Dart中RSA加密转Base64后跨场景解密失败问题
Dart RSA加密后Base64存储解密失败问题解决
问题核心
在Dart中执行RSA加密,将密文转为Base64字符串存储后,取出解密时触发Invalid argument(s): decoding error错误。同一函数内连续执行加密→Base64编码→解码→解密流程完全正常,但使用数据库取出的Base64串或复制打印输出的Base64串解密时,即便解码后的字节数组与原密文字节数组一致,仍解密失败。
复现代码与错误信息
示例代码
import 'dart:convert'; import 'package:pointycastle/asymmetric/rsa.dart'; import 'package:pointycastle/key_generators/rsa_key_generator.dart'; import 'package:pointycastle/api.dart'; void main() async { // 生成RSA密钥对 final keyGenerator = RSAKeyGenerator(); final params = RSAKeyGeneratorParameters(BigInt.from(65537), 2048, 12); keyGenerator.init(ParametersWithRandom(params, SecureRandom())); final keyPair = keyGenerator.generateKeyPair(); final publicKey = keyPair.publicKey as RSAPublicKey; final privateKey = keyPair.privateKey as RSAPrivateKey; // 测试1:同函数内加密解码解密(正常) final plainText = 'test data'; final encryptor = RSAEngine()..init(true, PublicKeyParameter<RSAPublicKey>(publicKey)); final encrypted = encryptor.process(utf8.encode(plainText)); final base64Str = base64.encode(encrypted); print('Base64密文:$base64Str'); final decodedBytes = base64.decode(base64Str); final decryptor = RSAEngine()..init(false, PrivateKeyParameter<RSAPrivateKey>(privateKey)); final decrypted1 = utf8.decode(decryptor.process(decodedBytes)); print('同函数解密结果:$decrypted1'); // 输出test data // 测试2:使用打印的Base64串解密(失败) final copiedBase64 = '这里替换成打印的base64Str内容'; final copiedDecoded = base64.decode(copiedBase64); print('解码字节数组是否一致:${encrypted.toString() == copiedDecoded.toString()}'); // 输出true try { final decrypted2 = utf8.decode(decryptor.process(copiedDecoded)); print('复制串解密结果:$decrypted2'); } catch (e) { print('解密错误:$e'); // 输出Invalid argument(s): decoding error } }
错误栈
Invalid argument(s): decoding error #0 _RSAImpl.decrypt (package:pointycastle/impl/asymmetric/rsa.dart:254:7) #1 RSAEngine.process (package:pointycastle/asymmetric/rsa.dart:107:25) #2 main (file:///path/to/your/file.dart:28:46)
可能原因与解决方案
1. Base64字符串存在隐藏字符或格式问题
从数据库取出或复制打印的Base64串可能包含不可见字符(如换行符、制表符、前后空格)或多余符号(如打印时的引号)。即使肉眼看起来一致,这些字符会导致解码后的字节数组看似匹配,但实际解密时因格式不符报错。
解决方法:
- 对取出的Base64串进行清理:
final cleanedBase64 = copiedBase64.trim().replaceAll(RegExp(r'\s'), '').replaceAll('"', ''); - 对比原Base64串与取出串的字符长度,确保无截断或额外字符。
2. Base64编码/解码标准不匹配
Dart中dart:convert提供了base64和base64Url两种编码标准,若加密时用base64.encode,解密时误用base64Url.decode(或反之),会导致解码后的字节数组异常。
解决方法:
- 统一使用同一套Base64工具方法:加密用
base64.encode(encryptedBytes),解密用base64.decode(base64Str)。
3. RSA填充模式不一致
RSA加密和解密必须使用相同的填充模式(如PKCS1、OAEP)。若加密时默认使用了某填充模式,解密时未指定或指定错误,会导致解密失败。
解决方法:
- 显式指定填充模式,确保加密解密一致:
// 加密时指定PKCS1填充 final encryptor = PKCS1Encoding(RSAEngine()) ..init(true, PublicKeyParameter<RSAPublicKey>(publicKey)); final encrypted = encryptor.process(utf8.encode(plainText)); // 解密时使用相同填充 final decryptor = PKCS1Encoding(RSAEngine()) ..init(false, PrivateKeyParameter<RSAPrivateKey>(privateKey)); final decrypted = decryptor.process(decodedBytes);
4. 数据库存储时的编码转换问题
部分数据库会自动对字符串进行编码转换(如将UTF-8转成其他编码),导致Base64串的字节结构被修改。
解决方法:
- 确保数据库存储Base64串时使用
UTF-8编码,且以纯文本形式存储,避免自动转码。
验证步骤
- 打印原Base64串和取出串的字符长度,确认一致。
- 将两个字符串转为字节数组后逐字节对比,确认完全匹配。
- 对取出的Base64串执行清理操作后再尝试解密。
内容的提问来源于stack exchange,提问作者Niek van Dommelen
相关产品推荐
相关产品推荐

