RSA算法java实现(BigInteger类的各种应用)

一、RSA算法

1.密钥生成

  • 随机生成两个大素数p、q
  • 计算n=p*q
  • 计算n的欧拉函数f=(p-1)*(q-1)
  • 选取1<e<f,使e与f互素
  • 计算d,ed=1modf
  • 公钥为(e,n),私钥为(d,n)

2.加密

  • c=m^e mod n

3.解密

  • m=c^e mod n

1591805-20190518131521407-493851371.png

二、BigInteger类(大数)

  • 定义:
BigInteger b=new BigInteger("1"); 
  • 将其他类型变量转化为BigInteger变量
BigInteger b=BigInteger.valueof(1);
  • 随机生成大素数
BigInteger bigInteger = BigInteger.probablePrime(2048, r);    //随机生成2048位的大素数,r为Random变量
  • 素性检验(米勒罗宾检验)
boolean a = b.isProbablePrime(256);    //b是素数的概率为1 - 1 / 2^256
  • 四则运算
BigInteger a,b,c;
c=a.add(b);   //加
c=a.subtract(b);  //减
c=a.multiply(b);  //乘
c=a.divide(b);  //除
  • 最大公因子
BigInteger a,b,c;
c=a.gcd(b);
  • 取余
BigInteger a,b,c;
c=a.remainder(b);
  • 次方模(a^b mod m)
BigInteger a,b,c;
c=a.modPow(b,m);

三、算法实现

1.两个大素数的生成

  • 构建Big类,随机生成大素数,并进行素性检验

1591805-20190518135347733-1116793955.png

2.公钥生成

  • 寻找与f互素的公钥e(1<e<f)

1591805-20190518135736982-230110760.png

3.私钥生成

  • 利用欧几里得算法(辗转相除法),列表,计算e模f的逆d

1591805-20190518140048559-990718331.png

1591805-20190518140140125-2118745045.png

4.获取密钥

  • 在Keys类中将公钥、私钥输出到文件

1591805-20190518160417349-1252859849.png

5.加密

(1)从文件逐行读取明文、公钥

1591805-20190518160852963-1591060944.png

(2)使用getByte()将明文转化为byte数组

1591805-20190518160928599-1046072676.png

(3)依次计算c=m^e mod n
(4)将结果逐行输出到文件

1591805-20190518161011602-5191109.png

6.解密

(1)从文件逐行读取密文、私钥

1591805-20190518161749564-1969098730.png

(2)读入密文的同时计算m=c^d mod n,并将其存入byte数组

1591805-20190518161828486-1361373929.png

(3)将byte数组还原为字符串(明文)

1591805-20190518161854177-736908198.png

(4)输出明文到文件

四、遇到的问题和解决方法

问题1:加密时不知道如何将明文转化为可用于加密的数字

解决1:纠结了好久,想到看书时看到过的getByte()方法可以将字符串转化为byte数组

1591805-20190518162709917-89970300.png

问题2:解密时,出现了以下问题

1591805-20190518162851126-951306227.png

解决2:这个错误还没法调试,检查了好久,发现自己计算公钥e的时候模的是n,修改了成模f后,解决了该问题

问题3:之后,解密出来的文件还是有问题

1591805-20190518163258774-1973668228.png

解决3:调试后,发现自己犯了很蠢的错误,我把int i=0放在了while 循环里,每次循环都会把i置1...

1591805-20190518163553480-315605429.png

问题4:然后,输出还是有问题,后面会多一些空格

1591805-20190518163720478-4522163.png

解决4:增加一个与明文长度等长的byte数组

1591805-20190518163854045-1313437214.png

成功~~

1591805-20190518163954602-287772790.png

五、码云链接

转载于:https://www.cnblogs.com/wyf20175217/p/10886124.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RSA公钥密码系统的Java实现 /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package rsa; import java.math.BigInteger; import java.util.Scanner; import java.util.Random; /** * * @author Administrator */ public class RSABigInteger { private BigInteger bign,ukey,rkey,eulerPhi; private int bitBLength=32; /** * @return the bign */ public BigInteger getBign() { return bign; } public RSABigInteger() { this.generatingUAndRKey(); } public static void main(String[] args) { RSABigInteger rsa = new RSABigInteger(); rsa.test02(); } public void test() { long ptt=25; System.out.println("Before encripting plaintext= "+ptt); BigInteger pt = BigInteger.valueOf(ptt); BigInteger ct=this.encripting(pt); System.out.println("The ciphertext="+ct.longValue()); pt = this.decripting(ct); System.out.println("After decripting the plaintext = "+ pt.longValue()); } public void test02() { BigInteger[] bgPt,bgCt; byte[] btPt,btCt; //long[] lgPt,lgCt; long lgC; String strPt,strCt; int len,i; pstr("Input a plain text to be encripted:"); Scanner scanf = new Scanner(System.in); strPt=scanf.nextLine(); pstr("The plain text to be encripted:"+strPt); len=strPt.length(); bgPt=new BigInteger[len]; bgCt=new BigInteger[len]; //lgPt=new long[len]; //lgCt=new long[len]; btPt=strPt.getBytes(); btCt=new byte[len]; //Encripting pstr("Encripting...."); for(i=0;i<len;i++) { lgC =(long)btPt[i]; bgPt[i]=BigInteger.valueOf(lgC); bgCt[i]=this.encripting(bgPt[i]); lgC=bgCt[i].longValue(); btCt[i]=(byte)lgC; } strCt = new String(btCt); pstr("The ciphertext is "+strCt); //Decripting pstr("Decripting...."); for(i=0;i<len;i++) { bgPt[i]=this.decripting(bgCt[i]); lgC=bgPt[i].longValue(); btPt[i]=(byte)lgC; } strPt=new String(btPt); pstr("The refound plain text is:"+strPt); } public void pstr(String mess) { System.out.println(mess); } /** * @param bign the bign to set */ public void setBign(BigInteger bign) { this.bign = bign; } /** * @return the ukey */ public BigInteger getUkey() { return ukey; } /** * @param ukey the ukey to set */ public void setUkey(BigInteger ukey) { this.ukey = ukey; } /** * @return the rkey */ public BigInteger getRkey() { return rkey; } /** * @param rkey the rkey to set */ public void setRkey(BigInteger rkey) { this.rkey = rkey; } public void generatingUAndRKey() { Random ran = new Random(); BigInteger p = BigInteger.probablePrime(this.bitBLength,ran); BigInteger q = BigInteger.probablePrime(this.bitBLength,ran); this.bign =p.multiply(q); this.eulerPhi=(p.subtract(BigInteger.ONE)). multiply(q.subtract(BigInteger.ONE)); do { this.ukey=BigInteger.probablePrime(bitBLength,ran); }while(!this.ukey.gcd(this.eulerPhi).equals(BigInteger.ONE)); this.rkey=this.ukey.modInverse(this.eulerPhi); } public BigInteger encripting(BigInteger plaintext) { return plaintext.modPow(this.ukey, this.bign); } public BigInteger decripting(BigInteger ciphertext) { return ciphertext.modPow(this.rkey, this.bign); } /** * @return the eulerPhi */ public BigInteger getEulerPhi() { return eulerPhi; } /** * @param eulerPhi the eulerPhi to set */ public void setEulerPhi(BigInteger eulerPhi) { this.eulerPhi = eulerPhi; } /** * @return the bitBLength */ public int getBitBLength() { return bitBLength; } /** * @param bitBLength the bitBLength to set */ public void setBitBLength(int bitBLength) { this.bitBLength = bitBLength; } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值