一、该问题的重现步骤是什么?
1. Flutter 数据加密后提交到接口解密后出现解密不完整,使用AesUtil.encryptToBase64(....)加密数据后用Flutter提交接口正常解密。
2. 测试了各种数据长度,框架加密后的数据长度是44、88成倍增长,Flutter用的组件加密后数据长度会出现24、44、64、88的,猜测是IV(偏移向量)或者补码方式的问题,没学过密码学,整不明白
3. Flutter用的组件:https://pub.dev/packages/encrypt,加密代码是AES部分示例代码
二、你期待的结果是什么?实际看到的又是什么?
怎么实现Flutter的AES加密对接呢?
三、你正在使用的是什么产品,什么版本?在什么操作系统上?
bladex 2.8.0 ,windows 10
四、请提供详细的错误堆栈信息,这很重要。
(1)正确的数据是 {"auPhone":"10008376857","auPassword":"123456"},加解密的KEY确认没有写错。
(2)密钥:eELB8HbcgKWkndH0g9qRcBMZG5zgPkMc
(3)框架加密:BLo1Q73NNBWMxpqBF66sKrI+PYfikhD5YU2O0A+tkBThF1W3TC3zKFCIg/34cnckkEBbjp3+ZsCKsz3zziWFFA==
(4)Flutter组件加密:0yCTQv/5A7cWbPTZjXFWZWaWLmkvkpHpeZlxnCBWixmvBpbXSQ3gWg1i4s6l8/TW
(5)如果数据再多一位,FIutter组件加密出来就是88位的,但是和框架加密的不一样...
五、若有更多详细信息,请在下面提供。
AesUtil 使用得是 AES/CBC/NoPadding,而 dart 中默认是 PKCS7Padding,
如果可以的话,将 java 的 AesUtil 的改成 AES/CBC/PKCS5Padding,详见:
Java Cipher package only supports PKCS#7 padding with AES/CBC/PKCS5Padding
.
This is not a good naming since PKCS#5 padding supports 8-byte block sizes as DES and PKCS#7 supports up to 255 bytes. For Java use this;
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
经过测试 java 端的代码需要调整,之前是为了兼容 的 PKCS7Padding。具体调整如下:
// 去掉的 PKCS7Padding 编码
public static byte[] encrypt(byte[] content, byte[] aesKey) {
return aes(content, aesKey, Cipher.ENCRYPT_MODE);
}
// 去掉的 PKCS7Padding 解码
public static byte[] decrypt(byte[] encrypted, byte[] aesKey) {
return aes(encrypted, aesKey, Cipher.DECRYPT_MODE);
}
// 改为 AES/CBC/PKCS5Padding
private static byte[] aes(byte[] encrypted, byte[] aesKey, int mode) {
Assert.isTrue(aesKey.length == 32, "IllegalAesKey, aesKey's length must be 32");
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
cipher.init(mode, keySpec, iv);
return cipher.doFinal(encrypted);
} catch (Exception e) {
throw Exceptions.unchecked(e);
}
}
dart 代码如下:
void main(List<String> arguments) {
// 明文数据和密钥
final plainText = '{"auPhone":"10008376857","auPassword":"123456"}';
final plainKey = 'eELB8HbcgKWkndH0g9qRcBMZG5zgPkMc';
// 初始化加密工具
final key = Key.fromUtf8(plainKey);
final iv = IV.fromUtf8(plainKey.substring(0, 16));
final encrypter = Encrypter(AES(key, mode: AESMode.cbc));
// dart 端加密
final encrypted = encrypter.encrypt(plainText, iv: iv);
print(encrypted.base64);
// 解密 java 端密文
final javaEncryptedText = 'BLo1Q73NNBWMxpqBF66sKrI+PYfikhD5YU2O0A+tkBRuiy1FkPxSnxUHw5rV2QZK';
final decrypted = encrypter.decrypt64(javaEncryptedText, iv: iv);
print(decrypted);
}
你把 dart 代码改成这样试试,这样输出的是:
BLo1Q73NNBWMxpqBF66sKrI+PYfikhD5YU2O0A+tkBRuiy1FkPxSnxUHw5rV2QZK
{"auPhone":"10008376857","auPassword":"123456"}
这样,加密出来 dart 和 java 是一样的,加解密是都没问题了
最新研究发现:java 中 AesUtil 只需要将 Pkcs7Encoder 中默认的 BLOCK_SIZE 改为 16 即可。
dart 中默认为 16,java 的 bcprov-jdk15on 中也是默认的 16
pc-dart/aes_fast.dart at e5cd4dd87d3a2b2f317b9a59b245978d92e965ee · bcgit/pc-dart (github.com)
"AesUtil 使用得是 AES/CBC/NoPadding,iv 取的是密钥的前 16 位"
这样测试过,IV写16个0和16个8也测试过,最好的情况就是解密出一半数据。
麻烦大佬们有时候看看,项目进度卡这了
那如果 把 Pkcs7Encoder 中默认的 BLOCK_SIZE 改为 16,vue前端框架需要改吗?看了crypto.js里面的代码,没发现设置长度的地方,aes.js代码压缩了看不明白。
目前已经按照第一种方式改写了工具类,加解密key从依赖包里面的bean获取,正常使用中,工具类有个好处是可以对单个参数加解密。
感谢老铁
扫一扫访问 Blade技术社区 移动端