RSA加密解密算法Java

时间:2022-06-09 04:00:20

前言

        RSA公钥加密算法是1977年由Ron RivestAdi ShamirhLenA dleman开发的。RSA取名来自开发他们三者的名字。RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。RSA是被研究得最广泛的公钥算法,从提出到现在已近二十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一毫不夸张地说,只要有计算机网络的地方,就有RSA算法,签名文件,Https安全网络协议,github本地和远程库关联等等


1.RSA加密算法实现

2.RSA解密算法实现

3.遇到的问题  

4.总结


产生秘钥:

  1. 选两个保密的大素数pq
  2. 计算n=p*q,f(n)=(p-1)*(q-1),其中f(n)n的欧拉函数值;
  3. 选一整数e,满足1<e<f(n),gcd(f(n),e)=1;
  4. 计算d,满足d*e≡1mod(f(n)),de在模f(n)下的乘法逆元因ef(n)互素,由模运算可知,它的乘法逆元一定存在;
  5. {e,n}为公开钥,{d,n}为秘密钥
加密:
      加密是首先将明文比特串分组,使得每个分组对应的十进制数小于n,即分组长度小于log2(n)。然后每个明文分组m,作加密运算:                                          

                              c≡m^e mod n

  解密:
        对明文分组的解密运算为:            

                                               m≡c^d mod n

   

       首先选取保密的两个大素数pq。然后求他们的乘积n=p*qn的欧拉函数值。然后选取任意的e,并且满足1<e<f(n)en的欧拉函数值f(n)互素。最后利用我们选取的e来加密明文文件。

       在我的程序中我把pq选取100内的素数,并且程序把pq自动生成。程序利用生成的pq的值来求它们的乘积n=p*qn的欧拉函数值f(n)。然后选取与f(n)互素的整数e,按照给定的公式生成密文文件

        生成密钥和密文的相关公式:      

                                       n=p*q   f(n)=(p-1)*(q-1) 

                                       c≡m^e mod n

相关的代码与结果如下:

生成pq的JAVA代码:

    SecureRandom random=new SecureRandom();
random.setSeed(new Date().getTime());
BigInteger p , q;
while(!(p=BigInteger.probablePrime(bitlength,random)).isProbablePrime(1)){
continue;
}//生成大素数p
while(!(q=BigInteger.probablePrime(bitlength,random)).isProbablePrime(1)){
continue;
}//生成大素数q

生成f、n、e的值        

SecureRandom random=new SecureRandom();
random.setSeed(new Date().getTime());
BigInteger n=p.multiply(q);//生成n
//生成f
BigInteger f =p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
//生成一个比k小的b,或者使用65537
BigInteger e=BigInteger.probablePrime(bitlength-1, random);

生成密文d的相关代码:

private static BigInteger x; //存储临时的位置变量x,y 用于递归
private static BigInteger y;
//欧几里得扩展算法
public static BigInteger ex_gcd(BigInteger a,BigInteger b){
if(b.intValue()==0){
x=new BigInteger("1");
y=new BigInteger("0");
return a;
}
BigInteger ans=ex_gcd(b,a.mod(b));
BigInteger temp=x;
x=y;
y=temp.subtract(a.divide(b).multiply(y));
return ans;
}
//求反模     public static BigInteger cal(BigInteger a,BigInteger k){        BigInteger gcd=ex_gcd(a,k);        if(BigInteger.ONE.mod(gcd).intValue()!=0){            return new BigInteger("-1");        }        //由于我们只求乘法逆元 所以这里使用BigInteger.One,实际中如果需要更灵活可以多传递一个参数,表示模的值来代替这里        x=x.multiply(BigInteger.ONE.divide(gcd));        k=k.abs();        BigInteger ans=x.mod(k);        if(ans.compareTo(BigInteger.ZERO)<0) ans=ans.add(k);        return ans;    }
  • 加密代码
public static BigInteger encrypt(String text) {
BigInteger res = BigInteger.ONE;
BigInteger big2 = new BigInteger(String.valueOf(2));
BigInteger data = new BigInteger(text);
data = data.mod(n);
for (; e.compareTo(BigInteger.ZERO) != 0; e = e.divide(big2)) {
if (e.mod(big2).compareTo(BigInteger.ONE) == 0)
res = (res.multiply(data)).mod(n);
data = (data.pow(2)).mod(n);
}
return res;
}
  • 解密代码
  BigInteger res = BigInteger.ONE;
BigInteger big2 = new BigInteger(String.valueOf(2));
encrypt = encrypt.mod(n);
for (; d.compareTo(BigInteger.ZERO) != 0; d = d.divide(big2)) {
if (d.mod(big2).compareTo(BigInteger.ONE) == 0)
res = (res.multiply(encrypt)).mod(n);
encrypt = (encrypt.pow(2)).mod(n);
}

问题

        生成的q,p超过12位时同样加密,解密是可以正确的解密,破解时有的时候解密结果出错。(原因:随着密钥变长,暴力破解的质越多,满足的因式分解p,q组合越多,私钥确实是其中一个)。

      有时候生成的密文和原来的明文相同,出现这样的问题可能跟e的选取有关。

      如果输入的原文为多个0或者一个1时,加密后的明文和密文是一样的,这种情况可以使用加salt的方式解决。


  总结

         我编写的RSA加密解密算法的程序的功能特别的简单,我编写的是对于五位以下数字的加密和解密。虽然看起来很简单,但是实现出来不那么容易了,我通过编写这么小的一个RSA的加密解密算法,我意识到了RSA算法的安全性很高。

      虽然我编写了解密的算法,但没有详细的分析不了解密的一些问题,我成功的解密了低位的数字的加密,只要密钥足够长的目前还不知道怎么破解。