323 字
1 分钟
crypto-js加密
Crypto-JS 基础 API 速查
安装
npm install crypto-jsconst CryptoJS = require('crypto-js');1. 字符串 ↔ WordArray
CryptoJS 内部不直接操作字符串,所有加解密都在 WordArray(32-bit word 数组)上进行。
// 字符串 → WordArray(UTF-8 编码)const wa = CryptoJS.enc.Utf8.parse('Hello');
// WordArray → 字符串const str = wa.toString(CryptoJS.enc.Utf8); // 'Hello'
// WordArray → 十六进制字符串wa.toString(); // '48656c6c6f'(默认 hex)
// 十六进制字符串 → WordArrayCryptoJS.enc.Hex.parse('48656c6c6f');常见编码格式:
| 编码 | 读 | 写 |
|---|---|---|
| UTF-8 | CryptoJS.enc.Utf8 | CryptoJS.enc.Utf8 |
| Hex | CryptoJS.enc.Hex | CryptoJS.enc.Hex |
| Base64 | CryptoJS.enc.Base64 | CryptoJS.enc.Base64 |
| Latin1 | CryptoJS.enc.Latin1 | CryptoJS.enc.Latin1 |
2. AES 加密/解密
基本用法(字符串输入,自动 PKCS7 填充)
const ciphertext = CryptoJS.AES.encrypt('明文', '密码').toString();// ciphertext 是 Base64 字符串
const plaintext = CryptoJS.AES.decrypt(ciphertext, '密码').toString(CryptoJS.enc.Utf8);// plaintext 是解密后的字符串高级用法(WordArray 输入,指定模式和填充)
const key = CryptoJS.enc.Utf8.parse('1234567890abcdef'); // 16 字节 = AES-128const iv = CryptoJS.enc.Utf8.parse('abcdefghijklmnop'); // 16 字节 IV
const encrypted = CryptoJS.AES.encrypt(message, key, { iv: iv, mode: CryptoJS.mode.CBC, // CBC / ECB / CTR / CFB / OFB padding: CryptoJS.pad.Pkcs7, // Pkcs7 / NoPadding / ZeroPadding});
// encrypted 是 CipherParams 对象encrypted.toString(); // Base64 字符串encrypted.ciphertext.toString(); // Hex 密文(不含 IV)encrypted.ciphertext.toString(CryptoJS.enc.Base64); // Base64 密文(不含 IV)
// 解密const decrypted = CryptoJS.AES.decrypt(encrypted, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7,});const plain = decrypted.toString(CryptoJS.enc.Utf8);⚠️ 常见坑
// ❌ 错误:传普通对象代替 WordArrayCryptoJS.AES.encrypt({ words: wa.words, sigBytes: wa.sigBytes }, key, opts)// CryptoJS 不认这个对象,内部当字符串处理 → 结果错误
// ✅ 正确:直接传 WordArrayCryptoJS.AES.encrypt(wa, key, opts)
// ❌ 错误:CipherParams.toString(CryptoJS.enc.Base64)encrypted.toString(CryptoJS.enc.Base64) // 报错: wordArray.clamp is not a function
// ✅ 正确:用 enc.Base64.stringify()CryptoJS.enc.Base64.stringify(encrypted.ciphertext)3. AES 四种模式对比
| 模式 | 需要 IV | 并行 | 特点 |
|---|---|---|---|
| ECB | ❌ | ✅ | 相同明文→相同密文,不安全 |
| CBC | ✅ | ❌ | 最常用,需要 IV |
| CTR | ✅ | ✅ | 计数器模式 |
| CFB | ✅ | ❌ | 流密码模式 |
// ECB(无 IV)CryptoJS.AES.encrypt(data, key, { mode: CryptoJS.mode.ECB });
// CBC(需要 IV)CryptoJS.AES.encrypt(data, key, { iv: iv, mode: CryptoJS.mode.CBC });4. 填充模式
| 填充 | 说明 |
|---|---|
Pkcs7 | 默认,按块大小填充(AES=16字节) |
NoPadding | 不填充,明文必须是块大小的整数倍 |
ZeroPadding | 用 0x00 填充到块大小整数倍 |
Iso97971 | 0x80 + 0x00 填充 |
// 数据正好是 16 字节时用 NoPaddingCryptoJS.AES.encrypt(data16, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding});5. MD5 / SHA 系列
// MD5CryptoJS.MD5('hello').toString(); // '5d41402abc4b2a76b9719d911017c592'
// SHA-256CryptoJS.SHA256('hello').toString();
// SHA-512CryptoJS.SHA512('hello').toString();
// 也可以传 WordArrayCryptoJS.MD5(CryptoJS.enc.Utf8.parse('hello')).toString();6. HMAC
// HMAC-SHA256CryptoJS.HmacSHA256('message', 'secret-key').toString();
// HMAC-MD5CryptoJS.HmacMD5('message', 'secret-key').toString();
// 用 WordArray 做 keyconst key = CryptoJS.enc.Utf8.parse('my-key');CryptoJS.HmacSHA256(CryptoJS.enc.Utf8.parse('message'), key).toString();7. TripleDES
const key = CryptoJS.enc.Utf8.parse('123456789012345678901234'); // 24 字节const encrypted = CryptoJS.TripleDES.encrypt('hello', key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7,});8. 实用工具
// Hex ↔ WordArrayconst hex = '48656c6c6f';const wa = CryptoJS.enc.Hex.parse(hex);wa.toString(CryptoJS.enc.Utf8); // 'Hello'
// Base64 ↔ WordArrayconst b64 = 'SGVsbG8=';const wa2 = CryptoJS.enc.Base64.parse(b64);wa2.toString(CryptoJS.enc.Utf8); // 'Hello'
// 字节数组 ↔ WordArrayconst bytes = [72, 101, 108, 108, 111];const wa3 = CryptoJS.lib.WordArray.create(bytes);wa3.toString(CryptoJS.enc.Utf8); // 'Hello'9. 完整链式加密示例(AES 双层 + XOR)
const CryptoJS = require('crypto-js');
function xorWords(str, mask) { const words = []; for (let i = 0; i < str.length; i += 4) { let w = 0; for (let j = 0; j < 4 && i + j < str.length; j++) { w = (w << 8) | (str.charCodeAt(i + j) ^ mask); } words.push(w); } return CryptoJS.lib.WordArray.create(words, str.length);}
const keyA = CryptoJS.enc.Utf8.parse('PIVOT_KEY_A_0001');const keyB = CryptoJS.enc.Utf8.parse('PIVOT_KEY_B_0001');
// 正向:XOR → AES(keyB) → AES(keyA) → Base64function encrypt(plain) { const xored = xorWords(plain, 0x5A); const enc1 = CryptoJS.AES.encrypt(xored, keyB, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }).ciphertext; const enc2 = CryptoJS.AES.encrypt(enc1, keyA, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }).ciphertext; return CryptoJS.enc.Base64.stringify(enc2);}
// 反向:Base64 → AES(keyA) 解密 → AES(keyB) 解密 → XORfunction decrypt(license) { const raw = CryptoJS.enc.Base64.parse(license); const dec1 = CryptoJS.AES.decrypt({ ciphertext: raw }, keyA, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); const dec2 = CryptoJS.AES.decrypt({ ciphertext: dec1 }, keyB, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); const xored = dec2.toString(CryptoJS.enc.Latin1); let result = ''; for (let i = 0; i < xored.length; i++) { result += String.fromCharCode(xored.charCodeAt(i) ^ 0x5A); } return result;}
// 测试const lic = encrypt('GRANTED_2026_OK!');console.log('加密:', lic);console.log('解密:', decrypt(lic));10. CipherParams 对象属性
const encrypted = CryptoJS.AES.encrypt('hello', 'key');
encrypted.toString(); // Base64 密文(含 IV + 密文)encrypted.ciphertext; // WordArray(仅密文)encrypted.ciphertext.toString(); // Hex 密文encrypted.iv; // WordArray(IV,CBC 模式)encrypted.key; // WordArray(密钥)encrypted.salt; // WordArray(盐值)encrypted.algorithm; // 算法对象encrypted.mode; // 模式encrypted.padding; // 填充encrypted.blockSize; // 块大小(字节)encrypted(formatter); // 自定义输出格式注意事项
- AES-128 需要 16 字节密钥,AES-256 需要 32 字节密钥
- ECB 模式不需要 IV,其他模式需要
- NoPadding 时明文必须是 16 字节整数倍
- 不要用
{words, sigBytes}代替 WordArray 对象 - CipherParams.toString() 默认输出 Base64,要输出 hex 用
.toString(CryptoJS.enc.Hex)
crypto-js加密
https://fatdog.20060113.xyz/posts/crypto-js/ 部分信息可能已经过时









