参考 《密码学引论》武汉大学出版社
RSA简介
1978年美国麻省理工学院的三名密码学者R.L.Rivest, A.Shamir和L.M.Adleman提出了一种基于大合数因子分解困难性的公开密钥密码,简称RSA密码。
RSA密码被誉为是一种风格幽雅的公开密钥密码。由于RSA密码即可用于加密,又可用于数字签名,安全、易懂。因此,RSA密码已成为目前应用最广泛的公开密钥密码。许多国家标准化组织,如ISO,ITU和SWIFT等都已接受RSA作为标准。Internet网的E-Mail保密系统CPG以及国际的VISA和MASTER组织的电子商务协议(SET协议)中都将RSA密码作为传送会话密钥和数字签名的标准。
RSA加解密过程
- 随机地选择两个大素数p和q,而且保密;
- 计算n=pq,将n公开
- 计算fi=(p-1)*(q-1),对fi保密
- 随机选择一个正整数e,1<e<fi 且e和fi 互素
- 根据 ed=1 mod fi,求出d,并对d保密
- 加密运算:C=M^e mod n
- 解密运算:M=C^d mod n
简单实现
#include<stdio.h>
int main(){
int p=3,q=5;
int n=p*q,fi=(p-1)*(q-1);
int e=3,d;
int i;
for(i=0;i<fi;i++){
if((i*e)%fi==1){
d=i;break;
}
}
printf("p:%d q:%d n:%d fi:%d e:%d d:%d\n",p,q,n,fi,e,d);
int m=7,c=1,tmp=1;
for(i=0;i<e;i++){
c=(c*m)%n;
}
for(i=0;i<d;i++){
tmp=(tmp*c)%n;
}
printf("m:%d c:%d dec:%d\n",m,c,tmp);
return 0;
}
代码效果:
RSA-1024实现
涉及大数运算参考:https://editor.csdn.net/md/?articleId=109395413
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define max(a,b) (a>b?a:b)
#define BUFLEN 514
int a[BUFLEN],b[BUFLEN],c[BUFLEN];
//将数组设置为0
int setZero(int*num,int len){
memset(num,0,sizeof(int)*len);
}
void hex_str2hex(char*str,int*num){
setZero(num,BUFLEN);
int i,j;
int len=strlen(str);
for(i=0;i<len;i++){
if(str[len-1-i]<58&&str[len-1-i]>47) //0-9
num[i]=str[len-1-i]-48;
else if(str[len-1-i]<71&&str[len-1-i]>64) //A-F
num[i]=10+str[len-1-i]-65;
else if(str[len-1-i]<103&&str[len-1-i]>96) //a-f
num[i]=10+str[len-1-i]-97;
}
}
void hex2hex_str(int*num,char*str){
int i,tmp;
memset(str,0,BUFLEN);
for(i=BUFLEN-1;num[i]==0;i--);//这里还能优化
for(tmp=0;i>=0;i--,tmp++){
if(num[i]>=0&&num[i]<=9)str[tmp]=num[i]+'0';
else str[tmp]=num[i]-10+'A';
}
}
void str2hex_str(char*str1,char*str2){
setZero(a,BUFLEN);
int i,j,len=strlen(str1);
for(i=0,j=2*len-1;i<len;i++){
a[j--]=(str1[i]>>4)&0xf;
a[j--]=str1[i]&0xf;
}
hex2hex_str(a,str2);
}
void hex_str2str(char*str1,char*str2){
int i,len=strlen(str1);
hex_str2hex(str1,a);
memset(str2,0,BUFLEN);
for(i=0;i<strlen(str1)/2;i++){
str2[i]=(a[len-1-2*i]<<4)+a[len-2-2*i];
}
}
int compare(int*num1,int len1,int*num2,int len2){
int i=len1-1,j=len2-1;
if(i<j)return -1;
else if(i>j)return 1;
else{
for(;i>=0;i--){
if(num1[i]>num2[i])
return 1;
else if(num1[i]<num2[i])
return -1;
}
return 0;
}
}
int copy(int*num1,int*num2,int len){
int j;
setZero(num1,BUFLEN);
for(j=0;j<len;j++)
num1[j]=num2[j];
return len;
}
//无符号大数加法 ,16进制
void add(char*str1,char*str2,char*str3){
int i,carry=0;
int len1=strlen(str1),len2=strlen(str2),len=max(len1,len2);
hex_str2hex(str1,a);
hex_str2hex(str2,b);
setZero(c,BUFLEN);
for(i=0;i<len;i++){
c[i]=(a[i]+b[i]+carry)%16;
carry=(a[i]+b[i]+carry)/16;
}
if(carry!=0)
c[len++]=1;
hex2hex_str(c,str3);
}
//无符号大数减法,仅当str1大于str2时得到正确结果
void sub(char*str1,char*str2,char*str3){
int i,borrow=0;
int len=strlen(str1);
hex_str2hex(str1,a);
hex_str2hex(str2,b);
setZero(c,BUFLEN);
for(i=0;i<len;i++){
c[i]=a[i]-b[i]-borrow;
if(c[i]<0&&i+1<len){
borrow=1;
c[i]+=16;
}
else
borrow=0;
}
hex2hex_str(c,str3);
}
//带符号大数加法,实际上没用到这个函数
void signAdd(char*str1,char*str2,char*str3){
int len1=strlen(str1)-1,len2=strlen(str2)-1;
hex_str2hex(&str1[1],a);
hex_str2hex(&str2[1],b);
if(str1[0]==str2[0]){
add(&str1[1],&str2[1],&str3[1]);
str3[0]=str1[0];
}
if(str1[0]!=str2[0]){
if(compare(a,len1,b,len2)>0){
sub(&str1[1],&str2[1],&str3[1]);
str3[0]=str1[0];
}
else if(compare(a,len1,b,len2)<0){
sub(&str2[1],&str1[1],&str3[1]);
str3[0]=str2[0];
}
else{
strcpy(str3,"+0");
}
}
}
//带符号大数减法
void signSub(char*str1,char*str2,char*str3){
int len1=strlen(str1)-1,len2=strlen(str2)-1;
hex_str2hex(&str1[1],a);
hex_str2hex(&str2[1],b);
char tmp1=str1[0],tmp2=str2[0];
memset(str3,0,BUFLEN);
if(tmp1==tmp2){
if(compare(a,len1,b,len2)>0){
sub(&str1[1],&str2[1],&str3[1]);
str3[0]=tmp1;
}
else if(compare(a,len1,b,len2)<0){
sub(&str2[1],&str1[1],&str3[1]);
if(tmp1=='+')str3[0]='-';
else str3[0]='+';
}
else{
strcpy(str3,"+0");
}
}
if(tmp1!=tmp2){
add(&str1[1],&str2[1],&str3[1]);
str3[0]=tmp1;
}
}
//大数乘法 ,16进制
void mul(char*str1,char*str2,char*str3) {
int i,j,k=0,carry=0,tmp;
int len1=strlen(str1),len2=strlen(str2);
hex_str2hex(str1,a);
hex_str2hex(str2,b);
setZero(c,BUFLEN);
for(i=0;i<len1;i++){
for(k=i,j=0;j<len2;j++,k++){
c[k]+=a[i]*b[j];
}
}
for(i=0;i<=k;i++) {
c[i]+=carry;
tmp=c[i];
c[i]=tmp%16;
carry=tmp/16;
}
hex2hex_str(c,str3);
}
//大数除法,16进制
void div(char*str1,char*str2,char*str3){
int i,j,tmp,tmp2=0,borrow=0,temp[BUFLEN]={0},temp2[BUFLEN]={0};
int len1=strlen(str1),len2=strlen(str2);
hex_str2hex(str1,a);
hex_str2hex(str2,b);
if(compare(a,len1,b,len2)<0){
memset(str3,0,BUFLEN);
return;
}
setZero(c,BUFLEN);
while(compare(a,len1,b,len2)>=0){
tmp=len1-len2;
if(tmp==tmp2&&tmp>0)
tmp--;
tmp2=tmp;
setZero(temp2,BUFLEN);
for(i=len1-1;i>=tmp;i--)
temp2[i]=b[i-tmp];
copy(temp,a,len1);
if(compare(temp,len1,temp2,len2+tmp)<0)
continue;
for(j=1;;j++){
borrow=0;
for(i=tmp;i<len1;i++){
temp[i]=a[i]-temp2[i]-borrow;
if(temp[i]<0){
borrow=1;
temp[i]+=16;
}
else
borrow=0;
}
for(;temp[i]==0;i--);i++;
len1=copy(a,temp,i);
c[tmp]=j;
if(compare(temp,len1,temp2,len2+tmp)<0)
break;
}
}
hex2hex_str(c,str3);
}
//大数模运算,16进制
void mod(char*str1,char*str2,char*str3){
setZero(c,BUFLEN);
int i,j,tmp,tmp2=0,borrow=0,temp[BUFLEN]={0},temp2[BUFLEN]={0};
int len1=strlen(str1),len2=strlen(str2);
hex_str2hex(str1,a);
hex_str2hex(str2,b);
if(compare(a,len1,b,len2)<0){
memset(str3,0,BUFLEN);
hex2hex_str(a,str3);
return;
}
while(compare(a,len1,b,len2)>=0){
tmp=len1-len2;
if(tmp==tmp2&&tmp>0)
tmp--;
tmp2=tmp;
setZero(temp2,BUFLEN);
for(i=len1-1;i>=tmp;i--)
temp2[i]=b[i-tmp];
copy(temp,a,len1);
if(compare(temp,len1,temp2,len2+tmp)<0)continue;
for(j=1;;j++){
borrow=0;
for(i=tmp;i<len1;i++){
temp[i]=a[i]-temp2[i]-borrow;
if(temp[i]<0){
borrow=1;
temp[i]+=16;
}
else
borrow=0;
}
for(;temp[i]==0;i--);i++;
len1=copy(a,temp,i);
c[tmp]=j;
if(compare(temp,len1,temp2,len2+tmp)<0)
break;
}
}
hex2hex_str(temp,str3);
}
int exgcd(char*str1,char*str2,char*x, char*y){
if(strlen(str2)==0){
strcpy(x,"+1");strcpy(y,"+0");
return 1;
}
char temp[BUFLEN];mod(str1,str2,temp);
int ret=exgcd(str2,temp,y,x);
char temp2[BUFLEN+1]={0},temp3[BUFLEN+1]={0};
div(str1,str2,temp2);
mul(temp2,&x[1],&temp2[1]);temp2[0]=x[0];
signSub(y,temp2,temp3);
strcpy(y,temp3);
return ret;
}
//扩展欧几里得求e的逆元d
void genPrivateKey(char*e,char*fi,char*d){
char x[BUFLEN+1]={0},y[BUFLEN+1]={0};
int ret=exgcd(e,fi,x,y);
if(x[0]=='+')
add(&x[1],"",d);
else if(x[0]=='-'){
sub(fi,&x[1],d);
mod(d,fi,d);
}
}
#define HEX_ENC 0
#define HEX_DEC 1
#define STR_ENC 2
#define STR_DEC 3
//利用反复平方乘加解密
void enc_dec(char*str,char*key,char*n,char*out,int opt){
char temp[BUFLEN]={0};
int key_t[BUFLEN];
if(opt==STR_ENC)
str2hex_str(str,str);
strcpy(temp,"1");
int i,tmp,flag;
hex_str2hex(key,key_t);
for(i=strlen(key)*4-1;((key_t[i/4]>>(i%4))&0x1)==0;i--);
for(;i>=0;i--){
mul(temp,temp,temp);
mod(temp,n,temp);
tmp=(key_t[i/4]>>(i%4))&0x1;
if(tmp==1){
mul(str,temp,temp);
mod(temp,n,temp);
}
}
if(opt==STR_DEC)
hex_str2str(temp,out);
else{
strcpy(out,temp);
}
}
int main(){
char p[BUFLEN]="e86c7f16fd24818ffc502409d33a83c2a2a07fdfe971eb52de97a3de092980279ea29e32f378f5e6b7ab1049bb9e8c5eae84dbf2847eb94ff14c1e84cf568415";
char q[BUFLEN]="d7d9d94071fcc67ede82084bbedeae1aaf765917b6877f3193bbaeb5f9f36007127c9aa98d436a80b3cce3fcd56d57c4103fb18f1819d5c238a49b0985fe7b49";
char p1[BUFLEN],q1[BUFLEN],n[BUFLEN],fi[BUFLEN];
sub(p,"1",p1);sub(q,"1",q1);mul(p,q,n);mul(p1,q1,fi); //计算获得n和fi
char e[BUFLEN]="100001",d[BUFLEN]; //存储公私钥,取e=65537较为合理
genPrivateKey(e,fi,d);//获取解密钥
char temp[BUFLEN];
char M[BUFLEN]="b503be7137293906649e0ae436e29819ea2d06abf31e10091a7383349de84c5b",C[BUFLEN];
//char M[BUFLEN]="this is a test",C[BUFLEN];
printf("p: %s\n\nq: %s\n\nn: %s\n\nfi: %s\n\ne: %s\n\nd: %s\n\nM: %s\n\n",p,q,n,fi,e,d,M);
enc_dec(M,e,n,C,HEX_ENC);
printf("enc: %s\n\n",C);
enc_dec(C,d,n,temp,HEX_DEC);
printf("dec: %s\n\n",temp);
}
加解密16进制字符串:
上述代码在Dev C++, VS2010, gcc 中编译均通过,一次完整的加解密时间大概在8秒左右,但是用python写是真的快,1~2秒就完成了。