package com.xiaopeng.common.core.utils; import javax.crypto.Cipher; import java.nio.charset.StandardCharsets; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; /** * RSA 加密解密工具类 *

* 支持功能: * 1. 公钥加密、私钥解密(OAEP 填充模式) * 2. 私钥签名、公钥验签 * 3. 密钥对生成 * 4. Base64 编码/解码 *

* 注意事项: * - RSA 使用 OAEP 填充模式,更安全,默认密钥长度 2048 位,最大加密数据长度为 190 字节 * - 超长数据需要分段加密或使用对称加密(如 AES) * - OAEP 填充使用 SHA-256 和 MGF1 算法 * - 使用 ThreadLocal 缓存 Cipher 实例,提升高并发性能 */ public class RSAUtil { private static final String RSA_ALGORITHM = "RSA"; private static final String SIGNATURE_ALGORITHM = "SHA256withRSA"; private static final String TRANSFORMATION = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; private static final int KEY_SIZE = 2048; /** * 缓存 Cipher 实例,提高高并发性能 * Cipher 不是线程安全的,每个线程使用自己的实例 */ private static final ThreadLocal ENCRYPT_CIPHER = ThreadLocal.withInitial(() -> { try { return Cipher.getInstance(TRANSFORMATION); } catch (Exception e) { throw new RuntimeException("初始化加密 Cipher 失败", e); } }); private static final ThreadLocal DECRYPT_CIPHER = ThreadLocal.withInitial(() -> { try { return Cipher.getInstance(TRANSFORMATION); } catch (Exception e) { throw new RuntimeException("初始化解密 Cipher 失败", e); } }); private static final ThreadLocal SIGNATURE = ThreadLocal.withInitial(() -> { try { return java.security.Signature.getInstance(SIGNATURE_ALGORITHM); } catch (Exception e) { throw new RuntimeException("初始化 Signature 失败", e); } }); /** * 生成 RSA 密钥对 * * @return 密钥对 */ public static KeyPair generateKeyPair() { try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM); keyPairGenerator.initialize(KEY_SIZE); return keyPairGenerator.generateKeyPair(); } catch (Exception e) { throw new RuntimeException("生成密钥对失败", e); } } /** * 获取公钥 Base64 字符串 * * @param keyPair 密钥对 * @return Base64 编码的公钥 */ public static String getPublicKey(KeyPair keyPair) { return Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()); } /** * 获取私钥 Base64 字符串 * * @param keyPair 密钥对 * @return Base64 编码的私钥 */ public static String getPrivateKey(KeyPair keyPair) { return Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()); } /** * 使用公钥加密 * * @param data 待加密数据 * @param publicKey Base64 编码的公钥 * @return Base64 编码的密文 */ public static String encryptByPublicKey(String data, String publicKey) { try { byte[] keyBytes = Base64.getDecoder().decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PublicKey key = keyFactory.generatePublic(keySpec); Cipher cipher = ENCRYPT_CIPHER.get(); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { throw new RuntimeException("公钥加密失败", e); } } /** * 使用私钥解密 * * @param data Base64 编码的密文 * @param privateKey Base64 编码的私钥 * @return 明文 */ public static String decryptByPrivateKey(String data, String privateKey) { try { byte[] keyBytes = Base64.getDecoder().decode(privateKey); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PrivateKey key = keyFactory.generatePrivate(keySpec); Cipher cipher = DECRYPT_CIPHER.get(); cipher.init(Cipher.DECRYPT_MODE, key); byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(data)); return new String(decrypted, StandardCharsets.UTF_8); } catch (Exception e) { throw new RuntimeException("私钥解密失败", e); } } /** * 使用私钥加密 * * @param data 待加密数据 * @param privateKey Base64 编码的私钥 * @return Base64 编码的密文 */ public static String encryptByPrivateKey(String data, String privateKey) { try { byte[] keyBytes = Base64.getDecoder().decode(privateKey); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PrivateKey key = keyFactory.generatePrivate(keySpec); Cipher cipher = ENCRYPT_CIPHER.get(); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { throw new RuntimeException("私钥加密失败", e); } } /** * 使用公钥解密 * * @param data Base64 编码的密文 * @param publicKey Base64 编码的公钥 * @return 明文 */ public static String decryptByPublicKey(String data, String publicKey) { try { byte[] keyBytes = Base64.getDecoder().decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PublicKey key = keyFactory.generatePublic(keySpec); Cipher cipher = DECRYPT_CIPHER.get(); cipher.init(Cipher.DECRYPT_MODE, key); byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(data)); return new String(decrypted, StandardCharsets.UTF_8); } catch (Exception e) { throw new RuntimeException("公钥解密失败", e); } } /** * 使用私钥签名(SHA256withRSA) * * @param data 待签名的数据 * @param privateKey Base64 编码的私钥 * @return Base64 编码的签名 */ public static String sign(String data, String privateKey) { try { byte[] keyBytes = Base64.getDecoder().decode(privateKey); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PrivateKey key = keyFactory.generatePrivate(keySpec); java.security.Signature signature = SIGNATURE.get(); signature.initSign(key); signature.update(data.getBytes(StandardCharsets.UTF_8)); byte[] signBytes = signature.sign(); return Base64.getEncoder().encodeToString(signBytes); } catch (Exception e) { throw new RuntimeException("签名失败", e); } } /** * 使用公钥验签(SHA256withRSA) * * @param data 原始数据 * @param publicKey Base64 编码的公钥 * @param sign Base64 编码的签名 * @return 验签结果 */ public static boolean verify(String data, String publicKey, String sign) { try { byte[] keyBytes = Base64.getDecoder().decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PublicKey key = keyFactory.generatePublic(keySpec); java.security.Signature signature = SIGNATURE.get(); signature.initVerify(key); signature.update(data.getBytes(StandardCharsets.UTF_8)); return signature.verify(Base64.getDecoder().decode(sign)); } catch (Exception e) { throw new RuntimeException("验签失败", e); } } /** * 分段加密(用于超长数据) *

* 注意:实际项目中,超长数据建议使用 AES + RSA 混合加密 * * @param data 待加密数据 * @param publicKey Base64 编码的公钥 * @return Base64 编码的密文 */ public static String encryptByPublicKeySegment(String data, String publicKey) { try { byte[] keyBytes = Base64.getDecoder().decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PublicKey key = keyFactory.generatePublic(keySpec); Cipher cipher = ENCRYPT_CIPHER.get(); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8); int maxLength = 190; // 2048 位密钥 OAEP 模式最大加密长度 byte[][] segments = splitArray(dataBytes, maxLength); StringBuilder result = new StringBuilder(); for (int i = 0; i < segments.length; i++) { byte[] encrypted = cipher.doFinal(segments[i]); if (i > 0) { result.append(","); } result.append(Base64.getEncoder().encodeToString(encrypted)); } return result.toString(); } catch (Exception e) { throw new RuntimeException("分段加密失败", e); } } /** * 分段解密 * * @param data 加密的数据(逗号分隔的 Base64 字符串) * @param privateKey Base64 编码的私钥 * @return 明文 */ public static String decryptByPrivateKeySegment(String data, String privateKey) { try { byte[] keyBytes = Base64.getDecoder().decode(privateKey); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PrivateKey key = keyFactory.generatePrivate(keySpec); Cipher cipher = DECRYPT_CIPHER.get(); cipher.init(Cipher.DECRYPT_MODE, key); String[] segments = data.split(","); StringBuilder result = new StringBuilder(); for (String segment : segments) { byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(segment)); result.append(new String(decrypted, StandardCharsets.UTF_8)); } return result.toString(); } catch (Exception e) { throw new RuntimeException("分段解密失败", e); } } /** * 将字节数组分段 */ private static byte[][] splitArray(byte[] array, int chunkSize) { int chunks = (array.length + chunkSize - 1) / chunkSize; byte[][] result = new byte[chunks][]; for (int i = 0; i < chunks; i++) { int start = i * chunkSize; int end = Math.min(start + chunkSize, array.length); result[i] = new byte[end - start]; System.arraycopy(array, start, result[i], 0, end - start); } return result; } /** * 测试示例 */ public static void main(String[] args) { // 1. 生成密钥对 // KeyPair keyPair = generateKeyPair(); // String publicKey = getPublicKey(keyPair); // String privateKey = getPrivateKey(keyPair); // // System.out.println("公钥: " + publicKey); // System.out.println("私钥: " + privateKey); // System.out.println(); // // // 2. 测试加密解密 // String originalData = "Hello RSA 加密测试!123456789"; // System.out.println("原始数据: " + originalData); // // // 公钥加密,私钥解密 // String encrypted = encryptByPublicKey(originalData, publicKey); // System.out.println("加密后: " + encrypted); // // String decrypted = decryptByPrivateKey(encrypted, privateKey); // System.out.println("解密后: " + decrypted); // System.out.println(); // // // 3. 测试签名验签 // String signature = sign(originalData, privateKey); // System.out.println("签名: " + signature); // // boolean verified = verify(originalData, publicKey, signature); // System.out.println("验签结果: " + verified); // // // 4. 测试私钥加密,公钥解密 // String encryptedByPrivate = encryptByPrivateKey(originalData, privateKey); // System.out.println("私钥加密: " + encryptedByPrivate); // // String decryptedByPublic = decryptByPublicKey(encryptedByPrivate, publicKey); // System.out.println("公钥解密: " + decryptedByPublic); // // // 5. 测试分段加密(长数据) // String longData = "这是一段很长的数据,需要分段加密。".repeat(10); // String encryptedSegment = encryptByPublicKeySegment(longData, publicKey); // System.out.println("分段加密长度: " + encryptedSegment.length()); // // String decryptedSegment = decryptByPrivateKeySegment(encryptedSegment, privateKey); // System.out.println("分段解密结果: " + (longData.equals(decryptedSegment) ? "成功" : "失败")); } }