RSA对称加密
RSA
工作原理
- 密钥生成:
• 选择两个大素数 p 和 q ,计算 n = p \times q 。
• 计算 \phi(n) = (p - 1) \times (q - 1) (欧拉函数)。
• 选择一个整数 e 满足 1 < e < \phi(n) 且 \gcd(e, \phi(n)) = 1 。
• 计算 d 使得 e \cdot d \equiv 1 \ (\text{mod} \ \phi(n)) 。
• 公钥:(e, n),用于加密。
• 私钥:(d, n),用于解密。 - 加密:
• 将明文 M 转换为数字 m (确保 m < n )。
• 使用公钥进行加密: c = m^e \mod n 。 - 解密:
• 使用私钥解密: m = c^d \mod n ,还原出明文 M 。 - 数字签名:
• 使用私钥对消息的哈希值进行加密,生成签名。
• 验签时用公钥解密签名,并与计算出的哈希值进行比较。
优缺点
优点:
• 安全性:基于大整数分解难题,攻击复杂度高。
• 灵活性:支持加密、签名和密钥交换。
• 互操作性:广泛支持,各种协议(如 HTTPS、SSL/TLS)中广泛应用。
缺点:
• 性能较差:比对称加密算法(如 AES)慢得多,通常仅用于加密小数据(如对称密钥)。
• 密钥长度长:安全性依赖于密钥长度,密钥越长性能越低。
RSA 2048 vs 4096
密钥长度
• RSA 的密钥长度指 n 的位数,例如:
• 2048 位密钥: n 是一个约 617 位十进制数。
• 4096 位密钥: n 是一个约 1234 位十进制数。
密钥长度越长,破解的难度越高,但计算性能也会显著下降。
安全性
1. RSA 2048 位:
• 被认为足够安全,可抵抗现有经典计算机的攻击。
• 当前技术下,通过分解 n 破解 RSA 2048 位需要数十亿年的计算。
2. RSA 4096 位:
• 提供更高的安全性,但在实际中很少使用。
• 通常用于高安全性场景,但性能代价较大。
性能比较
1. 加密/解密速度:
• RSA 算法的加解密速度与密钥长度的三次方成正比。
• RSA 2048 位的加解密速度明显快于 RSA 4096 位。
2. 存储需求:
• RSA 4096 位密钥的存储需求约为 RSA 2048 位的两倍。
实际应用建议
1. RSA 2048 位:
• 已成为目前的行业标准,用于绝大多数场景(如 HTTPS、SSL/TLS 等)。
• 安全性足够强,性能表现平衡。
2. RSA 4096 位:
• 用于对安全性有极高要求的场景(如政府、军方、关键基础设施)。
• 在量子计算逐渐成熟的未来可能更有意义,但目前 RSA 2048 已足够安全。
代码
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
* RSA对称加密解密工具包
*/
public class RsaEncryptionUtil {
//公钥 base64加密的公钥
public final static String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsY4RhB9cz9IBt4E73EAYNq2v0Dzc/2GfV/4fqNOefqATD/1HHez1YthpEyA0qKqJbaVTcjetioJJubxgM6edTfOVe5k/TWrt8ykGIQmM0YG+XED1GmMvwjVI+38fLBxbMWMaDRU/2qBcrEMd9VUbyh3q29HIZElNv7vmLLBoi2KswMuMf3Uf/QOlph2NoXvpE24Gq/EmZT+Gn6xFCxkMn6UcCVgsUvkSoETo5hKZhGuZmFrLWZgdhJiIuXFu4J0aCkJ9pQ3Inj1M//mSFtF+i45Xz+2YHIQndcT/5P7B1PLn47AYl0d1aqs0F62/sG6Smg/idfYbL4FF9ANFaa9uTQIDAQAB";
//私钥 base64加密的私钥
public final static String PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCxjhGEH1zP0gG3gTvcQBg2ra/QPNz/YZ9X/h+o055+oBMP/Ucd7PVi2GkTIDSoqoltpVNyN62Kgkm5vGAzp51N85V7mT9Nau3zKQYhCYzRgb5cQPUaYy/CNUj7fx8sHFsxYxoNFT/aoFysQx31VRvKHerb0chkSU2/u+YssGiLYqzAy4x/dR/9A6WmHY2he+kTbgar8SZlP4afrEULGQyfpRwJWCxS+RKgROjmEpmEa5mYWstZmB2EmIi5cW7gnRoKQn2lDciePUz/+ZIW0X6LjlfP7ZgchCd1xP/k/sHU8ufjsBiXR3VqqzQXrb+wbpKaD+J19hsvgUX0A0Vpr25NAgMBAAECggEAHb0+/9NE92YkdXkG7rgplhb3aLiZB4lxaAqfgOaZGHp1VutEWyXSYBEBYHu3djzCMgRL+siKn7V85chAkMZVWbYf5ojfincLjfvkE+qGlJzXppoWs6nDWRMVu1IqhXfmalpABcr2XAcaHpxLS0lLE0p5iQIVP37rr96oCfouOJIxpQW5wxmPbp4ei+fwgvJj+1lAhGFOLEFoYFDrG5cy5loYRnrtkSKUUvmMWdWfhQM/jfceBHUdp84JaxZ13p0HfSqO14JVab5CyoT19k6uRaHHrZNU04OJFCH5eswjFL4yB6zeTWM+SEQSAo75Kv0yjcWzgxQYZy9FvE/xW72zAQKBgQDt/SSjaG8wlWimSGtwKmiLJ801kHtLdsv0iA6Xy5CoxptCsNi6KUc8G+1rUINpMktxYFqjYEVwlXzCOWqw7Iy/GHi8x1vFmGW0LXtthCEyLx6MAUFV4ezCeS+VLQxrUBpBnmakf8XSpfM2Qaavb/q5Fh0mipSM5bktcyLaFdD/DQKBgQC+/hBOK1odBHP0GeOMAvvKXxZiMucRcar9ujTcLrX42/ojloFDkKfYfII7M8vW9hq7uOIAeivLxFIb+HAiADd8f+KFRyyjVTxzL7zjx5cTAZkpRYTb/ba/gU4V4VnpWpTQBOYOzPVLdtcMoWopska1va+tmu5cGAVo5vxRxk5cQQKBgQDTsbG9iVAer0h/YTvwcki8P5NSakrCPdH+mmggrnrnJoNFN3oRXlZ3KYBvTRcXpB1npIX7fc9G7jIjsl8tMb2g3mvHwK3pfj45n5uDN10v/qn1b8hmVKj99D5XO9MoQgCZDgXPnbiiP+uv/4X92GX17a3QcsTg8BdgTmJaC730oQKBgG/XROMRfdZqKiByHI57nMhXwDrGxgqv/kpQBO4+qC7PWf4G/zD6f19FIdnbLe119hehXy6aXBUZpF9erwMqD1Pna1VSZXBL1Hc7KChWU0A8+lxxqihMvPwNkxU6/jSo52WcyL84BBgpwipSR2GdVMzOBBbsF9Jz+o8AXBbiwjZBAoGALdubdaeHcnx4l5IxDVwkaZ4rU3l3Qhj2oEGWKVYtP9wVfSMSDTDCDcsb7V1qRwrCJAtBXPcoYg32+LtygoibN/Uyzgr3IrrgTl2oOmMKXnUM69T35wiWljQEURWV2kA1YlbLuHtWmFIeCwOCLqfHneXjm75JDWQcoSxhftBw54M=";
/**
* RSA加密
* @param data 要加密的数据
* @param publicKeyString base加密的公钥
* @return base64加密的RSA
* @throws Exception
*/
public static String encrypt(String data, String publicKeyString) throws Exception {
// 解析公钥
byte[] keyBytes = Base64.getDecoder().decode(publicKeyString);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
// 加密数据
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
/**
* RSA解密
* @param encryptedData 已加密数据
* @param privateKeyString base加密的私钥
* @return
* @throws Exception
*/
public static String decrypt(String encryptedData, String privateKeyString) throws Exception {
// 解析私钥
byte[] keyBytes = Base64.getDecoder().decode(privateKeyString);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// 解密数据
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
return new String(decryptedBytes);
}
/**
* 生成RSA公钥和私钥
* @return base64的公钥和私钥
* @throws Exception
*/
public static void generateKey() throws Exception {
try {
//RSA2048为2048,RSA4096为4096
int keySize = 2048;
// 1. 创建 KeyPairGenerator 对象
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
// 2. 初始化密钥大小(通常为 2048 位)
keyPairGenerator.initialize(keySize);
// 3. 生成密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 4. 获取公钥和私钥
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// 5. 转换为 Base64 编码的字符串(便于存储或传输)
String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());
// 6. 打印公钥和私钥
System.out.println("Public Key: " + publicKeyString);
System.out.println("Private Key: " + privateKeyString);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
//生成RSA密钥
generateKey();
String data = "Hello, World!";
String encryptedData = RsaEncryptionUtil.encrypt(data, PUBLIC_KEY);
String decryptedData = RsaEncryptionUtil.decrypt(encryptedData, PRIVATE_KEY);
System.out.println("Original Data: " + data);
System.out.println("Encrypted Data: " + encryptedData);
System.out.println("Decrypted Data: " + decryptedData);
}
}