一、开始之前
网站应用中,对敏感的内容进行加密、解密十分常见。本文将探索 crypto-js
库中的加密和解密能力。crypto-js
主要专注于对称加密(如 AES、DES)、哈希算法(如 MD5、SHA 等)和流式加密(如 RC4、Rabbit 等)等方面的支持。
二、crypto-js 安装
sh
pnpm add crypto-js
三、顶层 api
以下是 crypto-js 提供的顶层 api
sh
import cj from 'crypto-js'
console.log("cj", Object.keys(cj))
输出的结果是:
sh
[
'lib', 'enc', 'algo',
'x64', 'MD5', 'HmacMD5',
'SHA1', 'HmacSHA1', 'SHA256',
'HmacSHA256', 'SHA224', 'HmacSHA224',
'SHA512', 'HmacSHA512', 'SHA384',
'HmacSHA384', 'SHA3', 'HmacSHA3',
'RIPEMD160', 'HmacRIPEMD160', 'PBKDF2',
'EvpKDF', 'mode', 'pad',
'format', 'kdf', 'AES',
'DES', 'TripleDES', 'RC4',
'RC4Drop', 'Rabbit', 'RabbitLegacy',
'Blowfish'
]
crypto-js 支持众多的 api, 下面对以上各种 api 的部分内容进行解析。
四、lib 核心库
lib 是核心 api 中的库,承担者主要的加密和解密功能,一般不直接使用。
五、enc 指定字符编码模式
ts
import cj from "crypto-js";
console.log(Object.keys(cj.enc));
包含以下的 8 个 API:
ts
["Hex", "Latin1", "Utf8", "Utf16BE", "Utf16", "Utf16LE", "Base64", "Base64url"];
使用示例(以下示例以常用的 MD5 形式,以及 16 进制和 base64 两种常见的加密形式):
ts
import cj from "crypto-js";
const message = "hello world";
const hash = cj.MD5(message).toString(cj.enc.Hex); // 16 进制形式进行编码
console.log(hash); // 5eb63bbbe01eeed093cb22bb8f5acdc3
const hash = cj.MD5(message).toString(cj.enc.Base64); // base64 形式进行编码
console.log(hash); // XrY7u+Ae7tCTyyK7j1rNww==
const hash = cj.MD5(message).toString(cj.enc.Base64url); // base64 url 形式进行编码
console.log(hash); // XrY7u-Ae7tCTyyK7j1rNww
六、algo 算法
ts
import cj from "crypto-js";
console.log(Object.keys(cj.algo))[
("MD5",
"SHA1",
"SHA256",
"SHA224",
"SHA512",
"SHA384",
"SHA3",
"RIPEMD160",
"HMAC",
"PBKDF2",
"EvpKDF",
"AES",
"DES",
"TripleDES",
"RC4",
"RC4Drop",
"Rabbit",
"RabbitLegacy",
"Blowfish")
];
类型 | 算法 | 说明 |
---|---|---|
哈希算法 | MD5 (常用) | 生成 128 位哈希值,用于校验数据完整性。 |
SHA1 (常用系列) | 生成 160 位哈希值。 | |
SHA256 | 生成 256 位哈希值。 | |
SHA224 | 生成 224 位哈希值。 | |
SHA512 | 生成 512 位哈希值。 | |
SHA384 | 生成 384 位哈希值。 | |
SHA3 | SHA-3 哈希算法。 | |
RIPEMD160 | 另一种生成 160 位哈希值的算法。 | |
HMAC | 基于密钥的哈希消息认证码。 | |
PBKDF2 | 密码基于密钥派生函数。 | |
EvpKDF | 另一种密钥派生函数。 | |
对称加密算法 | AES (常用) | 高级加密标准,用于对称加密和解密数据。 |
DES | 数据加密标准,较早的对称加密算法。 | |
TripleDES | 对 DES 进行多次加密以增加安全性。 | |
流式加密算法 | RC4 | 流式加密算法。 |
RC4Drop | RC4 的变种。 | |
Rabbit | 另一种流式加密算法。 | |
RabbitLegacy | Rabbit 算法的旧版本。 | |
其他 | Blowfish | 对称加密算法,用于加密和解密数据。 |
七、mode 模式
模式 | 说明 |
---|---|
ECB (Electronic Codebook) | 将整个明文分成块,每个块独立加密。可能存在安全性问题。 |
CBC (Cipher Block Chaining) | 前一个块的密文作为下一个块的加密向量,提高了安全性。 |
CFB (Cipher Feedback) | 前一个密文块作为密钥加密当前明文块,可按比块更小单位加密。 |
OFB (Output Feedback) | 使用函数产生的密钥流进行异或运算,提供加密流。 |
CTR (Counter) | 使用计数器的值加密,并与明文进行异或运算,提供加密效果。 |
CTRGladman | CTRGladman 模式 |
ts
import cj from "crypto-js";
const mode = cj.mode;
console.log(mode.CBC);
console.log(mode.CFB);
console.log(mode.CTR);
console.log(mode.CTRGladman);
console.log(mode.ECB);
console.log(mode.OFB);
八、pad 天秤模式
填充方式 | 说明 |
---|---|
AnsiX923 | 在数据末尾填充零字节,最后一个字节表示需要填充的字节数。 |
Iso10126 | 在数据末尾填充随机字节,最后一个字节表示需要填充的字节数。 |
Iso97971 | 使用 ISO/IEC 9797-1 填充方案,在数据末尾填充 \x80 加上零或多个 \x00 直到块的大小。 |
NoPadding | 不进行任何填充,要求数据长度必须是块大小的整数倍。 |
Pkcs7 | 使用 PKCS#7 填充方案,在数据末尾填充字节,字节的值表示需要填充的字节数。 |
ZeroPadding | 在数据末尾填充零字节,直到数据长度满足块大小的整数倍。 |
ts
import cj from "crypto-js";
const a = cj.pad.AnsiX923;
const b = cj.pad.Iso10126;
const c = cj.pad.Iso97971;
const d = cj.pad.NoPadding;
const e = cj.pad.Pkcs7;
const f = cj.pad.ZeroPadding;
九、对称加密
对称加密是一种加密方式,使用相同的密钥(也称为对称密钥)同时对数据进行加密和解密。这意味着使用相同的密钥,发送方对数据进行加密,接收方使用相同的密钥对加密后的数据进行解密。
AES 加密算法
AES(Advanced Encryption Standard,高级加密标准)是一种对称加密算法,被广泛用于加密和解密数据。它是由美国国家标准技术研究所(NIST)在 2001 年公布的一种加密标准,用来替代之前的 DES(Data Encryption Standard)算法。使用最为常见的算法。按照长度可以分为:128/192/256 位三种。其中 128 使用最为广泛。
- AES.encrypt
- AES.decrypt
将 AES 封装成一个类
ts
import CryptoJS from "crypto-js";
import Utf8 from "crypto-js/enc-utf8";
import AES from "crypto-js/aes";
import Pkcs7 from "crypto-js/pad-pkcs7";
class AESCipher {
constructor(key, mode = CryptoJS.mode.ECB, padding = Pkcs7) {
this.key = Utf8.parse(key);
this.mode = mode;
this.padding = padding;
}
// 加密函数
encrypt(plaintext) {
const encrypted = AES.encrypt(plaintext, this.key, {
mode: this.mode,
padding: this.padding,
}).toString();
return encrypted;
}
// 解密函数(可选)
decrypt(encryptedText) {
const decrypted = AES.decrypt(encryptedText, this.key, {
mode: this.mode,
padding: this.padding,
}).toString(Utf8);
return decrypted;
}
}
- 使用
ts
import CryptoJS from "crypto-js";
import Utf8 from "crypto-js/enc-utf8";
import AES from "crypto-js/aes";
import Pkcs7 from "crypto-js/pad-pkcs7";
// 使用示例
const key = "ThisIsASecretKey123";
const aesCipher = new AESCipher(key, CryptoJS.mode.ECB, Pkcs7);
const encryptedText = aesCipher.encrypt("Hello, world!");
console.log("Encrypted:", encryptedText);
// 解密示例(如果需要解密)
const decryptedText = aesCipher.decrypt(encryptedText);
console.log("Decrypted:", decryptedText);
DES 算法
DES(Data Encryption Standard,数据加密标准)是一种对称加密算法,最初在 1977 年被美国政府确定为加密标准,但由于其使用 56 位密钥长度(实际上是 64 位中的 8 位用于校验),密钥长度较短,安全性逐渐变弱,因此在现代安全需求下已不再推荐使用。
- DES.encrypt
- DES.decrypt
封装成类:
ts
import CryptoJS from "crypto-js";
import Utf8 from "crypto-js/enc-utf8";
class DESCipher {
constructor(key) {
this.key = Utf8.parse(key);
}
// 加密函数
encrypt(plaintext) {
const encrypted = CryptoJS.DES.encrypt(plaintext, this.key).toString();
return encrypted;
}
// 解密函数
decrypt(encryptedText) {
const decrypted = CryptoJS.DES.decrypt(encryptedText, this.key).toString(
Utf8
);
return decrypted;
}
}
- 使用示例
ts
// 使用示例
const key = "12345678"; // 这里示范的密钥长度是 8 位
const desCipher = new DESCipher(key);
// 加密示例
const encryptedText = desCipher.encrypt("Hello, world!");
console.log("Encrypted:", encryptedText);
// 解密示例
const decryptedText = desCipher.decrypt(encryptedText);
console.log("Decrypted:", decryptedText);
TripleDES 算法
TripleDES(Triple Data Encryption Standard)是 DES 的一种改进版本,它对 DES 进行了三重加密,以提高安全性。它的密钥长度是 DES 的三倍,即 168 位(56 位 * 3)。
三阶段:
- 第一个阶段(Encrypt) :使用第一个密钥对数据进行加密。
- 第二个阶段(Decrypt) :使用第二个密钥对加密后的数据进行解密。
- 第三个阶段(Encrypt) :使用第三个密钥再次对解密后的数据进行加密。
- TripleDES.encrypt
- TripleDES.decrypt
封装成类:
ts
import CryptoJS from "crypto-js";
import Utf8 from "crypto-js/enc-utf8";
class TripleDESCipher {
constructor(key) {
this.key = Utf8.parse(key);
}
// 加密函数
encrypt(plaintext) {
const encrypted = CryptoJS.TripleDES.encrypt(
plaintext,
this.key
).toString();
return encrypted;
}
// 解密函数
decrypt(encryptedText) {
const decrypted = CryptoJS.TripleDES.decrypt(
encryptedText,
this.key
).toString(Utf8);
return decrypted;
}
}
- 使用
ts
// 使用示例
const key = "123456789012345678901234"; // 密钥长度为 24 字符(192 位)
const tripleDESCipher = new TripleDESCipher(key);
// 加密示例
const encryptedText = tripleDESCipher.encrypt("Hello, world!");
console.log("Encrypted:", encryptedText);
// 解密示例
const decryptedText = tripleDESCipher.decrypt(encryptedText);
console.log("Decrypted:", decryptedText);
十、MD5 算法
MD5(Message Digest Algorithm 5)是一种常见的哈希算法,用于生成 128 位(16 字节)的哈希值。它通常用于数据完整性校验、密码存储等场景,被设计为单向散列函数,意味着它将任意长度的输入数据转换为固定长度的输出。
md5 基础用法:
ts
import cj from "crypto-js";
console.log(cj.MD5("sdf").toString());
注意: MD5 方法调用之后,还需要调用 toString 方法。MD5 方法得到的是一个对象 {words: array, sigBytes: number}
。MD5 方法的特点非常简单固定输入有固定的输出。
十一、SHA 系列算法
算法 | 哈希值长度 | 特点 |
---|---|---|
SHA-1 | 160 位(20 字节) | 存在碰撞漏洞,不再被认为是安全的哈希算法。 |
SHA-256 (常用) | 256 位(32 字节) | 比 SHA-1 更安全,广泛用于数字签名、SSL 证书等领域。 |
SHA-224 | 224 位(28 字节) | SHA-256 的截断版,用于特定应用场景。 |
SHA-512 | 512 位(64 字节) | 比 SHA-256 更安全,提供更长的哈希值,适用于敏感的应用。 |
SHA-384 | 384 位(48 字节) | 提供比 SHA-256 更长的哈希值,适用于高安全性要求的场景。 |
SHA-3 | - | 一种与 SHA-2 系列不同的哈希算法,被认为更为安全。 |
ts
import cj from "crypto-js";
console.log(cj.SHA256(123));
console.log(cj.SHA256(123, {}));
console.log(cj.SHA256([123]));
console.log(cj.SHA256(cj.enc.Utf8.parse("Hello, World!")));
SHA256 函数的参数类型,可以是 string | cj.lib.WordArray
, 也可接受第二个可选的参数 config
对象。
十二、基于 hash 的 HMAC 算法
算法 | 哈希函数 | 哈希值长度 | 密钥长度要求 | 特点 |
---|---|---|---|---|
HMAC-MD5 | MD5 | 128 位(16 字节) | 任意长度 | 安全性较低,不推荐使用,存在碰撞攻击风险。 |
HMAC-SHA1 | SHA-1 | 160 位(20 字节) | 任意长度 | 安全性较低,不推荐使用,存在碰撞攻击风险。 |
HMAC-SHA256 | SHA-256 | 256 位(32 字节) | 推荐大于 256 位 | 安全性高,广泛应用于数字签名、SSL 证书等领域。 |
HMAC-SHA512 | SHA-512 | 512 位(64 字节) | 推荐大于 512 位 | 安全性更高,适用于对安全性要求极高的场景。 |
在实际应用中,HMAC-SHA256 是最常用的 HMAC 算法之一。它具有较高的安全性和广泛的应用场景,在数字签名、SSL 证书、API 认证等许多领域都被广泛采用。HMAC-SHA256 提供了 256 位(32 字节)的哈希值长度,适中的长度同时提供了较高的安全性和较快的计算速度,适合大多数安全性要求不是特别高的场景。
以 HmacSHA256 为例:
ts
const CryptoJS.HmacSHA256: HmacHasherHelper
(message: string | cj.lib.WordArray, key: string | cj.lib.WordArray) => cj.lib.WordArray
HmacSHA256 可以接受两个参数: message 需要加密,key
十三、其他加密算法
RC4、RC4Drop、Blowfish、Rabbit 等:一些其他的加密算法,用于特定场景的加密和解密。
算法 | 密钥长度 | 块大小 | 安全性 | 特点 |
---|---|---|---|---|
RC4 | 可变(1-256 字节) | 无 | 弱 | 早期加密算法,由于存在严重的安全漏洞,不再推荐使用。 |
RC4Drop | 固定为 128 位(16 字节) | 无 | 弱 | 是 RC4 的一个变种,通过舍弃初始几个字节来提高初始输出的随机性。 |
Blowfish | 32-448 位(4-56 字节) | 64 位(8 字节) | 中等 | 对称分组密码算法,安全性较高,但因为比较老旧,在某些场景可能不够。 |
Rabbit | 128 位(16 字节) | 无 | 较高 | 流密码算法,用于加密通信。在一些应用中,比如 WPA 和蓝牙加密中被使用。 |
十四、RSA
RSA 算法属于非对称加密算法,其实现通常比较复杂,并不在crypto-js
的范畴之内。
十五、小结
本文从 crypto-js 库的角度看 JS 中的各种加密和解密的方法。全局了解 crypto-js
的 api, 其中包含了 enc、algo、mode 和 pad 属性,以及对称加密 AES/DES 等对称加密。hash 散列计算方法 MD5 以及 SHA 系列算法。