Dart实现AES-CCM遇问题:JS迁移后加密结果不一致及密钥报错
AES-CCM加密代码从SJCL迁移到Dart时结果不一致的解决方法
问题背景
我正在将一段基于Stanford JavaScript Crypto Library(SJCL)的AES-CCM加密代码迁移到Dart环境,使用Dart Cryptography 2.5.0库的AesGcm类,但始终无法得到和原JS代码一致的加密结果,还遇到了密钥长度错误的异常。
原JavaScript(SJCL)代码
result = sjcl.codec.hex.fromBits( sjcl.mode.ccm.encrypt( new sjcl.cipher.aes(sjcl.codec.hex.toBits("6dbe8f8c87d58e61c2ec29321f42e9ff")), // 密钥 sjcl.codec.hex.toBits("00626c742e332e3132397649356b744455415443"), // 明文 sjcl.codec.hex.toBits("101112131415161718191A1B"), // IV sjcl.codec.hex.toBits("6465764944"), // 附加数据(AAD) 32 // 标签长度(32比特) ) );
尝试的Dart代码及问题
第一次尝试(数据编码错误)
final encrypted = await AesGcm.with256bits().encrypt( secretKey: SecretKey(utf8.encode("6dbe8f8c87d58e61c2ec29321f42e9ff")), utf8.encode("00626c742e332e3132397649356b744455415443"), nonce: utf8.encode("101112131415161718191A1B"), aad: utf8.encode("6465764944"), ); final result = bytesToHex(Uint8List.fromList(encrypted.cipherText));
问题:所有参数用UTF-8编码,和SJCL将十六进制转字节数组的逻辑不符,导致结果不一致。
第二次尝试(算法和密钥长度不匹配)
final encrypted = await AesGcm.with256bits().encrypt( secretKey: SecretKey(hex.decode("6dbe8f8c87d58e61c2ec29321f42e9ff")), hex.decode("00626c742e332e3132397649356b744455415443"), nonce: hex.decode("101112131415161718191A1B"), aad: hex.decode("6465764944"), );
问题:抛出异常Invalid argument (secretKeyData): Expected 32 bytes, got 16 bytes——因为用了256位AES,但密钥解码后只有16字节(对应128位AES);同时原JS代码用的是CCM模式,Dart代码误用了GCM模式,两种算法不兼容。
解决方案
要解决问题,需保证算法匹配、参数处理逻辑一致、密钥长度对应,具体修正如下:
1. 匹配加密算法
原JS代码用的是AES-CCM,Dart中需使用AesCcm类而非AesGcm,GCM和CCM是不同的AEAD算法,无法互相兼容。
2. 正确处理密钥长度
原密钥十六进制字符串是32个字符,解码后为16字节,对应AES-128,需使用AesCcm.with128bits()。
3. 统一数据解码逻辑
所有参数(密钥、明文、IV、AAD)都需从十六进制字符串解码为字节数组,和SJCL的sjcl.codec.hex.toBits()行为一致。
4. 匹配标签长度
SJCL中指定的标签长度是32比特(4字节),Dart的AesCcm默认标签长度为16字节,需显式指定tagLength:4。
修正后的Dart代码
import 'package:cryptography/cryptography.dart'; import 'package:convert/convert.dart'; void main() async { // 从十六进制解码所有参数,和SJCL逻辑对齐 final secretKey = SecretKey(hex.decode("6dbe8f8c87d58e61c2ec29321f42e9ff")); final plaintext = hex.decode("00626c742e332e3132397649356b744455415443"); final nonce = hex.decode("101112131415161718191A1B"); final aad = hex.decode("6465764944"); // 使用AES-CCM,指定128位密钥和4字节标签长度 final encrypted = await AesCcm.with128bits(tagLength: 4).encrypt( plaintext, secretKey: secretKey, nonce: nonce, aad: aad, ); // 将密文转为十六进制字符串,和SJCL结果对比 final result = hex.encode(encrypted.cipherText); print(result); }
内容的提问来源于stack exchange,提问作者martin_elkjaer
相关产品推荐
相关产品推荐

