【密码学】RSA的大整数雏形

 2019.11.23:


这个代码一开始采用的是如《算法笔记》上等PAT中的类似题目将十进制数字转换为数组大整数(也是十进制形式)。

但是这种想法在后来实现加密的时候快速积出现了严重的弊端,和普通十进制并没有什么区别了,依旧拖慢进程大的可怕。

今天课设答辩同学们都做出了像毕设一样的作品,很完善的调用各种类实现各种混合加密,还有图形化界面,python、java、各种语言起飞。到了我这,可怜的连个运行起来都有问题。

下面的代码是256进制的刚起步,老师说不要这样转换,可以直接用long int类型读入(C++),然后直接转换为256进制。

我在下面的写法没有抛弃原来的10进制大整数。

#include 
#include 
#include
#include 
#include 
#include 
using namespace std;

/*1.生成密钥对,(e,d,n),公钥是(e,n),私钥是(d,n)
步骤如下:
求n(准备两个质数p,q。这两个数不能太小,太小则会容易破解,将p乘以q就是N),
求f=(p-1)(q-1)
求e :gcd(e,f)=1
求d:e*d mod f = 1
2.加密:用(e,n):密文 c=m^e(mod n)
3.解密:用(d,n):明文 m=c^d(mod n)
*/
//定义大整数结构体,使用保存十位数字每一位的方法
struct bigint{
	int d[1000];
	int len;
	bigint(){
		memset(d,0,sizeof(d));
		len=0;
	}
};
bigint e,d,p,q,n;


struct bigint256{
	int d[32];
	int len;
	bigint256(){
		memset(d,0,sizeof(d));
		len=0;
	}
};


int compare(bigint a,bigint b){//比较a和b的大小,a大、相等、a小分别返回1,0,-1
	if(a.len>b.len)return 1;//a大
	else if(a.len=0;i--){
			if(a.d[i]>b.d[i]) return 1;//只要有一位a大,则a大
			else if(a.d[i]=0;i--){
		cout<=1&&c.d[c.len-1]==0){
		c.len--;//去除高位的0,同时至少保留1位最低位
	}
	if(sign==1)return c;
	else if(sign==-1){
		c.d[c.len-1]=-c.d[c.len-1];
		return c;
	}
}
//重载高精度加法
bigint operator + ( bigint a, bigint b)
{
	if(a.d[a.len-1]<0&&b.d[b.len-1]>0){
		a.d[a.len-1]=-a.d[a.len-1];
		return b-a;
	}
	if(a.d[a.len-1]>0&&b.d[b.len-1]<0){
		b.d[b.len-1]=-b.d[b.len-1];
		return a-b;
	}
	int sign=1;
	if(a.d[a.len-1]<0&&b.d[b.len-1]<0){
		b.d[b.len-1]=-b.d[b.len-1];
		a.d[a.len-1]=-a.d[a.len-1];
		sign=-1;
	}
	
	bigint c;
	int carry = 0;//carry是进位
	for(int i=0;i=1&&c.d[c.len-1]==0){//清高位零
		c.len--;}
	if(sign==1)return c;
	else if(sign==-1){
		c.d[c.len-1]=-c.d[c.len-1];
		return c;
	}
}
//重载大整数除法
/*
思想:反复做减法,看从被除数里面最多能减去多少个除数,商就是多少。
*/
//重新写一个减法,适合于返回长度,将数组直接做减法,参数是bigint中数组
int SubStract( int *p1, int *p2, int len1, int len2 )
{
    int i;
    if( len1 < len2 )
        return -1;
    if( len1 == len2 )
    {                        //判断p1 > p2
        for( i=len1-1; i>=0; i-- )
        {
            if( p1[i] > p2[i] )   //若大,则满足条件,可做减法
                break;
            else if( p1[i] < p2[i] ) //否则返回-1
                return -1;
        }
    }
    for( i=0; i<=len1-1; i++ )  //从低位开始做减法
    {
        p1[i] -= p2[i];
        if( p1[i] < 0 )          //若p1<0,则需要借位
        {
            p1[i] += 10;         //借1当10
            p1[i+1]--;           //高位减1
        }
    }
    for( i=len1-1; i>=0; i-- )       //查找结果的最高位
        if( p1[i] )                  //最高位第一个不为0
            return (i+1);       //得到位数并返回
    return 0;                  //两数相等的时候返回0
}

bigint operator / (bigint a, bigint b){//用一个例子方便写代码7546/23=328
	bigint c,z;
	if(a.len=0;i--){
		//首先将原来位置的b的数字移到后边(高位)
		if(i>=len){
			b.d[i]=b.d[i-len];//与a的长度对齐,现在即是xx32 (数组是从低位到高位进行存储)
		}
		//如果差值到了,开始补零
		else{
			b.d[i]=0;
		}
	}
	b.len=a.len;//现在b的长度和a的长度一样了,b[]="0032"即大数2300
	//现在可以利用上面的不断做减法记录次数计算除法的结果了。可以知道商的位数最大是len+1,即差值+1。
	//所以外层循环是0-len,内层循环对商的每一位进行计数
	bigint a1=a;//为了防止改变a,新增一个变量a1,变为a的副本
	for(int j=0;j<=len;j++)
	{
		//需要更新外层循环中b的长度,如第一次7546-2300*3=646,第二次646-230*2=186```,每次减少1
		//注意b.len-1即因为运算是从低位开始“0032”即从下标0开始,
		//所以在新的while循环中指针b.d要从下一位开始,即“032”,长度相应的当然要减少一个
		while((c.len=SubStract(a1.d,b.d+j,a1.len,b.len-j))>=0){//对齐后如果减1次结果还是大于等于0,说明没有减净
			a1.len=c.len;//更新a1的长度,即被除数的长度为结果的长度,
			//如7532-2300-2300-2300=632,这个时候a1.d="236",因为SubStract函数将结果保存在了a1.d中,所以被除数自动更新,但是位数要自己手动
			z.d[len-j]++;//开始保存商的结果,接着进行减法	
			//cout<<"运算过程:z.d[len-j]"<<"z.d["<=0;z.len--);//求出的商可能跳过高位有0,所以再重新更新商的长度,如可能求出0030,把后面多余的0去掉	
	 //cout<<"z.len"<=1&&z.d[z.len-1]==0){
	 z.len--;
	 }
	  //cout<<"z.len"<15*1进位1留5,a[1]->6+25+1=32 进位3留2,a[2]->3+10+3=16 进位1 留6,a[3]->5+1=6无进位   =>6625

找到规律ans[i+j]=a[i]+a[j];

*/
bigint operator * (bigint a, bigint b){//用一个例子方便写代码7546/23=328
	bigint z;
	z.len=a.len+b.len;
	for(int i=0;i=10)  //若>=10 
			{
				z.d[i+1]=z.d[i+1]+z.d[i]/10;  //将十位上数字进位 
				z.d[i]=z.d[i]%10;  //将个位上的数字留下
			}
		}
		while(z.len-1>=1&&z.d[z.len-1]==0){//和上面一样清零
		z.len--;
		//cout<<"a1.len--;a1.len="<=0;i--)
	{
		cout<=0;i--)
	   {
		   //只能先正序存,后面再逆过来
		   z.d[z.len]+=temp.d[i]*pow(10.0,(double)d.len-i);
		 // cout<<" printb(z):"; printb(z);cout<>=1;//右移相当于除以2
		b=b/in2;
    }
	while(ans.len-1>=1&&ans.d[ans.len-1]==0){//清高位零
		ans.len--;}
    return ans;
}
bigint Quick_Power(bigint a,bigint b,bigint c)     //快速幂
{
	
    bigint ans=in1,res=a;
	//if(b==in0)return in1;
    while(compare(b,in0)>0)//由于我没有重载比较运算符,但是在前面定义了compare函数,所以在这b=0则停止,应该是一样的。
    {
        //if(b&1)//b&1即b%2==1
		if(b%in2==in1){
        ans=ans*a%c;
		}
		a=a*a%c;
        // b>>=1;//右移相当于除以2
		b=b/in2;
    }
	while(ans.len-1>=1&&ans.d[ans.len-1]==0){//清高位零
		ans.len--;}
    return ans;
}

bool Miller_Rabin(bigint x)     //判断素数 
{
	
	//我们可以多选择几个 a,如果全部通过,那么 x 大概率是质数。
	char s5[3]="5";
	char s7[3]="7";	
	char s19[3]="19";
	char s23[3]="23";
	bigint in5=change(s5);
	bigint in7=change(s7);
	bigint in19=change(s19);
	bigint in23=change(s23);
	char s11[3]="11";
	char s13[3]="13";	
	char s17[3]="17";
	char s29[3]="29";
	bigint in11=change(s11);
	bigint in13=change(s13);
	bigint in17=change(s17);
	bigint in29=change(s29);
	bigint prime[10]={in2,in3,in5,in7,in11,in13,in17,in19,in23,in29};

    bigint k;
    bigint s=in0,t=x-in1,j;
    if(x==in2)  return true;   //2是素数 
   // if(x<2||!(x&1))  return false;     //如果x是偶数或者是0,1,那它不是素数 
	if(compare(x,in2)<0||(x%in2==in1)) return false;
   // while(!(t&1))  //将x分解成(2^s)*t的样子 
	while(t%in2==in1)
    {
        s=s+in1;
       // t>>=1;
		t=t/in2;
    }
   // for(i=0;i<10&&prime[i]=1&&res.d[res.len-1]==0){//清高位零
		res.len--;}
	return res;

}


/*
RSA中的e不能太小同样是密码学家D. Coppersmith,其于1990年指出[3]:
用于RSA的指数e不能太小,否则存在快速算法计算得到私钥d。这个定理要用到格密码学的著名算法LLL。
再次就不多做展开了… 不过需要注意的是,由于加密算法要计算m^e,如果e太大的话加密过程可能会比较慢。
现在一般认为令e=65537是比较合适的。
https://www.zhihu.com/question/54779059?sort=created
*/

bigint ex_gcd(bigint a,bigint b,bigint &x,bigint &y)      //扩展欧几里得
{
	//cout<<"compare(b,in0):"< 0)
		if( (compare(gcd,in1)==0)&& compare(x,in0)>0)
        {
            e = j;
            break;
        }
    }
    return e;//d为x.直接使用扩展欧几里得求出x后就可以用(x%m+m)%m得到(0,m)范围内的解。
}
 char tmp[10000];
int readMyf(){
	FILE *fp;
	fp = fopen("D://日常//大学文件//大三上学期//学科//安全协议//实验//MyCry02//mingwen.txt" , "r");
 
	fseek( fp , 0 , SEEK_END );
	int file_size;
	file_size = ftell( fp );
	cout<<"读取到文件大小为: "<< file_size<配置属性->c/c++->代码生成->基本运行时检查 设置为默认值

	char stre65537[6]="65537";//备用
	bigint in65537=change(stre65537);

	cout<<"\n随机生成私钥e"<>str1>>str2;
	bigint num1=change(str1);
	bigint num2=change(str2);
		//测试加法
	bigint sum=num1+num2;
	cout<<"\n****测试大整数加法结果********"<

2020.1.9:后记:这个后来用了1024bit的大整数,二进制什么的,现在我已经忘光了,记得当时网上有人家写的很好的,然后我从头到尾开始分析他代码的思想,做了个分析,然后加工加工就写报告了。

小结:关于大学里面课设的话,可能外观更重要,算法做的再好,以我现在菜鸡的水平也做不了什么,所以搞个壳子是最重要的,有了壳子之后里面的算法网上都有。

希望以后做毕设可以顺利些。

你可能感兴趣的:(密码学)