非对称加密原理和实现——RSA

Posted 一页破书

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了非对称加密原理和实现——RSA相关的知识,希望对你有一定的参考价值。

最近在做一个区块链相关的安全项目,之前掌握的密码学理论和编码经验很皮毛,跟不上项目要求,急需要补一下密码学。

(堡垒最容易从内部攻破,最近臭名昭著的长生生物兑水疫苗事件也是被内部员工曝光出来的——据说是加了几个月班,只给了两百多块钱的加班费;

此安全项目重点是防止内部操作人员、系统运维人员、系统开发&设计人员恶意侵入、仿冒、注入、后门等破坏攻击手段)




RSA基于大数质因式分解的,先看相关理论:

欧拉函数(符号Φ ):正整数N,1~N之间有多少个数与N互质?只看几种简单情况

N=1:Φ(1) =1

N是质数:Φ(N)=N-1

N是两个质数p、q乘积:Φ(N)= Φ(p) Φ(q)=(p-1)(q-1)

 

欧拉定理:

两个正整数a、n互质,a φ(n)-1是n的整数倍;

 

模反元素:

计算x使得a*x mod n=1,x就是a相对n的模反元素,记为:a-1 mod n

a和n互质的话,aφ(n)-1次方就是一个模反元素,

当然模反元素不唯一,aφ(n)-1+K*n都是a相对n的模反。

 

RSA过程:

选择两个很大的质数p、q

计算n=p*q

计算φ(n)=(p-1)(q-1)

选择一个与φ(n)互质并且小于φ(n)的数e

计算e对φ(n)的模反元素d,到此根据前面的欧拉函数、欧拉定理正向推导都很顺利

e*d-1=K*φ(n)  =》 d=e(p-1)(q-1)-1 +K(p-1)(q-1)

当然秘钥生成过程不会直接计算e的(p-1)(q-1)指数,欧拉定理仅仅是证明了d的存在性,计算d可以用扩展欧几里得算法:

e*d≡ 1(mod φ(n)) 相当于求解模线性方程:e*d+φ(n) y =1 (e、d、φ(n)、y都是整数)

欧几里得扩展算法:对于两个正整数a、b,必定存在整数对x、y,使得ax+by=gcd(a,b);gcd ——最大公约数。递归计算过程如下:

欧几里得原理:gcd(a,b)=gcd(b,a mod b)

所以 :ax1+by1 = bx2+(a mod b) y2 = bx2 + (a-( a/b)b)y2=ay2+b(x2-(a/b)y2)

(此处a/b是整除,不带小数),由x2、y2可推出x1、y1:

x1=y2

y1= x2-(a/b)y2

 

ax1+by1 = bx2+(a mod b) y2  不断递归,b一定会变成0,递归结束。

 

因为e、φ(n) 互质,gcd(e,φ(n))=1,所以计算d可以套用扩展欧几里得算法:e*d+φ(n) y =1。

 

最后,n和e作为公钥公开发布;n和d作为私钥;

如果知道n和e,想推导出d,必须先把n分解为p、q;

 

公钥加密:m e  mod n = c   (m表示原文、c表示加密后的密文)

私钥解密:c d mod n = m,下面证明解密过程:

把c= m e - K*n代入解密方程:

m d*e  mod n = m,只需要证明等式成立,继续代入d*e=K*φ(n)+1 ,

等式变为:m K*φ(n)+1  mod  n = m

如果m和n互质,代入欧拉定理mφ(n)=1 + k*n,

K*φ(n)+1  mod  n = (1+k*n)k * m mod n = m,因为(1+k*n)k  mod n = 1,证明等式成立。

如果m和n不互质,m是p或者q的倍数,证明过程稍微复杂一点。

 

私钥解密也不会直接计算cd,这个计算量更大,但是私钥持有者知道n、p、q,可以通过中国余数定理加速解密过程:

中国余数定理(孙子定理)针对一元线性同余方程组给出可解的判定条件和构造方式,一元同余方程组:

x≡a1 (mod m1)

x≡a2 (mod m2)

x≡an (mod mn)

 

定理给出:如果mi相互互质,对任意整数序列ai,方程组有解,构造方式:

1、构造M=m1*m2*m3*……*mn

2、构造Mi =M/mi

3、计算ti =Mi相对mi的模反

方程组的通用解:x= ∑aitiMi(i=1…n)  + K*M

再套用到RSA私钥解密过程 cd mod n:

先定义 C1 = cd mod p、C2 = cd  mod q

计算cd,找到不变量:

cd≡C1 (mod p)

cd≡C2 (mod q)

按中国余数定理计算:

M=pq=n

M1=M/p=q,M2=M/q=p

t1=q-1 mod p,t2=p-1 mod q

代入,计算出:

cd={ C1*(q-1 mod p)*q + C2*( p-1 mod q)*p } mod n

下面就是计算C1、C2:

cd mod p 根据费马小定理(欧拉定理的特例:ap-1≡1 (mod p) )可推倒:

d=K(p-1)+ [ d mod (p-1)]

cd mod p = c K(p-1)+ [ d mod (p-1)] mod p = c K(p-1) * c [ d mod (p-1)] mod p =

c [ d mod (p-1)] mod p

这样计算cd mod p 简化为 c [ d mod (p-1)] mod p。带入到cd=C1*(q-1 mod p)*q + C2*( p-1 mod q)*p,得到:

cd={ (c [ d mod (p-1)] mod p)*(q-1 mod p)*q +

(c [ d mod (q-1)] mod p)*( p-1 mod q)*p } mod n

 

理论之后,看代码实现(boundcycastle源码):

入口函数:

org.bouncycastle.crypto.generators.RSAKeyPairGenerator.generateKeyPair()

生成秘钥对的默认RSA参数:

finalstatic BigInteger defaultPublicExponent = BigInteger.valueOf(0x10001);

        finalstaticintdefaultTests = 12;

param = newRSAKeyGenerationParameters(defaultPublicExponent,

                            new SecureRandom(),2048, defaultTests);

 

publicAsymmetricCipherKeyPair generateKeyPair()

    {

        BigInteger    pqndepSub1qSub1phi;

 

        //

        // p and qvalues should have a length of half the strength in bits

        //

        intstrength = param.getStrength();

        intpbitlength = (strength + 1) / 2;

        intqbitlength = strength - pbitlength;

        intmindiffbits = strength / 3;

 

        e = param.getPublicExponent();

 

        // TODO Considergenerating safe primes for p, q (see DHParametersHelper.generateSafePrimes)

        // (then p-1and q-1 will not consist of only small factors - see "Pollard'salgorithm")

 

        //

        // generate p,prime and (p-1) relatively prime to e

        //

        for (;;)

        {这个for循环随机找到一个“可能的”素数,满足p-1e互质

            p = new BigInteger(pbitlength, 1, param.getRandom());

           

            if (p.mod(e).equals(ONE))

            {

                continue;

            }

            p.isProbablePrime只保证p概率上是个素数,概率为1-1/(2*certainty) ,默认是23/24如果不是素数会不会影响加解密呢

            if (!p.isProbablePrime(param.getCertainty()))

            {

                continue;

            }

           

            if (e.gcd(p.subtract(ONE)).equals(ONE)) 

            {ep-1互质

                break;

            }

        }

 

        //

        // generate amodulus of the required length

        //

        for (;;)

        {

            // generate q,prime and (q-1) relatively prime to e,

            // and notequal to p

            //

            for (;;)  生成q

            {

                q = new BigInteger(qbitlength, 1, param.getRandom());

 

                if (q.subtract(p).abs().bitLength()< mindiffbits)

                {

                    continue;

                }

               

                if (q.mod(e).equals(ONE))

                {

                    continue;

                }

           

                if (!q.isProbablePrime(param.getCertainty()))

                {

                    continue;

                }

           

                if (e.gcd(q.subtract(ONE)).equals(ONE))

                {

                    break;

                }

            }

 

            //

            // calculatethe modulus

            //

            n = p.multiply(q);

 

            if (n.bitLength() == param.getStrength())

            {

                break;

            }

 

            //

            // if we gethere our primes aren't big enough, make the largest

            // of the two pand try again

            //

            p = p.max(q);

        }

 

        if (p.compareTo(q) < 0)

        {

            phi = p;

            p = q;

            q = phi;

        }

 

        pSub1 = p.subtract(ONE);

        qSub1 = q.subtract(ONE);

        phi = pSub1.multiply(qSub1);   phi=p-1*q-1

 

        //

        // calculatethe private exponent

        //

        d = e.modInverse(phi);   d ——e相对(p-1)(q-1)模反

 

        //

        // calculatethe CRT factors

        //

        BigInteger    dPdQqInv;

 

        dP = d.remainder(pSub1);  dP——d mod (p-1)

        dQ = d.remainder(qSub1);  dQ —— d mod (q-1)

        qInv = q.modInverse(p); qInv —— q相对p的模反

 

        returnnewAsymmetricCipherKeyPair(

                newRSAKeyParameters(falsene),

                newRSAPrivateCrtKeyParameters(nedpqdPdQqInv));  这几个值都是私钥的一部分

    }

 

私钥加密过程:

org.bouncycastle.crypto.engines.RSACoreEngine.processBlock(BigInteger)

public BigIntegerprocessBlock(BigInteger var1) {

      if (this.keyinstanceof RSAPrivateCrtKeyParameters){

         RSAPrivateCrtKeyParameters var2 =(RSAPrivateCrtKeyParameters) this.key;

         BigInteger var3 = var2.getP();

         BigInteger var4 = var2.getQ();

         BigInteger var5 = var2.getDP();

         BigInteger var6 = var2.getDQ();

         BigInteger var7 = var2.getQInv();

         BigInteger var8 = var1.remainder(var3).modPow(var5var3);  m mod pd mod p-1mod p   C1

         BigInteger var9 = var1.remainder(var4).modPow(var6var4);  m mod qd mod q-1mod qC2

         BigInteger var10 = var8.subtract(var9); v

8-v9

         var10 = var10.multiply(var7); (v8-v9)qInv

         var10 = var10.mod(var3); (v8-v9)qInv mod p

         BigInteger var11 = var10.multiply(var4); ((v8-v9)qInv mod p)q

         var11 = var11.add(var9);

         returnvar11;

      } else {

         returnvar1.modPow(this.key.getExponent(), this.key.getModulus());

      }

   }

 

{ [(m mod pd mod p-1mod p - m mod qd mod q-1mod q ]*(qInv) mod p } q +

m mod qd mod q-1mod q

=

[m mod pd mod p-1mod p ]*qInv*q +

[m mod qd mod q-1mod q] * (1-qInv*q) mod q

1-qInv*q 泛化为 1+kq= p-1 mod q)*p,这样就和上面中国余数定理简化的公式一致。

 

RSAPrivateCrtKeyParameters里面的Crt就是中国余数定理 Chinese Remainder Theorem的首字母缩写。

 

最后,知道RSA的私钥能否推导出公钥?

1、假设私钥是CRT格式,私钥本身包含了n,e,d,p,q等元素,n和e就是公钥;

2、非CRT格式的私钥只包括n、d,多数情况下生成RSA公私钥对e都是固定选择65537,其他情况为了公钥加密解密耗时短,选择e也不会太多,所以知道n、d 可以在log(N)线性时间内推导出e。


以上是关于非对称加密原理和实现——RSA的主要内容,如果未能解决你的问题,请参考以下文章

非对称加密原理和实现——RSA

非对称加密技术- RSA算法数学原理分析

非对称加密技术- RSA算法数学原理分析

TLS/SSL 协议-非对称加密(RSA)原理

密码学基础:非对称加密(RSA算法原理)

RSA  加密算法(原理篇)