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

C语言tiny-aes-c与Node.js CryptoJS AES-CTR兼容问题排查

Troubleshooting AES-CTR Compatibility Between tiny-aes-c and CryptoJS

Hey there, let's dig into why your encryption/decryption isn't matching up between your C code (using tiny-aes-c) and Node.js's CryptoJS. This almost always boils down to subtle differences in how each library handles low-level CTR mode details—let's break down the most likely culprits and fixes:

1. Counter Byte Order (Endianness)

This is the #1 cause of AES-CTR incompatibility between libraries. Tiny-aes-c's default CTR implementation often uses little-endian for incrementing the counter, while CryptoJS follows the NIST standard and uses big-endian.

For example:

  • Tiny-aes-c might increment the counter starting from the first byte (left to right)
  • CryptoJS increments starting from the last byte (right to left, big-endian)

Fix: Modify your tiny-aes-c code to use big-endian counter increments. Locate the part of the CTR encryption loop where the counter is updated, and change it to:

// Replace any little-endian counter increment with this big-endian version
for (int i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
    if (++ctr[i]) { // Increment byte; break if no carryover
        break;
    }
}

2. Verify IV and Key Consistency

Double-check that both sides are using identical IV and key bytes—no sneaky encoding differences allowed:

  • If your IV is a hex string, make sure your C code parses it into the exact same byte array as CryptoJS (use CryptoJS.enc.Hex.parse(ivHex) in Node.js)
  • For the 16-byte AES-128 key:
    • If it's a hex string: Parse it to bytes in both C and Node.js
    • If it's a plaintext string: Ensure both use the same encoding (e.g., UTF-8) to convert to bytes

3. Validate CryptoJS Decryption Setup

Make sure your Node.js code is correctly configured for CTR mode with no padding. A common mistake is passing the ciphertext directly as a string to CryptoJS.AES.decrypt—instead, explicitly pass the ciphertext bytes:

const CryptoJS = require("crypto-js");

// Replace with your actual key and IV (parsed to bytes)
const key = CryptoJS.enc.Hex.parse("your-16-byte-key-in-hex");
const iv = CryptoJS.enc.Hex.parse("your-fixed-iv-in-hex");

// Parse the Base64 ciphertext to bytes
const ciphertextBytes = CryptoJS.enc.Base64.parse("y6nVvIQRPA==");

const decrypted = CryptoJS.AES.decrypt(
    { ciphertext: ciphertextBytes },
    key,
    {
        mode: CryptoJS.mode.CTR,
        iv: iv,
        padding: CryptoJS.pad.NoPadding
    }
);

// Convert decrypted bytes to UTF-8 string
console.log(decrypted.toString(CryptoJS.enc.Utf8)); // Should output "message"

4. Check Encrypted Byte Order and Conversion

Verify that your C code's encrypted output bytes match what you're passing to CryptoJS:

  • Take the raw encrypted byte array from your C code, convert it to hex (in order, first byte to last), and confirm it's exactly cba9d5bc84113c
  • Double-check the Base64 conversion: The 7-byte array [0xcb, 0xa9, 0xd5, 0xbc, 0x84, 0x11, 0x3c] should indeed convert to y6nVvIQRPA==—use a trusted byte-to-base64 tool to confirm.

5. Validate tiny-aes-c's CTR Implementation

Ensure tiny-aes-c is using standard CTR logic:

  • The initial counter should be your full IV (16 bytes)
  • Each block, encrypt the current counter to get the keystream, then XOR it with the plaintext
  • Increment the entire counter (big-endian) after each block

If your tiny-aes-c code is splitting the IV into a nonce and a separate counter, that's non-standard—CryptoJS expects the full IV to be the initial counter.


Start with the counter endianness fix—this is almost certainly the issue. Once you adjust that, re-test your encryption and decryption, and verify each step's byte output matches between the two systems.

内容的提问来源于stack exchange,提问作者Shlomi Schwartz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:00:38