一、该问题的重现步骤是什么?
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(Listarguments) { // 明文数据和密钥 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技术社区 移动端