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

如何用Node.js Crypto的AES-256-CBC加密超块大小文本?

问题分析与解决方案

原代码错误原因

你的代码出现乱码的核心问题是Buffer与字符串直接拼接导致的编码错误:

  • cipher.update(message)返回Buffer类型,直接和cipher.final("hex")的字符串相加时,Buffer会被强制转为UTF-8字符串,但加密后的二进制数据并非合法UTF-8序列,因此出现乱码。
  • 这个问题和文本长度无关,只是短文本恰好没触发明显的编码错误而已。

修复方案(无需分片)

如果不需要强制分片,只需修正加密时的Buffer处理逻辑即可:

const AES_ALGORITHM = 'aes-256-cbc'; // 原代码缺失该常量,需补充

var {
  randomBytes,
  createCipheriv,
  createDecipheriv,
} = require("crypto");
var config = require("../../config");
var { hkdfKeygen } = require("./hashing");

function encryptAes(message, key) {
  try {
    const encryption_key_buffer = hkdfKeygen(
      key,
      config.hkdfSalt,
      config.hkdfAdditionalInfo,
      32
    );
    const initialization_vector_buffer = randomBytes(16);
    const cipher = createCipheriv(
      AES_ALGORITHM,
      encryption_key_buffer,
      initialization_vector_buffer
    );

    // 用Buffer.concat合并update和final的结果,再统一转hex
    const encryptedBuffer = Buffer.concat([cipher.update(message, 'utf8'), cipher.final()]);
    const encrypted = encryptedBuffer.toString('hex');

    return {
      encrypted,
      iv: initialization_vector_buffer.toString("hex"),
    };
  } catch (err) {
    throw new Error("Error encrypting in AES -> " + err.message);
  }
}

function decryptAes(ciphertext, key, iv) {
  try {
    const encryption_key_buffer = hkdfKeygen(
      key,
      config.hkdfSalt,
      config.hkdfAdditionalInfo,
      32
    );
    const initialization_vector_buffer = Buffer.from(iv, "hex");

    const decipher = createDecipheriv(
      AES_ALGORITHM,
      encryption_key_buffer,
      initialization_vector_buffer
    );

    // 解密时统一处理,避免编码问题
    const decryptedBuffer = Buffer.concat([decipher.update(ciphertext, 'hex'), decipher.final()]);
    return decryptedBuffer.toString('utf8');
  } catch (err) {
    throw new Error("Error decrypting in AES -> " + err.message);
  }
}

分片加密实现(按需求)

如果确实需要分片加密(比如处理超大文件或特定业务场景),需注意:

  • AES-CBC的每个分片需要使用链式IV(前一个分片的密文最后一块作为下一个分片的IV),否则会失去CBC模式的安全性。
  • 分片大小按你要求设为2*BLOCK_SIZE=32字节(BLOCK_SIZE=16字节)。

以下是分片加密解密的完整实现:

const AES_ALGORITHM = 'aes-256-cbc';
const BLOCK_SIZE = 16;
const CHUNK_SIZE = 2 * BLOCK_SIZE; // 32字节

var {
  randomBytes,
  createCipheriv,
  createDecipheriv,
} = require("crypto");
var config = require("../../config");
var { hkdfKeygen } = require("./hashing");

// 分片加密
function encryptAesChunked(message, key) {
  try {
    const encryption_key_buffer = hkdfKeygen(
      key,
      config.hkdfSalt,
      config.hkdfAdditionalInfo,
      32
    );
    const originalMessageBuffer = Buffer.from(message, 'utf8');
    const chunks = [];
    let currentIv = randomBytes(BLOCK_SIZE); // 初始IV
    const ivs = [currentIv.toString('hex')]; // 保存所有IV(初始IV+链式IV)

    // 切割文本为分片
    for (let i = 0; i < originalMessageBuffer.length; i += CHUNK_SIZE) {
      const chunk = originalMessageBuffer.slice(i, i + CHUNK_SIZE);
      const cipher = createCipheriv(AES_ALGORITHM, encryption_key_buffer, currentIv);
      const encryptedChunk = Buffer.concat([cipher.update(chunk), cipher.final()]);
      chunks.push(encryptedChunk.toString('hex'));
      // 更新IV为当前密文的最后16字节(链式IV)
      currentIv = encryptedChunk.slice(-BLOCK_SIZE);
      ivs.push(currentIv.toString('hex'));
    }

    return {
      encryptedChunks: chunks,
      ivs: ivs, // 需要保存所有IV用于解密
    };
  } catch (err) {
    throw new Error("Error encrypting in AES (chunked) -> " + err.message);
  }
}

// 分片解密
function decryptAesChunked(encryptedChunks, key, ivs) {
  try {
    const encryption_key_buffer = hkdfKeygen(
      key,
      config.hkdfSalt,
      config.hkdfAdditionalInfo,
      32
    );
    const decryptedChunks = [];
    let currentIv = Buffer.from(ivs[0], 'hex');

    for (let i = 0; i < encryptedChunks.length; i++) {
      const encryptedChunkBuffer = Buffer.from(encryptedChunks[i], 'hex');
      const decipher = createDecipheriv(AES_ALGORITHM, encryption_key_buffer, currentIv);
      const decryptedChunk = Buffer.concat([decipher.update(encryptedChunkBuffer), decipher.final()]);
      decryptedChunks.push(decryptedChunk);
      // 更新IV为当前密文的最后16字节
      currentIv = encryptedChunkBuffer.slice(-BLOCK_SIZE);
    }

    return Buffer.concat(decryptedChunks).toString('utf8');
  } catch (err) {
    throw new Error("Error decrypting in AES (chunked) -> " + err.message);
  }
}

// 使用示例
const testMessage = " This is is a kind of text that my implementaion will spit out partial gibberish for ";
const testKey = "your-secret-key"; // 替换为实际密钥

// 分片加密
const encryptedResult = encryptAesChunked(testMessage, testKey);
console.log("Encrypted chunks:", encryptedResult.encryptedChunks);

// 分片解密
const decryptedMessage = decryptAesChunked(encryptedResult.encryptedChunks, testKey, encryptedResult.ivs);
console.log("Decrypted message:", decryptedMessage);

注意事项

  1. 原代码中缺失AES_ALGORITHM常量,必须补充为'aes-256-cbc'才能正常运行。
  2. 分片加密时必须保存所有IV(初始IV+每个分片的链式IV),否则无法正确解密。
  3. 无论是否分片,都要确保密钥的安全性,避免硬编码密钥。

内容的提问来源于stack exchange,提问作者Timileyin Pelumi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:24:29