1、RSA算法的简介
由Ron Rivest、 Adi Shamir 和 Leonard Adleman三位学者提出的非对称加密算法。RSA 算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。它是第一个既能用于数据加密也能用于数字签名的算法。
2、RSA 数学原理
(1)加解密公式
RSA加密:密文 = 明文E mod N 公钥(E,N)
RSA解密:明文 = 密文D mod N 私钥(D,N)
(2)模拟生成密钥对
1)求N:p=17 q=19 N=p*q = 323
2)求L:L=lcm(p-1,q-1)=lcm(16,18) = 144
3)求E:gcd(E,L)=1 E=5
4)求D:E*D mod L = 1 D=29
公钥(5,323) 私钥(29,323)
(3)加密
密文 = 明文E mod N = 1235 mod 323 = 225
(4)解密
明文 = 密文D mod N = 22529 mod 323 = 123
3、JDK的实现
4、RSA算法编程步骤
4.1 生成公钥和私钥
4.2 加密/解密
5、RSA算法的实现
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
public class RSAUtil {
public static final String PUBLIC_KEY = "RSAPublicKey";
public static final String PRIVATE_KEY = "RSAPrivateKey";
public static final String KEY = "RSA";
/**
* 生成 RSA 的 公钥 和 私钥
*
* @return
*/
public static Map<String, Object> initKey() {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator
.getInstance(KEY);
keyPairGenerator.initialize(1024); // 512-65536 & 64的倍数
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, Object> keyMap = new HashMap<String, Object>();
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取RSA的公钥
*
* @param keyMap
* @return
*/
public static RSAPublicKey getPublicKey(Map<String, Object> keyMap) {
RSAPublicKey publicKey = (RSAPublicKey) keyMap.get(PUBLIC_KEY);
return publicKey;
}
/**
* 获取RSA的私钥
*
* @param keyMap
* @return
*/
public static RSAPrivateKey getPrivateKey(Map<String, Object> keyMap) {
RSAPrivateKey privateKey = (RSAPrivateKey) keyMap.get(PRIVATE_KEY);
return privateKey;
}
/**
* 公钥加密
*
* @param data
* 要加密的数据
* @param publicKey
* 公钥
* @return
* @throws Exception
*/
public static byte[] encrypt(byte[] data, RSAPublicKey publicKey) {
try {
Cipher cipher = Cipher.getInstance(KEY);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cipherBytes = cipher.doFinal(data);
return cipherBytes;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 私钥解密
*
* @param data
* 要解密的数据
* @param privateKey
* 私钥
* @return
* @throws Exception
*/
public static byte[] decrypt(byte[] data, RSAPrivateKey privateKey) {
try {
Cipher cipher = Cipher.getInstance(KEY);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] plainBytes = cipher.doFinal(data);
return plainBytes;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
字节数组转16进制
public class BytesToHex {
public static String fromBytesToHex(byte[] resultBytes) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < resultBytes.length; i++) {
if (Integer.toHexString(0xFF & resultBytes[i]).length() == 1) {
builder.append("0").append(
Integer.toHexString(0xFF & resultBytes[i]));
} else {
builder.append(Integer.toHexString(0xFF & resultBytes[i]));
}
}
return builder.toString();
}
}
测试代码
public class Test {
// 待加密的明文
public static final String DATA = "test";
public static void main(String[] args) throws Exception {
/* Test RSA */
Map<String, Object> keyMap = RSAUtil.initKey();
RSAPublicKey rsaPublicKey = RSAUtil.getPublicKey(keyMap);
RSAPrivateKey rsaPrivateKey = RSAUtil.getPrivateKey(keyMap);
System.out.println("RSA PublicKey : " + rsaPublicKey);
System.out.println("RSA PrivateKey : " + rsaPrivateKey);
byte[] rsaResult = RSAUtil.encrypt(DATA.getBytes(), rsaPublicKey);
System.out.println(DATA + ">>>RSA 加密>>>"
+ BytesToHex.fromBytesToHex(rsaResult));
byte[] plainResult = RSAUtil.decrypt(rsaResult, rsaPrivateKey);
System.out.println(DATA + ">>>RSA 解密>>>" + new String(plainResult));
}
}