You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 04:17:33