核心衝突點
| 環節 | Java 默認 | iOS (Security.framework) 默認 | 解決方案 |
| 密鑰編碼 | PKCS#8 (私鑰), X.509 (公鑰) | PKCS#1 (傳統) | Java 生成 PKCS#1,或 iOS 轉換 PKCS#8→PKCS#1 |
| Base64 | 標準 Base64 | 標準 Base64 | 雙方統一無換行、無空格 |
| 填充模式 | RSA/ECB/PKCS1Padding | SecPadding.PKCS1 (默認) | 雙方顯式指定 PKCS1Padding |
| 加密數據長度 | KeySize/8 - 11 bytes | 同 | 分段加密(長數據用 AES+RSA 混合) |
Java 端生成 PKCS#1 密鑰對
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.generateKeyPair();
// 私鑰轉 PKCS#1 (需 BouncyCastle)
PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded());
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(pkcs8.getEncoded());
RSAPrivateKey rsaPriv = RSAPrivateKey.getInstance(pki.parsePrivateKey());
byte[] pkcs1Priv = rsaPriv.getEncoded(); // PKCS#1 DER
String base64Priv = Base64.getEncoder().encodeToString(pkcs1Priv);
// 公鑰 X.509 → PKCS#1
SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded());
RSAPublicKey rsaPub = RSAPublicKey.getInstance(spki.parsePublicKey());
byte[] pkcs1Pub = rsaPub.getEncoded();
String base64Pub = Base64.getEncoder().encodeToString(pkcs1Pub);
iOS 端使用
// 加載公鑰加密
SecKeyRef publicKey = [self addPublicKey:base64Pub];
NSData *encrypted = [self rsaEncrypt:plainData key:publicKey padding:SecPadding.PKCS1];
// 加載私鑰解密
SecKeyRef privateKey = [self addPrivateKey:base64Priv];
NSData *decrypted = [self rsaDecrypt:encryptedData key:privateKey padding:SecPadding.PKCS1];
最佳實踐
- **長數據採用混合加密**:隨機生成 AES Key 加密數據,RSA 加密 AES Key 傳輸。
- 雙方約定密鑰格式文檔,包含 Base64 字符串示例。
- 集成測試階段互相提供測試向量(明文/密文/密鑰)驗證互通性。