Flutter PointyCastle生成RSA密钥传入Java解析报InvalidKeyException错误
问题根因排查
- 密钥格式不匹配:Flutter侧PointyCastle默认导出的是PKCS1格式的RSA公钥,而Java原生
X509EncodedKeySpec仅支持带X.509头的公钥格式,缺少算法标识头的PKCS1公钥无法被Java解析,直接触发你遇到的Error parsing public key报错。 - 传参逻辑错误:Flutter侧加密按钮的传参使用了共享变量
futureText,该变量会被点击其他按钮(比如获取私钥、签名)的结果覆盖,可能出现公钥传成私钥、私钥传成公钥的问题。 - Java侧逻辑漏洞:
MainActivity的方法处理逻辑没有分支返回,不管加密/解密是否执行成功,最后都会走到result.notImplemented(),导致Flutter侧收到未实现的错误。
解决方案
步骤1:修改Flutter侧密钥导出格式
将公钥导出格式从PKCS1改为X.509格式,私钥导出格式从PKCS1改为PKCS8格式,适配Java的密钥解析规则,示例工具方法如下:
import 'dart:convert'; import 'package:pointycastle/asn1.dart'; import 'package:pointycastle/api.dart' as crypto; import 'package:pointycastle/rsa.dart'; // 导出X.509格式公钥,适配Java X509EncodedKeySpec String encodePublicKeyToX509Pem(RSAPublicKey publicKey) { // 构造算法标识序列 final algorithmSeq = ASN1Sequence(); algorithmSeq.add(ASN1ObjectIdentifier.fromName('rsaEncryption')); algorithmSeq.add(ASN1Null()); // 构造RSA公钥参数序列 final pubKeySeq = ASN1Sequence(); pubKeySeq.add(ASN1Integer(publicKey.modulus)); pubKeySeq.add(ASN1Integer(publicKey.exponent)); final pubKeyBitStr = ASN1BitString(pubKeySeq.encode()); // 构造顶级序列 final topSeq = ASN1Sequence(); topSeq.add(algorithmSeq); topSeq.add(pubKeyBitStr); final pubKeyBase64 = base64.encode(topSeq.encode()); return '-----BEGIN PUBLIC KEY-----\n$pubKeyBase64\n-----END PUBLIC KEY-----'; } // 导出PKCS8格式私钥,适配Java PKCS8EncodedKeySpec String encodePrivateKeyToPKCS8Pem(RSAPrivateKey privateKey) { final version = ASN1Integer(BigInt.from(0)); final algorithmSeq = ASN1Sequence(); algorithmSeq.add(ASN1ObjectIdentifier.fromName('rsaEncryption')); algorithmSeq.add(ASN1Null()); final privateKeySeq = ASN1Sequence(); privateKeySeq.add(ASN1Integer(BigInt.from(0))); privateKeySeq.add(ASN1Integer(privateKey.modulus)); privateKeySeq.add(ASN1Integer(privateKey.publicExponent)); privateKeySeq.add(ASN1Integer(privateKey.privateExponent)); privateKeySeq.add(ASN1Integer(privateKey.p)); privateKeySeq.add(ASN1Integer(privateKey.q)); privateKeySeq.add(ASN1Integer(privateKey.privateExponent.remainder(privateKey.p - BigInt.one))); privateKeySeq.add(ASN1Integer(privateKey.privateExponent.remainder(privateKey.q - BigInt.one))); privateKeySeq.add(ASN1Integer(privateKey.q!.modInverse(privateKey.p!))); final privateKeyOctet = ASN1OctetString(privateKeySeq.encode()); final topSeq = ASN1Sequence(); topSeq.add(version); topSeq.add(algorithmSeq); topSeq.add(privateKeyOctet); final privKeyBase64 = base64.encode(topSeq.encode()); return '-----BEGIN PRIVATE KEY-----\n$privKeyBase64\n-----END PRIVATE KEY-----'; }
步骤2:修复Flutter侧传参逻辑
直接从已生成的keyPair中获取公私钥,不要复用被覆盖的futureText变量:
MaterialButton( color: Colors.red, child: Text("Encrypt"), onPressed: () async { // 直接从keyPair生成符合Java要求的密钥 final pubPem = encodePublicKeyToX509Pem(keyPair.publicKey as RSAPublicKey); final privPem = encodePrivateKeyToPKCS8Pem(keyPair.privateKey as RSAPrivateKey); futureText = methodC("encryptMsg", priv: RSA().removePemHeaderAndFooter(privPem), pub: RSA().removePemHeaderAndFooter(pubPem), msg: _controller.text); setState(() {}); }, ),
步骤3:修复Java侧逻辑漏洞
在每个方法分支处理完成后添加return,避免执行到result.notImplemented():
if(call.method.equals("encryptMsg")) { try { String encryptedString = Base64.getEncoder().encodeToString(rsa.encrypt(msg, pubKey)); result.success(encryptedString); } catch (Exception e) { result.error("ENCRYPT_ERROR", e.getMessage(), null); } return; // 新增返回,避免走到后续逻辑 } else if(call.method.equals("decryptMsg")) { try { byte[] encryptedBytes = Base64.getDecoder().decode(msg); String decryptedString = rsa.decrypt(encryptedBytes, privKey); result.success(decryptedString); } catch (Exception e) { result.error("DECRYPT_ERROR", e.getMessage(), null); } return; // 新增返回 } result.notImplemented();
内容的提问来源于stack exchange,提问作者Brightcode
相关产品推荐
相关产品推荐

