Node.js Crypto:求每次加密结果不同、短文本加密长度<10的加解密方法
咱们先搞清楚原来的加密结果为啥这么长:
你的AES-256-CBC是块加密算法,块大小固定16字节——明文“1”只有1字节,会被自动填充到16字节,加密后还是16字节。再加上16字节的IV转成hex是32个字符,加密后的16字节转hex又是32个,再加上分隔符“XX”,32+2+32=66,这就难怪长度超标了。
要实现「每次加密结果不同」+「加密“1”后长度<10字符」,咱们可以换个思路,用流加密模式+更紧凑的编码方式,具体方案如下:
核心思路
- 改用AES-256-CTR模式:这是流加密,不需要填充明文,加密1字节的明文只会得到1字节的密文,直接缩短密文长度;
- 用base64代替hex编码:hex是每字节转2个字符,base64是每3字节转4个字符,空间利用率高很多;
- 使用4字节的随机nonce:既保证每次加密结果不同(随机nonce),又能控制总长度——4字节nonce+1字节密文=5字节,转base64后是7个字符,完全符合<10的要求。
实现代码
const crypto = require('crypto'); const ENCRYPTION_KEY = 'Must256bytes(32characters)secret'; // 必须是32字符(256位) const NONCE_LENGTH = 4; // 4字节随机nonce,低频率使用足够安全 function encrypt(text) { // 生成随机nonce const nonce = crypto.randomBytes(NONCE_LENGTH); // 创建CTR加密器 const cipher = crypto.createCipheriv('aes-256-ctr', Buffer.from(ENCRYPTION_KEY), nonce); // 加密明文(流加密无需填充,密文长度和明文一致) const encrypted = Buffer.concat([cipher.update(text.toString()), cipher.final()]); // 拼接nonce和密文,转base64返回 return Buffer.concat([nonce, encrypted]).toString('base64'); } function decrypt(text) { try { // 把base64转成Buffer const buffer = Buffer.from(text, 'base64'); // 拆分nonce(前4字节)和密文(剩余部分) const nonce = buffer.slice(0, NONCE_LENGTH); const encryptedText = buffer.slice(NONCE_LENGTH); // 创建CTR解密器 const decipher = crypto.createDecipheriv('aes-256-ctr', Buffer.from(ENCRYPTION_KEY), nonce); // 解密 const decrypted = Buffer.concat([decipher.update(encryptedText), decipher.final()]); return decrypted.toString(); } catch (err) { return 'NULL'; } }
安全性说明
- 4字节nonce的碰撞概率:对于同一个密钥,理论上每加密2^16次才会有1%的碰撞概率,如果你不是高频加密(比如每秒上万次),这个长度完全够用;
- 如果需要更高的安全性(比如高频场景),可以把
NONCE_LENGTH改成8,此时加密“1”的结果是11个字符,虽然超过了10,但安全性大幅提升——你可以根据自己的实际需求权衡。
内容的提问来源于stack exchange,提问作者Gopalakrishnan
相关产品推荐
相关产品推荐

