守口如瓶

项目地址:https://github.com/lixuhui123/RSA

一、项目简介

    传统的对称加密,是甲方使用一种规则加密,乙方要使用相同的规则解密。这种加密方式的关键在于保证解密规则的安全性,往往这是一个让人头疼的问题。在1976年,两位美国的计算机学家Whitfifield Diffie  Martin Hellman,提出了新的构想,在不传递加密规则的情况下对对数据进行加密。称为“非对称加密算法”,笔者对此非常感兴趣,决定自己实现,探索其中的奥秘。

  • 乙方生成两把秘钥(公钥和私钥)。公钥是公开的,谁都可以获取,私钥保存在乙方
  • 甲方获取公钥,将它要传递的信息用公钥加密。
  • 乙方得到加密的信息之后,用私钥进行解密

二、RSA加解密公式

  •     加密,公钥(E,N)

                                                 密文cipher=clear^{E}modN

  • 解密,私钥(D,N)

                                                 clear=cipher^{D}modN

 三、实例描述

    1、选择p=6;q=5;

    2、n=pq=5*6=30

    3、\varphi (n)=(p-1)*(q-1)=5*4=20

    4、选择e=7,此时e和\varphi (n)互质

    5、计算e对\varphi (n)的模反元素d

                                                     (de)mod\varphi (n)=1,求得d=3

    6、公钥(7,30),私钥(3,30)

    7、比如选择8进行加密,按照规则8^{7}mod30=2,解密:2^{3}mod30=8

由此可见,RSA加密的基于大数分解的难度,通常采用100-200位甚至更多位的十进制整数作为公钥和私钥,从公钥算出私钥的难度等价于分解两个大素数之积(公认的数学难题)。

四、数学知识

质数(素数):一个数只能被1或者它本身整除,那么这个数是素数。

互质数:公约数只有1的两个数叫做互质数。

  • 两个质数一定是互质数
  • 相邻两个自然数是互质数
  • 相邻两个奇数是互质数
  • 如果两个数之中,较大的那个数是质数,则两者构成互质关系

欧拉函数:欧拉函数是小于X的正整数中与X互质的数的个数,它的公式如下:

                                                           \varphi (x)=x\prod_{i=1}^{n}(1-\frac{1}{Pi})

 欧拉函数是积性函数,若m,n互质,则

                                                         \varphi (mn)=\varphi (m)\varphi (n)

若m为质数,则

                                                           \varphi (m)=m-1

若m和n都是质数,则

                                                           \varphi (mn)=\varphi (m-1)\varphi (n-1)

欧拉定理:如果正整数m和n互质,则n的欧拉函数\varphi (n)可以让下面等式成立

                                                             a^{\varphi (n)}\equiv 1(modn)

上式的中\equiv是同余符号,同余的定义为:给定一个正整数n,如果两个整数a和b满足a-b能被n整除,即(a-b)modn=0,那么就称整数a与b对模n同余,记作a≡b(modn),同时可成立amodn=b。

 上式可以记为为:

                                                          (a^{\varphi (n)}-1)modn=0

                                                            a^{^{\varphi (n)}}mod(n)=1

模反元素:根据欧拉定理,如果两个正整数a和n互质,那么存在一个数b使得ab-1可以被n整除,这是b就叫做“模反元素”。

                                                       ab-1\equiv 1mod(n)       

b等价于                                            b=a^{\varphi (n)-1}

五、技术难点

    1、计算较大数的幂次方是比较消耗时间的比如:100^{100}计算时间先不说但是常规变量类型都无法表示。

         此处我们采用快速模幂运算来解决。

首先介绍同余定理:

                                            (a+b)%c=(a%c+b%c)%c 

                                            (a*b)%c=((a%c)*(b*c))%c

                                            (a^{b})%c=((a%c)*(a%c)*(a%c)...)%c=(a%c)^{b}%c

模幂运算:计算a^b%c

首先 b的二进制表示展开为:b=b_{0}*2^{0}+b_{1}*2^{1}+b_{2}*2^{2}+....+b_{n}*2^{n};

a^b可以展开为                   a^{b}=a^{b_{0}*2^{0}}*a^{b_{1}*2^{1}}*a^{b_{2}*2^{2}}*...*a^{b_{n}*2^{n}}

因为当bi的值为0的时候a^0=1,所以式可以简化为:

                                         a^{b}=(a^{b_{i}*2^{i}}*...*a^{b_{n}*2^{n}})    bi != 0             

                                          a^{b}%c=(a^{2^{i}{\color{DarkBlue} }}*...*a^{2^{n}})%c

令                                      a^{b}%c=(Ai*...*An)%c

                                          A0=a^{2^{0}}%c

                                          A1=a^{2^{1}}%c

                                          An=a^{2^{n}}%c

                                 A(n-1)=a^{2^{n-1}}%c,A(n)=  a^{2^{n}}%c      ,    A(n)=(a^{2^{(n-1)}})^{2} %c

                                                            A(n)=(A(n-1)*A(n-1))%c          

不知不觉我们发现了计算关系式:可以写代码啦:

DataType RSA::ecrept(DataType data, DataType ekey, DataType pkey)//加密 m=d^e % modp
{
	//i :0....n
	DataType Ai = data;// data^(b0*2^0),因为bi=1的时候才计算,bi=0的时候不计算,所以Ai的初始值为data
	DataType msgE = 1;//第一次密文初始化为1,因为A0=A0没有谁和它乘给msgE为1
	//data ^ ekey %pkey
	while (ekey)//计算多少位
	{
		if (ekey & 1)
		{
			msgE = (msgE *Ai) % pkey;
		}
		ekey >>= 1;
		Ai = (Ai*Ai) % pkey;
	}
	return msgE;
}

2、当公钥和私钥都使用了大数之后,按照普通的求最大公约数的方法,从两个较小数中较小数开始往前遍历寻找,在大数的规模下,是非常消耗时间的,可能一辈子找不出来,所以我找到了欧几里得定理:

    (a,b)的最大公约数等价于(b,a%b)的最大公约数,证明如下:

                              假设c是a和b的最大公约数,那么a=c*k,b=c*m

                                    令a%b=r,就是求a和r的最大公约数

                                           a=nb+r,即

                                          ck=mnc+r      可以得到 

                                          r=c(k-mn)       c也是a%b的公约数    

         证明了定理的正确性,我们就能用定理去写代码了。

int GreadCommonDividor(int a, int b) {
    if(b == 0)
        return a;
    return GreadCommonDividor(b, a%b);
}

 解释:当a%b==0的时候,说明a可以将b整除,那么最大公约数就b

优化:

DataType RSA::getGcd(DataType data1, DataType data2)
{
	//求最大公约数,两个质数的最大公约数为1
	//使用辗转相除法
	DataType residdual;
	while (residdual = data1%data2)
	{
		data1 = data2;
		data2 = residdual;
	}
	return data2;
}

3、模反元素优化

    模反元素d,满足(de)mod\varphi (n)=1,常规方法要从1开始逐个往后遍历寻找,显然在大数运算中不可取。我们借助欧几里得定理和欧几里得定理的扩展来优化模反元素的求解。

    欧几里得定理:

  • gcd(a,b)=gcd(b,a%b) 这里的含义是a,b的最大公约数和b,a%b的最大公约数相同
  • 如果a,b的最大公约数是gcd,则一定可以找到x,y,使等式ax+by=gcd成立。此方程的x,y的解不唯一,可以有无数组解

    扩展的欧几里得算法:

不仅要求出a,b的最大公约数gcd,也要求出一组解(x,y)使等式ax+by=gcd成立。

当b=0的时候,gcd即可求出,即ax=gcd。所以在求gcd的同时能够得到一组解(x,y)

观察上式,当b = 0时, 等式变成了ax = gcd,此时我们返回a的值,a既是所求的最大公约 ,数gcd,故此时x = 1, y可以是任意值。即(1,0)

再次看模反元素的表达式(de)mod\varphi (n)=1,变形为ab%n=1(n表示\varphi (n)整体值),ab-1为n的倍数,即,ab+kn=1,对应模反元素求法ed+k\varphi (n)=1,e为加密秘钥,d为解密秘钥,模反元素。e与\varphi (n)互质,gcd=1。求出一组解(d,k)解密秘钥即可求出。

假设:设d = x, k = y, e = a, φ(n) = b,则等式ed + kφ(n) = 1即变为ax + by = 1, 通过欧几里得递归算法,当b=0 时,可求得一组解(1,0)和最大公约数1

     在使用欧几里得算法中,

int GreadCommonDividor(int a, int b) {
    if(b == 0)
        return a;
    return GreadCommonDividor(b, a%b);
}

两个质数a,b,当a%b==0时返回a=1。

    令, a1=b,b1=a%b , 当b1==0时,返回a1。

    ax + by = 1 ,可以写成a1*x+b1*y=1,解为(1,0) 

     在递归算法里面b*x1+a%b*y1=1  可得 b*x1+(a-(a/b)*b)*y1 =1,

上式变形:                                             a*y1+b*(x1-a/b*y1)=1         对比ax + by = 1,

      得,                                                              x=y1,  y=x1-a/b*y1                  得到了解的通式

写代码就容易了

DataType RSA::exGcd(DataType a, DataType b, DataType &x, DataType &y)
{
    //传入&直接改变原值,而不是值拷贝
	if (b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	DataType gcd = exGcd(b, a%b, x, y);
	DataType x1 = x, y1 = y;
	x = y1;
	y = x1 - a / b * y1;
	return gcd;
}

  六、boost函数库介绍     

    项目中主要使用了随机产生大数,和大数的素性检测。

https://www.boost.org/doc/libs/1_58_0/libs/multiprecision/doc/html/boost_multiprecision/tut/primetest.html

DataType RSA::getPrime()
{
	boost::random::mt19937 gen(time(NULL));

	boost::random::uniform_int_distribution <DataType> dist(2, DataType(1) << 200);
	DataType prime;
	while (true)
	{
		cout << "get prime" << endl;
		prime = dist(gen);
		if (isPrimeBigInt(prime))
		{
			cout << "get prime finsh" << endl;
			break;
		}
	}
	return prime; 
	
}

可以看到使用uniform_int_distribution在1~1左移100位的数字之中的产生一个呈离散均匀分布的随机数。

大数的素性检测:直接使用boost库中使用的miller_rabin_test检测方法:

bool RSA::isPrimeBigInt(DataType data)
{
	 
	brdm::mt11213b gen(time(nullptr));
	if (miller_rabin_test(data, 25, gen))
	{
		if (miller_rabin_test((data - 1) / 2, 25, gen))
		{
			return true;
		}
	}
	return false;
}

七、RSA加密算法的经典使用场景

    1、对密码等短小私密的信息进行加密                                                                     

2、网络通信协议HTTPS

    HTTPS是一种被广泛的应用层的通信协议,它和HTTP的区别在于它传递的信息是经过加密的。

    https协议采用非对称加密和对称加密算法相结合的方式进行加密信息通信,大概机制如下:
      1. 浏览器发起链接请求。 
      2. 服务器返回公钥。
      3. 浏览器产生一个对称加密密钥session key。
      4. 使用服务器的公钥加密此session key。
      5. 加密的session key 发送给服务器。
      6. 服务器通过私钥解密session key, 获取明文密码。
      7. 浏览器和服务器的通信现在通过session key 进行加密,进行安全通信。
 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值