-
2021-04-27 11:53:23
1、RSAUtils
package rsa; import javax.crypto.Cipher; import java.io.ByteArrayOutputStream; import java.security.*; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Base64; import java.util.List; /** * @ClassName: RsaUtils * @Description: TODO * @Author: zhānghào * @Date: 2021/4/25 3:29 下午 * @Version: v1.0 **/ public class RSAUtils { // 加密算法 private final static String ALGORITHM_RSA = "RSA"; /** * 直接生成公钥、私钥对象 * * @param modulus * * @throws NoSuchAlgorithmException * */ public static List<Key> getRSAKeyObject(int modulus) throws NoSuchAlgorithmException{ List<Key> keyList = new ArrayList<>(2); // 创建RSA密钥生成器 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGORITHM_RSA); // 设置密钥的大小,此处是RSA算法的模长 = 最大加密数据的大小 keyPairGen.initialize(modulus); KeyPair keyPair = keyPairGen.generateKeyPair(); // keyPair.getPublic() 生成的是RSAPublic的是咧 keyList.add(keyPair.getPublic()); // keyPair.getPrivate() 生成的是RSAPrivateKey的实例 keyList.add(keyPair.getPrivate()); return keyList; } /** * 生成公钥、私钥的字符串 * 方便传输 * * @param modulus 模长 * @return * @throws NoSuchAlgorithmException */ public static List<String> getRSAKeyString(int modulus) throws NoSuchAlgorithmException{ List<String> keyList = new ArrayList<>(2); KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGORITHM_RSA); keyPairGen.initialize(modulus); KeyPair keyPair = keyPairGen.generateKeyPair(); String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()); String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()); keyList.add(publicKey); keyList.add(privateKey); return keyList; } // Java中RSAPublicKeySpec、X509EncodedKeySpec支持生成RSA公钥 // 此处使用X509EncodedKeySpec生成 public static RSAPublicKey getPublicKey(String publicKey) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA); byte[] keyBytes = Base64.getDecoder().decode(publicKey); X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); return (RSAPublicKey) keyFactory.generatePublic(spec); } // Java中只有RSAPrivateKeySpec、PKCS8EncodedKeySpec支持生成RSA私钥 // 此处使用PKCS8EncodedKeySpec生成 public static RSAPrivateKey getPrivateKey(String privateKey) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA); byte[] keyBytes = Base64.getDecoder().decode(privateKey); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); return (RSAPrivateKey) keyFactory.generatePrivate(spec); } /** * 公钥加密 * * @param data * @param publicKey * @return * @throws Exception */ public static String encryptByPublicKey(String data, RSAPublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.ENCRYPT_MODE, publicKey); // 模长n转换成字节数 int modulusSize = publicKey.getModulus().bitLength() / 8; // PKCS Padding长度为11字节,所以实际要加密的数据不能要 - 11byte int maxSingleSize = modulusSize - 11; // 切分字节数组,每段不大于maxSingleSize byte[][] dataArray = splitArray(data.getBytes(), maxSingleSize); ByteArrayOutputStream out = new ByteArrayOutputStream(); // 分组加密,并将加密后的内容写入输出字节流 for (byte[] s : dataArray) { out.write(cipher.doFinal(s)); } // 使用Base64将字节数组转换String类型 return Base64.getEncoder().encodeToString(out.toByteArray()); } /** * 私钥解密 * * @param data * @param privateKey * @return * @throws Exception */ public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception { Cipher cipher = Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.DECRYPT_MODE, privateKey); // RSA加密算法的模长 n int modulusSize = privateKey.getModulus().bitLength() / 8; byte[] dataBytes = data.getBytes(); // 之前加密的时候做了转码,此处需要使用Base64进行解码 byte[] decodeData = Base64.getDecoder().decode(dataBytes); // 切分字节数组,每段不大于modulusSize byte[][] splitArrays = splitArray(decodeData, modulusSize); ByteArrayOutputStream out = new ByteArrayOutputStream(); for(byte[] arr : splitArrays){ out.write(cipher.doFinal(arr)); } return new String(out.toByteArray()); } /** * 按指定长度切分数组 * * @param data * @param len 单个字节数组长度 * @return */ private static byte[][] splitArray(byte[] data,int len){ int dataLen = data.length; if (dataLen <= len) { return new byte[][]{data}; } byte[][] result = new byte[(dataLen-1)/len + 1][]; int resultLen = result.length; for (int i = 0; i < resultLen; i++) { if (i == resultLen - 1) { int slen = dataLen - len * i; byte[] single = new byte[slen]; System.arraycopy(data, len * i, single, 0, slen); result[i] = single; break; } byte[] single = new byte[len]; System.arraycopy(data, len * i, single, 0, len); result[i] = single; } return result; } }
2、RSATest
package rsa; import java.security.Key; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.List; /** * @ClassName: RSATest * @Description: TODO * @Author: zhānghào * @Date: 2021/4/25 3:41 下午 * @Version: v1.0 **/ public class RSATest { public static void main(String[] args) throws Exception { // 使用公钥、私钥对象加解密 List<Key> keyList = RSAUtils.getRSAKeyObject(1024); RSAPublicKey puk = (RSAPublicKey) keyList.get(0); RSAPrivateKey prk = (RSAPrivateKey) keyList.get(1); String message = "referrer:[http://www.example.com/start.html](http://www.example.com/start.htmluser_agent: Mozilla/4.08 [en] (Win98; I ;Nav)"; String encryptedMsg = RSAUtils.encryptByPublicKey(message, puk); String decryptedMsg = RSAUtils.decryptByPrivateKey(encryptedMsg, prk); System.out.println("object key ! message == decryptedMsg ? " + message.equals(decryptedMsg)); // 使用字符串生成公钥、私钥完成加解密 List<String> keyStringList = RSAUtils.getRSAKeyString(1024); String pukString = keyStringList.get(0); String prkString = keyStringList.get(1); System.out.println("公钥:" + pukString); System.out.println("私钥:" + prkString); // 生成公钥、私钥 puk = RSAUtils.getPublicKey(pukString); prk = RSAUtils.getPrivateKey(prkString); encryptedMsg = RSAUtils.encryptByPublicKey(message, puk); decryptedMsg = RSAUtils.decryptByPrivateKey(encryptedMsg, prk); System.out.println("string key ! message == decryptedMsg ? " + message.equals(decryptedMsg)); } }
更多相关内容 -
RSA算法Java实现
2019-03-23 16:27:06RSAPrivateKey prk = (RSAPrivateKey) b.readObject(); BigInteger d = prk.getPrivateExponent(); // 获取私钥参数及解密 BigInteger n = prk.getModulus(); System.out.println("d= " + d); System.out... -
JAVA RSA 加密算法 RSA.java
2020-08-29 17:22:17JAVA RSA 加密算法 RSA.java RSA公钥加解密,RSA私钥加解密,MD5withRSA 签名 MD5withRSA签名较验 -
RSA算法的Java实现
2022-02-22 09:13:38一、RSA算法描述 RSA主要利用的是大素数分解的困难性,即知道n如何求出p和q。 二、总体结构 //判断是否是素数 public static boolean isPrime(long n) { } //计算欧拉数 public static long Euler(long...一、RSA算法描述
RSA主要利用的是大素数分解的困难性,即知道n如何求出p和q。
二、总体结构
//判断是否是素数 public static boolean isPrime(long n) { } //计算欧拉数 public static long Euler(long p, long q) { } //欧几里得算法求两数的最大公因数---a>b static long gcd(long a, long b) { } //求模反元素d(私钥) public static long Key(long e, long euler) { } //递归求n次方 public static long power(long a, long n) { } //加密 public static long encryption(long msg, long e, long n) { } //解密 public static long decryption(long c, long key, long n) { } public static void main(String[] args) { }
三、模块分解
1.判断是否是素数
public static boolean isPrime(long n) { boolean b = true; for (long i = 2; i <= Math.sqrt(n); i++) { if (n % i == 0) { b = false; break; } else b = true; } return b; }
2.计算欧拉数
public static long Euler(long p, long q) { return (p - 1) * (q - 1); }
3.欧几里德算法求两数的最大公因数
static long gcd(long a, long b) { if (a < b) { long t = a; a = b; b = t; } if (a % b == 0) return b; else return gcd(b, a % b); }
4.求模范元素
public static long Key(long e, long euler) { long key = 1; while ((key * e) % euler != 1) { key++; } return key; }
5.递归求a的n次方
public static long power(long a, long n) { long r = 1; if (n == 0) r = 1; else { r = a * power(a, n - 1); } return r; }
6.加密过程
public static long encryption(long msg, long e, long n) { System.out.println("加密中......."); return power(msg, e) % n; }
7.解密过程
public static long decryption(long c, long key, long n) { System.out.println("解密中......."); return power(c, key) % n; }
四、数据结构
long p:大素数p
long q:大素数q
boolean b:判断素数的flag
long euler:p*q的欧拉数
long e:最小的加密密钥e
long key:e对euler的模范元素(即算法描述中的d)
long msg:明文
long c:密文
五、运行结果
这个是选取较小的素数进行测试得到的正确的结果,但是由于long的范围有限,当选取较大的素数进行测试的时候就会因为范围溢出导致数据丢失,从而影响最终的结果,具体如下图所示。
六、源代码
package RSA; import java.awt.desktop.SystemEventListener; import java.util.Scanner; public class Demo { //判断是否是素数 public static boolean isPrime(long n) { boolean b = true; for (long i = 2; i <= Math.sqrt(n); i++) { if (n % i == 0) { b = false; break; } else b = true; } return b; } //计算欧拉数 public static long Euler(long p, long q) { return (p - 1) * (q - 1); } //欧几里得算法求两数的最大公因数---a>b static long gcd(long a, long b) { if (a < b) { long t = a; a = b; b = t; } if (a % b == 0) return b; else return gcd(b, a % b); } //求模反元素d(私钥) public static long Key(long e, long euler) { long key = 1; while ((key * e) % euler != 1) { key++; } return key; } //递归求n次方 public static long power(long a, long n) { long r = 1; if (n == 0) r = 1; else { r = a * power(a, n - 1); } return r; } //加密 public static long encryption(long msg, long e, long n) { System.out.println("加密中......."); return power(msg, e) % n; } //解密 public static long decryption(long c, long key, long n) { System.out.println("解密中......."); return power(c, key) % n; } public static void main(String[] args) { System.out.println("--------RSA--------"); //两个大素数 long p; long q; System.out.print("输入两个大素数p、q:"); Scanner sc = new Scanner(System.in); p = sc.nextLong(); q = sc.nextLong(); // System.out.println("p = " + p + ",q = " + q); //判断输入的是否是素数 boolean b; //flag //判断p b = isPrime(p); if (b == false) { System.out.println("p = " + p + "不是素数。重新输入p!"); p = sc.nextLong(); b = isPrime(p); while (b = false) { System.out.println("p = " + p + "不是素数。重新输入p!"); p = sc.nextLong(); b = isPrime(p); } } System.out.println(" p = " + p + "是素数。"); //判断q b = isPrime(q); if (b == false) { System.out.println("q = " + q + "不是素数。重新输入q!"); q = sc.nextLong(); b = isPrime(q); while (b = false) { System.out.println("q = " + q + "不是素数。重新输入q!"); q = sc.nextLong(); b = isPrime(q); } } System.out.println(" q = " + q + "是素数。"); //打印最终的p、q System.out.println("p = " + p + ",q = " + q); //计算p、q的欧拉数 long euler = Euler(p, q); System.out.println("Euler(p,q) = " + euler); //选取最小的公钥e,1<e<euler,且与euler互质 long e = 2; while (gcd(e, euler) != 1 || e > euler || e < 1) { e++; } System.out.println("e = " + e); //求出模反元素(私钥) long key = Key(e, euler); System.out.println("key = " + key); //System.out.println(power(2, 2)); //加密过程 System.out.println("输入明文:"); long msg = sc.nextLong(); System.out.println("明文:" + msg); long c = encryption(msg, e, p * q);//密文 System.out.println("加密后的密文:" + c); //解密过程 msg = decryption(c, key, p * q); System.out.println("解密后的明文:" + msg); } }
-
RSA算法JAVA版
2013-06-01 16:51:38这是用JAVA编写的RSA算法,功能比较完整,不过注意支持的数字不能太大。 -
编程利用Java实现RSA算法
2021-06-17 14:46:58使用该程序可利用eclipse打开源代码文件夹,然后运行RSA.java即可根据默认的明文和密钥输出加密、解密结果。默认使用的密钥由文件读出的1024位大素数产生,也可以更改参数使用自定义算法产生指定位的大素数。同时为...1.使用说明
本程序利用eclipse使用Java语言编写。使用该程序可利用eclipse打开源代码文件夹,然后运行RSA.java即可根据默认的明文和密钥输出加密、解密结果。默认使用的密钥由文件读出的1024位大素数产生,也可以更改参数使用自定义算法产生指定位的大素数。同时为保证安全性以及照顾到算法加密、解密时间,两个大素数强制规定必须在1024位及以上,公钥指数为最常用的65537。
2.运行截图
3.总体设计
3.1类和函数
本程序只有一个RSA.java类。
- (1)public RSA(BigInteger e, int generateKeyFlag, int pqLength) throws RSA.pqException,该构造函数根据传入的形参公钥指数e、大质数p和q的产生方式标识generateKeyFlag、q和p的长度(比特数)pqLength,来调用函数generateKey来产生密钥(公钥和私钥)。
- (2)public static void main(String[] args) throws RSA.pqException,主函数指定明文等参数并调用函数encryption和decryption来进行加密、解密。
- (3)自定义内部类private class pqException extends Exception,只有一个构造函数传入形参message,用于输出由于大素数p、q不符合要求所产生的异常。
- (4)private void generateKey(int generateKeyFlag, int pqLength) throws RSA.pqException,密钥产生函数,形参分别是大质数p和q的产生方式标识(0:文件读入;1:随机产生)generateKeyFlag、p和q的长度(比特数)pqLength。
- (5)private BigInteger[] encryption(String plainText)RSA加密函数,形参传入String类型的明文plainText,返回加密后的BigInteger类型的数组。
- (6)private String decryption(BigInteger[] c)RSA解密函数,形参传入BigInteger数组类型表达的密文c,返回String类型的new String(result)解密结果。
- (7)private static BigInteger[] extdGcd(BigInteger e, BigInteger φn) 利用扩展欧几里得算法求出私钥d,使得de = kφ(n)+1,k为整数。形参分别是公钥e、φn (=(p-1)(q-1)),返回BigInteger数组形式返回最大公约数、私钥d、k(gdk)。
- (8)private static boolean isPrime(BigInteger p) 利用米勒·罗宾算法判断一个数是否是质数,形参是要判断的数,返回true/false。
- (9)private static BigInteger generateNBitRandomPrime(int n),随机产生n比特的素数,形参数比特数n,返回产生的素数。
- (10)private static BigInteger expMod(BigInteger base, BigInteger exponent, BigInteger module) 蒙哥马利快速幂模运算,返回base^exponent mod module的结果,形参分别是底数base、指数exponent、模数module,返回结果result。
3.2结构说明
RSA算法的具体描述如下:
- (1)任意选取两个不同的大素数p和q计算乘积n=pq,φ(n)=(p-1)(q-1);
- (2)任意选取一个大整数e,满足gcd(e, φ(n))=1且1<e<φ(n),e用做加密钥;
- (3)确定的解密钥d,满足(de)modφ(n)=1,即de=kφ(n)+1,k>=1且为整数;
- (4)公开整数n和e,秘密保存d;
- (5)将明文m(m<n,是一个整数)加密成密文c,加密算法为c=E(m)=memodn;
- (6)将密文c解密为明文m,解密算法为m=D©=cdmodn。
根据如上所示的RSA算法的基本流程,结合本实例来说明一下程序结构。公钥e直接使用通用的65537,在generateKey函数中可使用文件读入或随机的方式产生p、q,随机产生的方式会利用到函数generateNBitRandomPrime和isPrime产生指定位的素数,然后利用extdGcd函数计算出私钥d。接着在encryption加密函数中会根据m<n的原则进行分组逐组加密,利用expMod进行快速幂模运算,解密函数decryption中同样逐组利用expMod函数进行幂模运算。
4.详细设计
RSA.java类中定义三个变量,分别是两个大质数乘积n、公钥指数e、私钥指数d,以及一个常量PQMINLENGTH表示质数q和p最小长度(比特数)。
- (1)public RSA(BigInteger e, int generateKeyFlag, int pqLength) throws RSA.pqException,该构造函数根据传入的形参公钥指数e、大质数p和q的产生方式标识generateKeyFlag、q和p的长度(比特数)pqLength,来调用函数generateKey来产生密钥(公钥和私钥)。
- (2)public static void main(String[] args) throws RSA.pqException,主函数定义变量generateKeyFlag、pqLength(p和q长度,比特数)、公钥指数e、以及要加密的原文originalText。利用指定参数初始化对象,然后调用函数encryption并传入原文进行加密同时返回密文数组,并输出密文。再将密文数组传进decryption函数来进行解密并返回明文。
- (3)自定义内部异常类private class pqException extends Exception,该自定义异常类很简单,只有一个构造函数传入形参字符串类型的形参message,用于输出由于大素数p、q不符合要求所产生的异常。
- (4)private void generateKey(int generateKeyFlag, int pqLength) throws RSA.pqException,密钥产生函数,形参分别是大质数p和q的产生方式标识(0:文件读入;1:随机产生)generateKeyFlag、p和q的长度(比特数)pqLength。首先定义两个大素数和φ(n),也就是大素数分别减一的乘积。判断素数产生的标识,如果为0则代表由文件读入。利用FileReader和BufferedReader对象,利用循环和后者的readline逐行读物出两个素数并赋值(文件中的两个素数按行存取,每一行代表一个素数),然后利用close方法关闭输入流。
- 接着逐个两个两个数是否是质数(利用函数isPrime判定)、长度是否大于所规定的,如果不满足其中一个则直接抛出异常,程序结束。如果是随机产生两个大素数,首先对参数pqLength判断是否小于规定的最小长度,如果小于,则抛出指定的自定义异常,程序结束;否则调用函数generateNBitRandomPrime传入素数长度这个产生两个素数。
- 接着分别求出n和φ(n),并利用自定义的扩展欧几里得算法extdGcd求出私钥d,如果求出的私钥小于0,则加上φ(n)即可。
- (5)private BigInteger[] encryption(String plainText)RSA加密函数,形参传入String类型的明文plainText,返回加密后的BigInteger类型的数组。利用getByte函数将String类型的明文转化为byte数组类型,指定编码为UTF-8,然后这里每个字节利用3为整数来表示,不够则在前面补0,因此循环遍历字节数组将每位和0xff(16进制数,10进制为255)进行与操作得到一个非负整数,然后添加到字符串上。
- 之后利用BigInteger的构造函数将这字符串转化为BigInteger类型保存在m上,判定该数是否小于n,若小于n则为mArray数组分配一个BigInteger大小的空间并将m保存到该数组上;如果大于n,由于算法的规定,因此需要进行分组加密,每组的长度规定为n的字符串的长度-1,这样是避免分组后大小依然超过n。同时也由于前面的每个字节是由3位整数保存的,因此分组的长度也应该为3的整数,避免恢复时出错。
- 因此判读此时的每组长度是否为3的整数,如果不是,则减一。然后判断明文数字形式字符串长度模上每组的长度是否为0,如果补是则明文数组mArray应该为明文数字字符串长度除每组长度加1,否则就不用加1。接着利用循环分割明文数字形式字符串保存在BigInteger数组中,然后再次利用循环调用expMod快速幂模函数逐组加密保存到数组上并返回。
- (6)private String decryption(BigInteger[] c)RSA解密函数,形参传入BigInteger数组类型表达的密文c,返回String类型的new String(result)解密结果。对密文BigInteger数组利用快速幂模函数expMod进行逐组解密,由于解密出来的每组的数字可能由于最前面的数字为0而缺失,导致转化为byte数组时出错,因此这里需要判断 是否为3的整数,如果不是则在最前面补0直到为3的整数倍,然后将每组所得的结果组合成一个长的数字字符串,利用循环每3为代表一个字节逐段截取并强化转为byte类型(byte) (Integer.parseInt(cPadding.substring(i * 3, i * 3 + 3))),并保存到byte数组上,然后利用String构造方法将次byte数组转化为明文。
- (7)private static BigInteger[] extdGcd(BigInteger e, BigInteger φn) 利用扩展欧几里得算法求出私钥d,使得de = kφ(n)+1,k为整数。形参分别是公钥e、φn (=(p-1)(q-1)),返回BigInteger数组形式返回最大公约数、私钥d、k(gdk)。7~10涉及到的数学原理就不再过多介绍,因为我们的重点并不在这里。定义3个BigInteger大小的数组用来保存最大公约数g、私钥d、k,如果φ(n)为0,为将公钥指数e赋给g,1赋给d,0赋给k,并返回gdk;否则将传入φ(n),e % φ(n)递归调用该函数,然后临时保存k,k为d-e/φ(n)*k,将临时保存的k赋给d,最后返回。
- (8)private static boolean isPrime(BigInteger p) 利用米勒·罗宾算法判断一个数是否是质数,形参是要判断的数,返回true/false。如果小于2则返回false,又不为2且可以整除2也直接返回false,否则利用如下代码BigInteger p_1 = p.subtract(BigInteger.ONE);BigInteger m = p_1;int q = m.getLowestSetBit();m = m.shiftRight(q); 找到q和m使得p = 1 + 2^q * m。然后在1~p区间上生成均匀随机数,将下面步骤的利用循环判断5轮(判断的轮数,精度、轮数和时间三者之间成正比关系),BigInteger z = RSA.expMod(b, m, p);while (!((j == 0 && z.equals(BigInteger.ONE)) || z.equals(p_1))) {if ((j > 0 && z.equals(BigInteger.ONE)) || ++j == q) {return false;}z = RSA.expMod(z, BigInteger.TWO, p);},若通过了米勒·罗宾算法则代表是素数,返回true。
- (9)private static BigInteger generateNBitRandomPrime(int n),随机产生n比特的素数,形参数比特数n,返回产生的素数。这里主要的思想是先算出在该比特数下的最小数,也就是2^(n-1),然后先随机生成一个1-100的整数用于确定0和1出现的比率,保证生成的01的概率都是50%,然后除了最高位(最高位肯定是1),逐位产生01并根据所在位置计算值和最小值相加,也就是二进制转化为10进制,最后便得到一个指定位的整数,然后利用前面的素数判断函数判断该数是否是素数,如果是则直接返回否则继续生成,直到是素数为止。
- (10)private static BigInteger expMod(BigInteger base, BigInteger exponent, BigInteger module) 蒙哥马利快速幂模运算,返回base^exponent mod module的结果,形参分别是底数base、指数exponent、模数module,返回结果result。Result为1,tmp = base.mod(module)。循环条件为指数不为0,然后判断指数和1进行与操作的值是否为0,如果不是则result = result.multiply(tmp).mod(module);出if语句,然后tmp = tmp.multiply(tmp).mod(module);,指数右移1位,继续进行循环,循环结束返回结果即可。
5.源码
-
25行代码实现完整的RSA算法Java版
2018-03-29 00:07:4325行代码实现完整的RSA算法Java版 我的上一篇博客《25行代码实现完整的RSA算法》自从上个月发表了以后,很多程序员给我打电话或者发短信说,终于看到了一篇能把RSA算法的代码写明白的,他们问我说能不能把...25行代码实现完整的RSA算法Java版
我的上一篇博客《25行代码实现完整的RSA算法》自从上个月发表了以后,很多程序员给我打电话或者发短信说,终于看到了一篇能把RSA算法的代码写明白的,他们问我说能不能把代码写成Java版的,我说Java的会看着很费劲,Python代码的直观性在数字计算方面有很大的优势。
但是架不住他们非要我写,我一拍肩膀说,好吧,我答应你们的请求。花了一晚上的时间,就把代码从Python翻译成为Java,经过测试完美。如果写得不好,请大家轻轻拍砖。
至于RSA理论我就不再这里讲了,代码如果看不懂,请看我的上一篇博客《25行代码实现完整的RSA算法》。下面就主要把代码贴出来了。1、计算最大公约数与扩展欧几里得算法
GCD.java文件,gcd方法用来计算两个整数的最大公约数。ext_gcd是扩展欧几里得方法的计算公式。
import java.math.BigInteger; /** * 求最大公约数 * @author 北门大官人 * */ public class GCD { /** * <p>辗转相除法求最大公约数 * @param a * @param b * @return */ public BigInteger gcd(BigInteger a, BigInteger b){ if(b.equals(BigInteger.ZERO)){ return a ; }else{ return gcd(b, a.mod(b)) ; } } /** * <p>扩展欧几里得算法: * <p>求ax + by = 1中的x与y的整数解(a,b互质) * @param a * @param b * @return */ public BigInteger[] extGcd(BigInteger a, BigInteger b){ if(b.equals(BigInteger.ZERO)){ BigInteger x1 = BigInteger.ONE ; BigInteger y1 = BigInteger.ZERO ; BigInteger x = x1 ; BigInteger y = y1 ; BigInteger r = a ; BigInteger[] result = {r, x, y} ; return result ; }else{ BigInteger[] temp = extGcd(b, a.mod(b)) ; BigInteger r = temp[0] ; BigInteger x1 = temp[1] ; BigInteger y1 = temp[2] ; BigInteger x = y1 ; BigInteger y = x1.subtract(a.divide(b).multiply(y1)) ; BigInteger[] result = {r, x, y} ; return result ; } } }
2、大整数幂取模算法
Exponentiation.java文件,主要用于计算超大整数超大次幂然后对超大的整数取模。我在网上查询到这个算法叫做“蒙哥马利算法”。
import java.math.BigInteger; import java.util.ArrayList; import java.util.List; /** * 主要用于计算超大整数超大次幂然后对超大的整数取模。 * 我在网上查询到这个算法叫做"蒙哥马利算法"。 * @author 北门大官人 */ public class Exponentiation { /** * 超大整数超大次幂然后对超大的整数取模 (base ^ exponent) mod n * @param base * @param exponent * @param n * @return */ public BigInteger expMode(BigInteger base, BigInteger exponent, BigInteger n){ char[] binaryArray = new StringBuilder(exponent.toString(2)).reverse().toString().toCharArray() ; int r = binaryArray.length ; List<BigInteger> baseArray = new ArrayList<BigInteger>() ; BigInteger preBase = base ; baseArray.add(preBase); for(int i = 0 ; i < r - 1 ; i ++){ BigInteger nextBase = preBase.multiply(preBase).mod(n) ; baseArray.add(nextBase) ; preBase = nextBase ; } BigInteger a_w_b = this.multi(baseArray.toArray(new BigInteger[baseArray.size()]), binaryArray, n) ; return a_w_b.mod(n) ; } private BigInteger multi(BigInteger[] array, char[] bin_array, BigInteger n){ BigInteger result = BigInteger.ONE ; for(int index = 0 ; index < array.length ; index ++){ BigInteger a = array[index] ; if(bin_array[index] == '0'){ continue ; } result = result.multiply(a) ; result = result.mod(n) ; } return result ; } }
3、公钥私钥生成
RSA.java,生成公钥、私钥、并对信息加密解密。
import java.math.BigInteger; /** * RSA加密、解密、测试正确性 * @author 北门大官人 * */ public class RSA { /** * <pre> def gen_key(p, q): n = p * q fy = (p - 1) * (q - 1) e = 3889 # generate d a = e b = fy r, x, y = ext_gcd(a, b) print x d = x # 公钥 私钥 return (n, e), (n, d) </pre> * @param p * @param q * @return */ public BigInteger[][] genKey(BigInteger p, BigInteger q){ BigInteger n = p.multiply(q) ; BigInteger fy = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE)) ; BigInteger e = new BigInteger("65537") ; // generate d BigInteger a = e ; BigInteger b = fy ; BigInteger[] rxy = new GCD().extGcd(a, b) ; BigInteger r = rxy[0] ; BigInteger x = rxy[1] ; BigInteger y = rxy[2] ; BigInteger d = x ; // 对于计算出来的负数d,需要d=d+fy if(d.compareTo(BigInteger.valueOf(0)) < 0){ d = d.add(fy) ; } // 公钥 私钥 return new BigInteger[][]{{n , e}, {n , d}} ; } /** * 加密 * @param m 被加密的信息转化成为大整数m * @param pubkey 公钥 * @return */ public BigInteger encrypt(BigInteger m, BigInteger[] pubkey){ BigInteger n = pubkey[0] ; BigInteger e = pubkey[1] ; BigInteger c = new Exponentiation().expMode(m, e, n) ; return c ; } /** * 解密 * @param c * @param selfkey 私钥 * @return */ public BigInteger decrypt(BigInteger c, BigInteger[] selfkey){ BigInteger n = selfkey[0] ; BigInteger d = selfkey[1] ; BigInteger m = new Exponentiation().expMode(c, d, n) ; return m ; } public static void main(String[] args) { // 公钥私钥中用到的两个大质数p,q''' BigInteger p = new BigInteger("106697219132480173106064317148705638676529121742557567770857687729397446898790451577487723991083173010242416863238099716044775658681981821407922722052778958942891831033512463262741053961681512908218003840408526915629689432111480588966800949428079015682624591636010678691927285321708935076221951173426894836169") ; BigInteger q = new BigInteger("144819424465842307806353672547344125290716753535239658417883828941232509622838692761917211806963011168822281666033695157426515864265527046213326145174398018859056439431422867957079149967592078894410082695714160599647180947207504108618794637872261572262805565517756922288320779308895819726074229154002310375209") ; RSA rsa = new RSA() ; // 生成公钥私钥''' // pubkey, selfkey = gen_key(p, q) BigInteger[][] keys = rsa.genKey(p, q) ; BigInteger[] pubkey = keys[0] ; BigInteger[] selfkey = keys[1] ; // 需要被加密的信息转化成数字,长度小于秘钥n的长度,如果信息长度大于n的长度,那么分段进行加密,分段解密即可。''' BigInteger m = new BigInteger("1356205320457610288745198967657644166379972189839804389074591563666634066646564410685955217825048626066190866536592405966964024022236587593447122392540038493893121248948780525117822889230574978651418075403357439692743398250207060920929117606033490559159560987768768324823011579283223392964454439904542675637683985296529882973798752471233683249209762843835985174607047556306705224118165162905676610067022517682197138138621344578050034245933990790845007906416093198845798901781830868021761765904777531676765131379495584915533823288125255520904108500256867069512326595285549579378834222350197662163243932424184772115345") ; System.out.println("被加密信息:" + m); // 信息加密''' BigInteger c = rsa.encrypt(m, pubkey) ; System.out.println("密文:" + c); // 信息解密''' BigInteger d = rsa.decrypt(c, selfkey) ; System.out.println("被解密后信息:" + d); } }
用Java写出来的数值运算就是没有Python的直观。大整数运算只能用BigInteger,确实看得人眼睛疼。如果哪里不懂可以对照上一篇《25行代码实现完整的RSA算法》一起看,祝大家晚安。
代码经过运行以后,发现加密的速度很快,但是解密的速度有点惨不忍睹。在2048位秘钥的时候,解密时间为0.14秒,比Python版的慢3倍多。python只用0.038秒左右。由此说明,Java语言不适合做数值运算,而Python语言在这方面有着很大的优势。
最后,觉得代码写得好的,请给我打赏
-
RSA算法JAVA公钥加密,C#私钥解密
2015-03-28 16:49:21可以直接运行成功的RSA加密解密示例 JAVA端采用公钥加密,服务端C#采用私钥解密。 -
rsa算法java实现的txt格式版本
2015-05-25 19:30:50从网上找到的,是别人的代码,但是自己还是不会,而且在自己的机子里实现不了,但是大神们可以看看,就不要积分了。 -
非对称加密算法:RSA算法的C++实现与Java实现
2021-04-23 21:54:30包括RSA算法的两种语言实现,原理正确,可以正常运行,对应博客为:https://blog.csdn.net/qq_41112170/article/details/104904340 -
RSA算法java实现(BigInteger类的各种应用)
2021-02-28 13:04:08一、RSA算法1.密钥生成随机生成两个大素数p、q计算n=p*q计算n的欧拉函数f=(p-1)*(q-1)选取1计算d,ed=1modf公钥为(e,n),私钥为(d,n)2.加密c=m^e mod n3.解密m=c^e mod n二、BigInteger类(大数)定义:BigInteger b=... -
rsa加密算法的java实现实例
2018-06-01 22:45:40提供了rsa算法的java类及测试代码.其中已经用过,有需要的可以拿去 -
RSA公钥加密算法Java实现
2018-01-07 19:44:14RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。 这时一个简单的Java实现,在RSA网络安全工具类是比较完整的实现。 -
Java加密算法RSA代码实例
2020-08-25 01:32:11主要介绍了Java加密算法RSA代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 -
RSA加密算法java简单实现方法(必看)
2020-09-01 15:22:17下面小编就为大家带来一篇RSA加密算法java简单实现方法(必看)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧 -
RSA算法JAVA实现的代码
2013-11-23 10:59:16RSA加密解密,物流信息安全方面,用java实现rsa算法。 -
RSA加密算法+界面(java)
2013-12-15 11:23:51RSA算法,有界面操作,能随机产生素数,进而随机产生公钥和私钥,功能完善 -
网络安全 RSA算法 java实现
2013-12-31 21:48:27RSA jar包是网络安全中关于RSA算法的实现,是我实习的时候写的 -
RSA算法JAVA通用代码
2018-08-21 20:48:51一 获取密钥 KeyPairGenerator keyPairGenerator = ...RSA"); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); 二 保存公钥 因为公钥是二进制... -
用java编程实现RSA加密算法
2021-03-07 11:02:25那么我今天就给大家介绍一下如何利用Java编程来实现RSA加密算法。一、RSA加密算法描述RSA加密算法是1978年提出的。经过多年的分析和研究,在众多的公开密钥加密算法中,RSA加密算法最受推崇,它也被推荐为公开密钥... -
RSA算法介绍及JAVA实现详解
2021-02-12 14:44:15最近处理RSA算法,找了一些相关的资料和代码,整理了一下,汇总成这篇文章。基础RSA算法非常简单,概述如下:找两素数p和q取n=p*q取t=(p-1)*(q-1)取任何一个数e,要求满足e取d*e%t==1这样最终得到三个数: n d e设... -
RSA算法JS加密JAVA解密
2017-10-30 16:20:00RSA非对称算法,前端JS通过公钥加密,后端JAVA通过私钥解密 -
RSA算法加解密java工具
2020-02-23 23:15:56RSA算法加解密java工具, 包括: 创建公钥、私钥、加密、解密、分段加密 创建公钥、私钥、加密、解密、分段加密 创建公钥、私钥、加密、解密、分段加密 -
Java实现的RSA加密解密算法示例
2020-08-28 05:24:16主要介绍了Java实现的RSA加密解密算法,结合实例形式分析了java RAS加密解密算法的相关实现技巧,需要的朋友可以参考下 -
浅析用Java编程实现RSA算法的过程.pdf
2021-07-02 19:00:16浅析用Java编程实现RSA算法的过程.pdf -
RSA加密算法实现 Java版
2019-05-15 10:05:29RSA加密算法是一种非对称加密算法,其玩法打破了以往所有加密算法的规则.在RSA出现之前,所有的加密方法都是同一种模式:加密解密的规则使用同一种方式.这种长达几个世纪的加密方案有一个致命的缺陷.在传递加密信息时,... -
非对称加密——RSA算法JAVA代码实践
2020-11-18 17:41:322:下面代码是RSA在JAVA中API级别的代码实现,具体实现原理见前面章节 3:下面代码中只需要JDK即可,其中为了便于阅读使用了commons-codec中Base64编码 4:公钥密码既可以公钥加密私钥解密,又可以私钥加密公钥解密... -
Java -- RSA 非对称加密算法工具类
2022-05-01 14:54:44RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制” RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪...本文提供RSA 非对称加密算法工具类