C语言实现RSA

参考 《密码学引论》武汉大学出版社

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加解密过程

  1. 随机地选择两个大素数p和q,而且保密;
  2. 计算n=pq,将n公开
  3. 计算fi=(p-1)*(q-1),对fi保密
  4. 随机选择一个正整数e,1<e<fi 且e和fi 互素
  5. 根据 ed=1 mod fi,求出d,并对d保密
  6. 加密运算:C=M^e mod n
  7. 解密运算: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秒就完成了。

  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值