
1. RSA算法基础从数学原理到非对称加密我第一次接触RSA算法时被它精妙的数学设计彻底震撼了。想象一下你有一把可以公开给全世界的锁公钥但只有你一个人持有钥匙私钥——这就是RSA的核心思想。1977年三位天才数学家Rivest、Shamir和Adleman基于大整数分解难题提出了这个改变密码学历史的算法。RSA的安全性建立在大数分解难题上给定两个大质数的乘积np*q要逆向分解出p和q极其困难。我做过一个实验用Python分解一个256位的n需要30分钟而1024位的n在我的笔记本上跑了三天都没结果。这就是为什么银行系统普遍采用2048位RSA密钥——以现有算力破解需要数万年。关键数学公式其实非常简单加密c ≡ m^e mod n解密m ≡ c^d mod n其中(e,n)是公钥(d,n)是私钥。我常把这个过程比作数学魔术——用模幂运算实现信息的安全变换。最近帮一个金融客户做安全审计时发现他们还在用1024位密钥我当即建议升级到2048位。因为根据NIST标准1024位RSA在2023年后已被认为不够安全。2. 密钥生成实战从OpenSSL到Java KeyPairGenerator生成RSA密钥对就像打造保险箱和钥匙。在实际项目中我通常推荐两种方式2.1 OpenSSL命令行生成# 生成PKCS#1格式私钥 openssl genrsa -out rsa_private.pem 2048 # 导出PKCS#8格式私钥Java更友好 openssl pkcs8 -topk8 -inform PEM -in rsa_private.pem -out rsa_private_pkcs8.pem -nocrypt # 提取公钥 openssl rsa -in rsa_private.pem -pubout -out rsa_public.pem上周帮一个团队排查问题发现他们直接使用PKCS#1私钥导致Java报错。记住Java的KeyFactory默认只认PKCS#8格式2.2 Java动态生成密钥KeyPairGenerator generator KeyPairGenerator.getInstance(RSA); generator.initialize(2048); // 推荐2048位 KeyPair pair generator.generateKeyPair(); // 获取Base64编码字符串 String publicKey Base64.getEncoder().encodeToString( pair.getPublic().getEncoded()); String privateKey Base64.getEncoder().encodeToString( pair.getPrivate().getEncoded());在Android开发中要注意低于Android 4.3的设备不支持2048位以上密钥。我曾遇到一个兼容性问题最终采用分段加密方案解决。3. 加解密实现PKCS1Padding与分段处理直接上代码前先说个真实案例某电商平台曾因未处理长文本加密导致订单数据截断损失惨重。RSA加密的明文长度受限必须分段处理public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception { // 转换公钥材料 X509EncodedKeySpec keySpec new X509EncodedKeySpec( Base64.getDecoder().decode(publicKey)); PublicKey key KeyFactory.getInstance(RSA) .generatePublic(keySpec); // 使用PKCS1PaddingAndroid兼容性好 Cipher cipher Cipher.getInstance(RSA/ECB/PKCS1Padding); cipher.init(Cipher.ENCRYPT_MODE, key); // 分段加密2048位密钥每次加密最多245字节 int blockSize 245; ByteArrayOutputStream out new ByteArrayOutputStream(); for(int i0; idata.length; iblockSize){ byte[] block Arrays.copyOfRange(data, i, Math.min(iblockSize, data.length)); out.write(cipher.doFinal(block)); } return out.toByteArray(); }解密时同样需要分段但块大小固定为256字节2048位。有个性能优化技巧对于Android低端设备可以改用RSA/ECB/OAEPWithSHA-256AndMGF1Padding虽然更安全但会损失约15%性能。4. 签名与验签SHA256WithRSA最佳实践数字签名就像电子指纹我常用这个比喻向产品经理解释其重要性。去年一个金融项目就因未验签导致API被篡改攻击。完整签名流程对数据计算哈希推荐SHA256用私钥加密哈希值将签名附加到原始数据Java实现示例// 签名 public static String sign(byte[] data, String privateKey) throws Exception { PKCS8EncodedKeySpec keySpec new PKCS8EncodedKeySpec( Base64.getDecoder().decode(privateKey)); PrivateKey key KeyFactory.getInstance(RSA) .generatePrivate(keySpec); Signature signature Signature.getInstance(SHA256WithRSA); signature.initSign(key); signature.update(data); return Base64.getEncoder().encodeToString(signature.sign()); } // 验签 public static boolean verify(byte[] data, String sign, String publicKey) throws Exception { X509EncodedKeySpec keySpec new X509EncodedKeySpec( Base64.getDecoder().decode(publicKey)); PublicKey key KeyFactory.getInstance(RSA) .generatePublic(keySpec); Signature signature Signature.getInstance(SHA256WithRSA); signature.initVerify(key); signature.update(data); return signature.verify(Base64.getDecoder().decode(sign)); }特别注意曾遇到客户使用SHA1WithRSA被安全扫描工具标记为漏洞。现在必须使用SHA256或更高强度算法。5. 完整工具类企业级RSAUtil实现下面是我在多个金融级项目中打磨过的工具类包含以下增强功能自动处理密钥格式PKCS#8智能分段加解密多哈希算法支持异常友好处理public class RSAUtil { private static final String ALGORITHM RSA; private static final int KEY_SIZE 2048; private static final int MAX_ENCRYPT_BLOCK 245; private static final int MAX_DECRYPT_BLOCK 256; public static KeyPair generateKeyPair() throws NoSuchAlgorithmException { KeyPairGenerator generator KeyPairGenerator.getInstance(ALGORITHM); generator.initialize(KEY_SIZE); return generator.generateKeyPair(); } public static String encrypt(String data, String publicKey) throws Exception { byte[] encrypted encryptByPublicKey(data.getBytes(StandardCharsets.UTF_8), publicKey); return Base64.getEncoder().encodeToString(encrypted); } public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception { PublicKey key getPublicKey(publicKey); Cipher cipher Cipher.getInstance(RSA/ECB/PKCS1Padding); cipher.init(Cipher.ENCRYPT_MODE, key); return processInBlocks(cipher, data, MAX_ENCRYPT_BLOCK); } public static String decrypt(String encryptedData, String privateKey) throws Exception { byte[] decoded Base64.getDecoder().decode(encryptedData); byte[] decrypted decryptByPrivateKey(decoded, privateKey); return new String(decrypted, StandardCharsets.UTF_8); } private static byte[] processInBlocks(Cipher cipher, byte[] data, int blockSize) throws Exception { try (ByteArrayOutputStream out new ByteArrayOutputStream()) { int offset 0; while (offset data.length) { int length Math.min(blockSize, data.length - offset); byte[] encryptedBlock cipher.doFinal(data, offset, length); out.write(encryptedBlock, 0, encryptedBlock.length); offset length; } return out.toByteArray(); } } // 其他方法同上文实现... }使用示例// 客户端加密 String encrypted RSAUtil.encrypt(敏感数据, publicKey); // 服务端解密 String original RSAUtil.decrypt(encrypted, privateKey); // 签名验证 boolean isValid RSAUtil.verify(data.getBytes(), signature, publicKey);6. 性能优化与安全实践在千万级用户系统中RSA性能至关重要。我的三个实战经验缓存密钥对象避免重复解析密钥// 使用ConcurrentHashMap缓存已解析的密钥 private static final MapString, PublicKey PUBLIC_KEY_CACHE new ConcurrentHashMap(); public static PublicKey getCachedPublicKey(String key) throws Exception { return PUBLIC_KEY_CACHE.computeIfAbsent(key, k - { try { return getPublicKey(k); } catch (Exception e) { throw new RuntimeException(e); } }); }混合加密方案用RSA加密AES密钥// 生成随机AES密钥 Key aesKey generateAESKey(); // 用RSA加密AES密钥 byte[] encryptedAesKey rsaEncrypt(aesKey.getEncoded()); // 实际数据用AES加密 byte[] encryptedData aesEncrypt(data, aesKey);密钥轮换策略设置密钥有效期并自动更新安全注意事项私钥必须存储在HSM或KeyStore中传输层必须使用TLS定期更换密钥建议每90天监控异常解密请求最近帮一个区块链项目设计安全方案时我们最终采用RSA-3072 AES-256-GCM的组合既保证性能又满足量子计算威胁下的安全要求。