RSA实例代码
通过上一篇的RSA算法原理了解之后,这里用一段简易的Java代码进行演示。
-
首先我们创建一个类,然后在main方法中通过BigInteger.probablePrime(int bitLength, Random rnd)方法生成两个素数
System.out.println(BigInteger.probablePrime(10, new Random())); System.out.println(BigInteger.probablePrime(10, new Random())); // 613 // 523
这里我生成的两个素数为 613 523,然后将两个素数相乘,613 * 523 = 320599[数字1]
-
将两个素数分别减一相乘,612 * 522 = 319464[数字2]
-
再通过随机数生成一个公钥 757。这个数不能与两个素数相同且小于数字2
System.out.println(BigInteger.probablePrime(10, new Random())); // 757
-
再通过下面的 for循环找出私钥。注意:公钥与私钥并非是一对的,也就是说一个公钥可以对应多个私钥。
for (int i = 0; i < 846216; i++) { // 私钥满足条件:公钥产生私钥除以数字2余1 if (((757 * i) % 319464) == 1) { System.out.println("私钥为:" + i); // 95797、415261、734725 } }
-
在这里我们得到公钥和私钥后,就可以发送我们所需要发送的东西了
比如我们发送一个密码,123456。通过模指运算来进行加密和解密。
System.out.println(new BigInteger("123456").modPow(new BigInteger("757"), new BigInteger("320599"))); // 172243 // 172243,这就是通过模指运算加密后的 System.out.println(new BigInteger("172243").modPow(new BigInteger("95797"), new BigInteger("320599"))); // 172243解密后就是123456
完整代码:
public class RSA {
public static void main(String[] args) {
System.out.println(BigInteger.probablePrime(10, new Random()));
System.out.println(BigInteger.probablePrime(10, new Random()));
for (int i = 0; i < 846216; i++) {
// 私钥满足条件:公钥产生私钥除以数字2余1
if (((757 * i) % 319464) == 1) {
System.out.println("私钥为:" + i); // 95797、415261、734725
}
}
System.out.println("加密后:");
System.out.println(new BigInteger("123456").modPow(new BigInteger("757"), new BigInteger("320599"))); // 172243,这就是通过模指运算加密后我们所需发给银行的
System.out.println("解密后:");
System.out.println(new BigInteger("172243").modPow(new BigInteger("95797"), new BigInteger("320599"))); // 172243解密后就是123456
}
}
标准的RSA算法模拟代码
导入第三方加密库的依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
<!-- 引入第三方加密库 bouncycastle的依赖 -->
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk16 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
</dependency>
</dependencies>
创建 RSA的公钥和密钥的PSAKeyCreator类
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.*;
import java.util.Base64;
/**
* Created by wb on 2020/9/4 0004 19:33
*
* 创建 RSA的公钥和私钥
*/
public class RSAKeyCreator {
public static void main(String[] args) {
createKeyPairs();
}
/*
* 生成公钥和私钥
*/
private static void createKeyPairs() {
Security.addProvider(new BouncyCastleProvider());
// KeyPairGenerator 密钥对的生成器
try {
// KeyPairGenerator.getInstance(algorithm): 需要放置一个字符串,也就是算法的名称
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
// initialize(keysize, random): 密钥的大小,随机数
generator.initialize(512, new SecureRandom()); // 初始化 generator
// 这里就可以通过 generator获取到密钥对(公钥、私钥)
KeyPair pair = generator.generateKeyPair();
PublicKey publicKey = pair.getPublic(); // 返回一个公钥对象
PrivateKey privateKey = pair.getPrivate(); // 返回一个私钥对象
// 接下来就需要将公钥和私钥转换成可识别的字符串,这里就需要进行 Base64的编码
// 通过 Base64获取到一个编码对象,编码对象里面的一个编码方法就可以获得 publicKey.getEncoded()的字节数组
// 然后再将字节数组转换成 Base64的字符串
String strPublicKey = new String(Base64.getEncoder().encode(publicKey.getEncoded())); // 公钥字符串
String strPrivateKey = new String(Base64.getEncoder().encode(privateKey.getEncoded())); // 私钥字符串
System.out.println(strPublicKey);
System.out.println(strPrivateKey);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
RSA加密/解密的RSAUtil工具类
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
/**
* Created by wb on 2020/9/4 0004 19:33
*
* 封装标准的 RSA加密/解密算法的工具类
*/
public class RSAUtil {
/*
* RSA公钥加密
*
* 参数:第一个是需要加密的明文字符串,第二参数是公钥对象
*/
public static String publicKeyEncryptData(String data, PublicKey publicKey) {
try {
// Cipher密码对象
Cipher cipher = Cipher.getInstance("RSA");
// 通过公钥进行加密
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 加密后的字节数组
byte[] encryptData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); // 使用 utf-8字符编码加密
// 获取加密字符串的结果,并返回
return Base64.getEncoder().encodeToString(encryptData);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/*
* RSA私钥解密
*
* 参数:第一个是需要加密后的字符串,第二参数是私钥对象
*/
public static String privateKeyDecryptData(String encryptData, PrivateKey privateKey) {
try {
// Cipher密码对象
Cipher cipher = Cipher.getInstance("RSA");
// 通过私钥进行解密
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 通过 Base64进行解码,然后返回一个字节数组
byte[] decryptData = cipher.doFinal(Base64.getDecoder().decode(encryptData));
// 转换成明文的字符串并返回
return new String(decryptData, StandardCharsets.UTF_8); // 使用 utf-8字符编码解密
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 扩展内容
/*
* RSA私钥加密
*
* 参数:第一个是需要加密的明文字符串,第二参数是私钥对象
*/
public static String privateKeyEncryptData(String data, PrivateKey privateKey) {
try {
// Cipher密码对象
Cipher cipher = Cipher.getInstance("RSA");
// 通过公钥进行加密
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
// 加密后的字节数组
byte[] encryptData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); // 使用 utf-8字符编码加密
// 获取加密字符串的结果,并返回
return Base64.getEncoder().encodeToString(encryptData);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/*
* RSA公钥解密
*
* 参数:第一个是需要加密后的字符串,第二参数是公钥对象
*/
public static String publicKeyDecryptData(String encryptData, PublicKey publicKey) {
try {
// Cipher密码对象
Cipher cipher = Cipher.getInstance("RSA");
// 通过私钥进行解密
cipher.init(Cipher.DECRYPT_MODE, publicKey);
// 通过 Base64进行解码,然后返回一个字节数组
byte[] decryptData = cipher.doFinal(Base64.getDecoder().decode(encryptData));
// 转换成明文的字符串并返回
return new String(decryptData, StandardCharsets.UTF_8); // 使用 utf-8字符编码解密
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
RSA算法测试
import fun.wblog.utils.RSAUtil;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
* Created by wb on 2020/9/4 0004 20:06
*/
public class RSATest {
public static void main(String[] args) {
// 公钥字符串
String strPublicKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJHXc9MzZLGNrs6nAB/PmaDopfOoOaiN9M+4ZSli/JW5XRx/2+DL8VPhOMadWiLUDYwtMjAlHO9YYOmAR+mIDKsCAwEAAQ==";
// 私钥字符串
String strPrivateKey = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAkddz0zNksY2uzqcAH8+ZoOil86g5qI30z7hlKWL8lbldHH/b4MvxU+E4xp1aItQNjC0yMCUc71hg6YBH6YgMqwIDAQABAkBOTqYlT+IQJ+glk6vQaNKvgFui4b/bziUV54eB2mGPLkFvbPPz6eEIu0XEvouBxGBxmgp/vMysEjDPzLcL8cIxAiEAzhNpbW5Yt4Hwej2JyHKsbHKPV1NaPp3gb4Cq9eJJMYMCIQC1LGIS+r2+e4hyPDEj4IFbjRxq2dRQ0CnlzHXo76WXuQIgYLTlXdBR29QjqQnl9eYymjXspJteF1J5d3oXQIpvtMcCIQCvu6JRyJdd+ZNLQyljJHQ1KnYDCtGPparONPm1/SZBOQIhAJpjZWIU3G8dAxtcdA7xhUOV4OiL/u8QPiOfSRjWZIjR";
// 公钥规则对象/公钥说明书对象
X509EncodedKeySpec x509EncodedKeySpec =
new X509EncodedKeySpec(Base64.getDecoder().decode(strPublicKey.getBytes()));
// 私钥规则对象/私钥说明书对象
PKCS8EncodedKeySpec pkcs8EncodedKeySpec =
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(strPrivateKey.getBytes()));
try {
// 密钥工厂对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// 通过 x509EncodedKeySpec规则生成公钥
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
// 通过 pkcs8EncodedKeySpec规则生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
// ===================================================================//
String data = "RSA加密解密算法@###123456%&"; // 明文
System.out.println("明文是: " + data);
// 1.调用公钥加密方法
String encryptData = RSAUtil.publicKeyEncryptData(data, publicKey);
System.out.println("公钥加密后: " + encryptData);
// 2.调用私钥解密方法
String decryptData = RSAUtil.privateKeyDecryptData(encryptData, privateKey);
System.out.println("私钥解密后: " + decryptData);
// 扩展内容==========================================================//
// 3.调用私钥加密方法
String encryptData2 = RSAUtil.privateKeyEncryptData(data, privateKey);
System.out.println("私钥加密后: " + encryptData2);
// 4.调用公钥解密方法
String decryptData2 = RSAUtil.publicKeyDecryptData(encryptData2, publicKey);
System.out.println("公钥解密后: " + decryptData2);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
}
}
}
https://i.loli.net/2020/09/05/TyZPsoczardQU89.gif
总结:
先通过KeyPairGenerator来生成密钥对,然后再去封装加密和解密的方法。
在工具类中最主要的实现加密和解密的关键的对象是靠Cipher密码对象通过getInstance()去找它的这个密码算法,然后实现了这个对象。这个对象的关键一点就是有两个常量,一个常量是ENCRYPT_MODE加密模式,一个常量是DECRYPT_MODE解密模式。
然后在使用的过程再去将我们的公钥和私钥字符串,把它转成一个公钥对象和私钥对象,那么如何将公钥字符串/私钥字符串转成公钥对象/私钥对象呢?那么就要使用到了一个公钥规则对象(公钥说明书X509EncodedKeySpec)/私钥规则对象(私钥说明书PKCS8EncodedKeySpec)。拿到这个说明书对象,我们最终的主要目的就是通过KeyFactory去生成一个公钥对象和私钥对象,这样就可以使用我们之前封装的加密解密工具了。从而对我们的明文进行加密和解密。