CryptoJS:数据安全的JavaScript加密利器
前言
在传统的客户端-服务器交互中,用户在前端输入的敏感信息(如用户名、密码、信用卡号等)通常会以明文通过 HTTPS 提交到后台,即便在 HTTPS 保护下,仍有安全隐患。如果用户的浏览器或网络受到攻击,可能篡改或窃取表单数据,甚至被浏览器插件劫持。而且如果后端在日志中意外记录了明文敏感信息,可能存在泄露风险。因此,在前端对敏感数据进行加密,并在后端对其解密,能够为安全防护增加一道“保险层”,即便数据在传输层被截获,也难以被攻击者直接获取明文。
一、CryptoJS 快速入门
1.1 CryptoJS 是什么
随着前端技术的不断发展,安全性问题越来越受到重视。在这样的背景下,加密技术成为了保护数据安全的重要手段。crypto-js 是一个功能强大的 JavaScript 加密库,它提供了多种加密算法,包括AES、DES、MD5等。这些算法可以帮助开发者轻松地实现数据的加密和解密操作,从而保护敏感数据的安全性。
⚠️ CryptoJS 作为一个成熟的 JavaScript 加密库,虽然官方已停止维护,但其稳定性和丰富的功能使其仍然是许多项目的可靠选择。通过合理的使用和配置,可以在项目中构建强大的安全防护体系。
CryptoJS 官方文档:cryptojs.gitbook.io/
1.2 主要功能概览
CryptoJS 是一套纯 JavaScript 实现的常用加密算法库,包含以下常见模块:
graph TD
A[输入数据]
A-->B{加密类型}
B-->C1[哈希算法]
B-->C2[对称加密]
B-->C3[编解码]
C1-->D1["MD5/SHA1/SHA256"]
C2-->D2["AES/DES/Rabbit"]
C3-->D3["Base64/Hex"]
D1-->E1[输出哈希值]
D2-->E2[输出密文]
D3-->E3[输出编码结果]
style B fill:#FFA500,stroke:#333,stroke-width:2px;
由于 CryptoJS 纯前端可用,不依赖于 Node 内置模块,体积较小、使用方便,常用于浏览器环境的数据加密、签名和哈希操作。
1.3 在 Vue 中安装并引入
安装 CryptoJS
要在 Vue 项目中使用 crypto-js,首先需要通过 npm 将其安装到项目中。打开终端,进入项目目录,执行以下命令:
npm install crypto-js --save-dev
# # 安装核心库与类型声明
npm install @types/crypto-js --save-dev
⚠️ crypto-js 4.x 版本依赖原生 crypto 模块,不支持IE10及以下浏览器。如需支持旧浏览器,建议使用 3.x 版本
在组件中引入 CryptoJS
在需要进行加密操作的 Vue 组件中,引入相关模块。
import CryptoJS from 'crypto-js';
引入后,我们就能得到 CryptoJS 这个对象,它包含了各种各样的加密算法。
1.4 CryptoJS 加密模式
在 CryptoJS 中,加密模式指的是在加密过程中使用的特定算法模式。这些模式决定了如何组织和处理明文和密钥,以及如何生成密文。CryptoJS 支持多种加密模式,每种模式都有其特定的用途和安全性。以下是一些常见的加密模式:
| 加密模式 | 简要说明 |
|---|---|
| ECB | 将明文分割成独立的块,然后使用相同的密钥对每个块进行独立加密。 安全性较低,因为相同的明文块会产生相同的密文块,在实际生产中不推荐使用 |
| CBC | 最常用的 AES 模式,通常用于加密较长的数据。 它需要 IV(初始化向量),并且每个数据块的加密依赖于前一个数据块 广泛使用,适用于大多数需要一定安全性的应用。 |
| CFB | 提供与CBC相似的安全性,但实现起来可能更复杂 |
| OFB | 使用一个初始向量(IV)和一个密钥流生成器。 密钥流生成器基于密钥和一系列迭代产生的输出。 提供与CFB相似的安全性,但实现上更简单 |
| CTR | 使用一个计数器来生成密钥流。 每个块的加密都是独立的,与前一个块无关。 提供高强度的安全性,并且易于实现并行处理 |
| GCM | 结合了计数器模式和Galois乘法的认证加密模式。 提供认证加密功能,即同时保证数据的机密性和完整性。 是目前推荐用于需要同时保证数据安全和完整性的应用(如TLS) |
二、编码转换
在 CryptoJS 中,编码转换是加密操作的基础环节,它负责在不同数据表示形式之间进行转换。CryptoJS 提供了完整的编码器体系,其中Base64、Hex、UTF-8、UTF-16是最常用的编码方式。
2.1 UTF-8、UTF-16
在现代 Web 开发和密码学应用中,字符编码处理是至关重要的基础环节。CryptoJS 提供了强大的 UTF-8 和 UTF-16 编码支持,使得我们能够轻松处理多语言文本的加密和解密操作。这些编码器不仅支持基本的 ASCII 字符,还能够正确处理复杂的 Unicode 字符,包括 emoji 表情和特殊符号。
// 字符串转换为WordArray
const wordArray = CryptoJS.enc.Utf8.parse("Hello 世界");
console.log("WordArray:", wordArray.toString());
// WordArray转换回字符串
const originalString = CryptoJS.enc.Utf8.stringify(wordArray);
console.log("Original String:", originalString);
2.2 Base64编解码
在Web开发过程中,Base64 编码是用于传输 8bit 字节数据的常见编码方式之一,能够将二进制数据转换为 ASCII 字符序列,广泛应用于数据加密、文件传输和图片处理等场景。CryptoJS 库提供了完整且高效的 Base64 加解密功能,包括Base64编码和解码。
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
| CryptoJS.enc.Utf8.parse() | 字符串 | WordArray | 将字符串转换为WordArray格式 |
| CryptoJS.enc.Base64.stringify() | WordArray | Base64字符串 | 执行Base64编码 |
| CryptoJS.enc.Base64.parse() | Base64字符串 | WordArray | 解析Base64字符串 |
| toString() | 编码类型 | 字符串 | 将WordArray转换为指定编码的字符串 |
// 待编码的字符串
const originalText = "Hello World";
// 字符串转 WordArray
const wordArray = CryptoJS.enc.Utf8.parse(originalText);
// Base64 编码(解决特殊字符传输问题)
const base64Encoded = CryptoJS.enc.Base64.stringify(wordArray);
console.log("Base64 编码:", base64Encoded);
const parsedWordArray = CryptoJS.enc.Base64.parse(base64Encoded);
// Base64 解码
const base64Decoded = parsedWordArray.toString(CryptoJS.enc.Utf8);
console.log("Base64 解码:", base64Decoded);
⚠️ 需要确保在编码和解码过程中使用相同的编码方式(如UTF-8),以避免出现乱码。虽然 Base64 编码可以用于加密数据的传输,但它本身并不提供加密功能。
2.3 Hex
在密码学和数据安全领域,十六进制(Hex)编码扮演着至关重要的角色。CryptoJS 库中的 CryptoJS.enc.Hex 编码器专门用于处理二进制数据与十六进制字符串之间的转换,这种编码方式在多个关键场景中发挥着不可替代的作用。以下是 Hex 编码解码的完整使用示例:
const message = "Hello World";
// Hex 编码
const hexEncoded = CryptoJS.enc.Hex.stringify(CryptoJS.enc.Utf8.parse(message));
console.log("Hex 编码:", hexEncoded);
// Hex 解码
const hexDecoded = CryptoJS.enc.Hex.parse(hexEncoded).toString(CryptoJS.enc.Utf8);
console.log("Hex 解码:", hexDecoded);
三、哈希算法
哈希函数主要用于生成数据的“数字指纹”,常用于密码存储(需配合加盐)和数据完整性校验,保证信息在传输过程中不被篡改。
3.1 MD5 加密
MD5 是一种广泛使用的散列函数,可以产生出一个128位(16字节)的不可逆的散列值,用于确保信息传输完整一致。它被用于各种安全应用,也通常用于校验文件的完整性。MD5算法具有以下特点:
| 特点 | 简要说明 |
|---|---|
| 压缩性 | 任意长度的消息都可以被压缩成一个128位的摘要 |
| 容易计算 | MD5 算法的计算速度比较快,适用于对大量数据进行哈希计算 |
| 抗修改性 | 对原始数据进行任何修改,都会导致哈希值的变化 |
| 抗碰撞性 | 对不同的原始数据,哈希值相同的概率非常小 |
在CryptoJS中,MD5加密非常简单,以下是 CryptoJS 实现 MD5 算法的示例代码:
const message = 'Hello, World!';
const encrypted = CryptoJS.MD5(message).toString();
// 输出MD5加密后的字符串
console.log("MD5:", encrypted);
上述代码的意思是将字符串“hello world”使用 MD5 算法进行加密,并将结果以字符串的形式输出到控制台中。需要注意的是,在输出字符串时,需要使用 toString 方法将加密结果转换为字符串,否则将无法正常输出。
传入CryptoJS.MD5 的参数除了字符串外,还可以是 CryptoJS 定义的一种叫做 WordArray 的数据类型。比如:
const wordArray = CryptoJS.enc.Utf8.parse('Hello World');
CryptoJS.MD5(wordArray).toString();
⚠️ 虽然 MD5 计算速度快,但已被证实存在安全隐患,仅建议用于非安全场景的本地文件校验。
3.2 SHA-1 加密
SHA1 是一种常用的哈希算法,用于将任意长度的消息压缩成一个160位的摘要。SHA1算法具有以下特点:
| 特点 | 简要说明 |
|---|---|
| 压缩性 | 任意长度的消息都可以被压缩成一个160位的摘要 |
| 容易计算 | SHA1 算法的计算速度比较快,适用于对大量数据进行哈希计算 |
| 抗修改性 | 对原始数据进行任何修改,都会导致哈希值的变化 |
| 抗碰撞性 | 对不同的原始数据,哈希值相同的概率非常小 |
以下是 CryptoJS 实现 SHA1 算法的示例代码:
const wordArray = CryptoJS.enc.Utf8.parse('Hello World');
console.log("SHA1:", CryptoJS.SHA1(message).toString());
3.3 SHA-2 加密
SHA-224、SHA-256、SHA-384和SHA-512合称为SHA-2,虽然 SHA-2 提供了更好的安全性,但是它的应用不如 SHA-1 广泛,通常用于数据签名和身份验证等场合。
SHA-256
SHA256 是一种比较常见的哈希算法,它是一种单向加密算法,不提供解密方法,用于将任意长度的消息压缩成一个256位的摘要。SHA256算法具有以下特点:
| 特点 | 简要说明 |
|---|---|
| 压缩性 | 任意长度的消息都可以被压缩成一个256位的摘要 |
| 容易计算 | SHA256 算法的计算速度比较快,适用于对大量数据进行哈希计算 |
| 抗修改性 | 对原始数据进行任何修改,都会导致哈希值的变化 |
| 抗碰撞性 | 对不同的原始数据,哈希值相同的概率非常小 |
以下是 CryptoJS 实现 SHA3 算法的示例代码:
const message = "Hello World";
console.log("SHA3:", CryptoJS.SHA3(message).toString());
SHA-512
SHA3 是一种比较常见的哈希算法,用于将任意长度的消息压缩成一个固定长度的摘要。。SHA256算法具有以下特点:
| 特点 | 简要说明 |
|---|---|
| 压缩性 | 任意长度的消息都可以被压缩成一个固定长度的摘要 |
| 容易计算 | SHA512 算法的计算速度比较快,适用于对大量数据进行哈希计算 |
| 抗修改性 | 对原始数据进行任何修改,都会导致哈希值的变化 |
| 抗碰撞性 | 对不同的原始数据,哈希值相同的概率非常小 |
以下是 CryptoJS 实现 SHA256 算法的示例代码:
const message = "Hello World";
console.log("SHA512:", CryptoJS.SHA512(message).toString());
3.4 SHA-3 加密
SHA512 是一种比较常见的哈希算法,它是一种单向加密算法,不提供解密方法,用于将任意长度的消息压缩成一个 512 位的摘要。SHA256算法具有以下特点:
| 特点 | 简要说明 |
|---|---|
| 压缩性 | 任意长度的消息都可以被压缩成一个 512 位的摘要 |
| 容易计算 | SHA512 算法的计算速度比较快,适用于对大量数据进行哈希计算 |
| 抗修改性 | 对原始数据进行任何修改,都会导致哈希值的变化 |
| 抗碰撞性 | 对不同的原始数据,哈希值相同的概率非常小 |
以下是 CryptoJS 实现 SHA256 算法的示例代码:
const message = "Hello World";
console.log("SHA512:", CryptoJS.SHA512(message).toString());
四、对称加密算法
加密是为了保证数据安全传输,使得其他人不能获取的具体信息内容。以某种特殊的算法,将原本信息数据进行改变,使得即使没有权限的人看到消息也不能从中得到任何有用信息,但是加密的信息是保证可逆的,即可加密必可解密(其长度与目标文本成正比)。所谓对称,指的是加密和解密使用的是相同的秘钥,常见的有 DES、3DES、AES等。对称加密主要用于对敏感数据进行加密和解密,确保数据的机密性。其加解密速度快、计算量小,适合对大量数据进行加密处理。
4.1 AES加密解密的实现
AES 是一种常见的对称加密算法,通过相同的密钥进行加密和解密,常用于数据保护和机密信息存储等场合。AES 的出现,是用于取代已经被证明不安全的 DES 算法。AES 或者说对称加密算法的优点是速度快,缺点就是不安全。为了最大程度地兼容性与安全性,我们采用 AES-256-CBC 模式对称加密。AES 算法具有以下特点:
| 特点 | 简要说明 |
|---|---|
| 安全性高 | AES 算法使用固定长度的密钥进行加密和解密,可以有效防止数据被破解 |
| 灵活性强 | AES 算法可以使用多种密钥长度,如128位、192位或256位 |
| 计算速度快 | AES 算法的计算速度比较快,适用于对大量数据进行加密和解密 |
// 加密:数据 → 密钥 → 密文
const ciphertext = CryptoJS.AES.encrypt("要加密的敏感数据", "自定义密钥").toString();
// 解密:密文 → 密钥 → 原始数据
const bytes = CryptoJS.AES.decrypt(ciphertext, "自定义密钥");
const plaintext = bytes.toString(CryptoJS.enc.Utf8);
密钥和偏移量的设置
加密需要一把“钥匙”,这把钥匙就是密钥。另外还有一个叫“偏移量”的东西,它可以帮助我们更好地加密信息。AES 加密需要密钥(Key)和初始向量(IV),这些参数可以自定义,以确保加密解密的正确性。
- key是对称加密算法的核心参数,同一个明文和密钥加密后得到的密文是相同的,因此密钥必须保密并且不易被破解。key的长度可以是128位、192位或256位,不同长度的key对应着不同的安全级别。
- iv是用于增加加密强度的参数,它需要与key一起作为输入参数传递给加密算法。iv的长度为128位,它在每次加密时都会改变,并与key一起参与加密过程。iv的作用是将相同的明文使用不同的iv加密后生成不同的密文,从而增加破解的难度和安全性。
// 密钥
const secretKey = CryptoJS.enc.Utf8.parse("12345678901234567890123456789012");
// 偏移量
const secretIv = CryptoJS.enc.Utf8.parse("abcdefghijklmnop");
⚠️ 注意:生产环境中,密钥(key)和初始向量(iv)强烈建议从后端接口动态获取,与后端开发保持一致,绝对不要硬编码在前端!
加密解密函数封装
我们需要创建一个加密函数来加密信息,这个函数接收一段明文(也就是正常能看懂的文字),然后返回加密后的文字。使用 CryptoJS 的 AES 模块对数据进行加密,使用相同的密钥和配置参数创建解密函数。
/**
* 使用 AES-256-CBC 进行加密
* @param originalText 待加密的数据,支持字符串、对象等
* @param secretKey - 加密密钥
* @param secretIv - 初始向量
* @returns 加密后的 Base64 字符串
*/
export const encryptAES = (originalText: any, secretKey: string, secretIv: string): string => {
if (!originalText) {
return "";
}
const key = CryptoJS.enc.Utf8.parse(secretKey);
const iv = CryptoJS.enc.Utf8.parse(secretIv);
// 统一将数据转为 JSON 字符串
const dataStr = typeof originalText === 'string' ? originalText : JSON.stringify(originalText);
// 使用AES算法进行加密
const encrypted = CryptoJS.AES.encrypt(dataStr, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// encrypted.toString() 默认返回 Base64 编码
return encrypted.toString();
}
我们还需要一个函数来解密信息,解密的写法和加密差不多,只是把 encrypt 方法名改为 decrypt。这个函数接收加密后的文字,然后返回正常的明文。
/**
* 使用 AES-256-CBC 进行解密
* @param cipherText 加密后的字符串
* @param secretKey - 解密密钥
* @param secretIv - 初始向量
* @returns {any} 解密后的原始数据
*/
export const decryptAES = (cipherText: string, secretKey: string, secretIv: string): any => {
if (!cipherText) {
return "";
}
// 将 Key 与 IV 转成 WordArray
const key = CryptoJS.enc.Utf8.parse(secretKey);
const iv = CryptoJS.enc.Utf8.parse(secretIv);
// 执行解密
const decrypted = CryptoJS.AES.decrypt(cipherText, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
});
// 将解密结果转为 UTF-8 字符串
const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
// 尝试还原为 JSON 对象,如果不是对象则直接返回字符串
try {
return JSON.parse(decryptedStr);
} catch {
return decryptedStr;
}
}
⚠️ 如果之前在加密时没有将明文进行 parse 而是直接传入的,那么在解密时,传入 toString() 的解析方式就是写默认的 CryptoJS.enc.Utf8。
既然有了上面的加密和解密函数,现在要在 Vue 项目中使用它们。创建一个简单的 Vue 组件,让用户输入一些信息,然后可以加密和解密。
<script setup lang="ts">
import { ref } from 'vue';
import {decryptAES, encryptAES} from "@/hooks/CryptoJSUtils.ts";
const plaintext = ref('');
const ciphertext = ref('');
const decryptedText = ref('');
// ⚠️ 注意:生产环境中,密钥(key)和初始向量(iv)强烈建议从后端接口动态获取,绝对不要硬编码在前端!
const secretKey = "12345678901234567890123456789012";
const secretIv = "abcdefghijklmnop";
// 加密
const handleEncrypt = () => {
ciphertext.value = encryptAES(plaintext.value, secretKey, secretIv);
}
// 解密
const handleDecrypt = () => {
decryptedText.value = decryptAES(ciphertext.value, secretKey, secretIv);
}
</script>
<template>
<div>
<input type="text" v-model="plaintext" placeholder="请输入明文" />
<button @click="handleEncrypt">加密</button>
<button @click="handleDecrypt">解密</button>
<p>加密后的文本: {{ ciphertext }}</p>
<p>解密后的文本: {{ decryptedText }}</p>
</div>
</template>
Java 加解密基础
Java 中的加解密 API 集中在 javax.crypto 包内,核心类包括:
| 核心类 | 简要说明 |
|---|---|
| Cipher | 加解密的核心类,指定算法、模式、填充方式后,可调用 init、doFinal 进行加密解密 |
| SecretKeySpec | 用来将字节数组转换成对称密钥(SecretKey) |
| IvParameterSpec | 用来封装初始化向量(IV) |
| Base64 | Java 8 内置的 Base64 编解码类 |
如果使用 Spring Boot,可在 pom.xml 中引入 Web 依赖即可,无需额外加密库,因为 JCE 已内置于 JDK。创建一个工具类 EncryptUtils,封装 AES 解密方法:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class EncryptUtils {
// 加密算法
private static String algorithm = "AES";
// 加解密算法/工作模式/填充方式
private static String algorithmProvider = "AES/CBC/PKCS5Padding";
public static String encrypt(String src, String uniqueKey) {
}
/**
* 使用 AES/CBC/PKCS5Padding 对 Base64 编码的密文进行解密
*
* @param base64CipherText 前端加密后的 Base64 密文
* @param aesKey 与前端约定的 32 字节(256 位)Key
* @param aesIv 与前端约定的 16 字节 (128 位) IV
* @return 解密后的明文字符串
*/
public static String decryptAES(String base64CipherText, String aesKey, String aesIv) {
try {
// 1. 将 Base64 密文解码成字节数组
byte[] cipherBytes = Base64.getDecoder().decode(base64CipherText);
// 2. 准备 Key 和 IV
byte[] keyBytes = aesKey.getBytes(StandardCharsets.UTF_8);
byte[] ivBytes = aesIv.getBytes(StandardCharsets.UTF_8);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, algorithm);
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
// 3. 初始化 Cipher
Cipher cipher = Cipher.getInstance(algorithmProvider);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
// 4. 执行解密
byte[] plainBytes = cipher.doFinal(cipherBytes);
// 5. 转为字符串并返回
return new String(plainBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
return null; // 解密失败返回 null,可根据实际情况抛出异常
}
}
}
⚠️ 注意:Java 默认使用 PKCS5Padding,而 CryptoJS 使用的是 PKCS7Padding。二者在实现上是兼容的,所以无需额外配置即可互通。
4.2 3DES加解密
在现代的互联网时代,数据安全性备受关注。为了保护敏感数据的机密性,对称加密算法是一种常用的方法。3DES(Triple DES)一种常用的对称加密算法,是 DES 加密算法的一种增强版本,通过对数据进行三次DES加密来提高安全性。TripleDES 算法的全称是“三重数据加密标准”,它使用固定长度的密钥对数据进行加密和解密,密钥长度为192位。TripleDES 算法具有以下特点:
| 特点 | 简要说明 |
|---|---|
| 安全性较高 | TripleDES 算法使用三个不同的密钥进行加密和解密,密钥长度较长,安全性较高 |
| 灵活性较差 | TripleDES 算法只能使用168位的密钥长度,不够灵活 |
| 计算速度较慢 | TripleDES 算法的计算速度比较慢,适用于对数据进行加密和解密 |
3DES加密的基本用法
在 CryptoJS 中,3DES 加密需要指定密钥和加密模式。以下是一个简单的 3DES 加密示例:
export const encrypt3DES = (originalText: string, publicKey: string, secretIv: string, mode: string) => {
if (!originalText || !publicKey) {
throw new Error('内容和密钥不能为空');
}
if (publicKey.length !== 8) {
throw new Error('密钥必须为8个字符');
}
const options = {
mode: mode === 'ECB' ? CryptoJS.mode.ECB : CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}
if (secretIv) {
if (secretIv.length !== 8) {
throw new Error('IV必须为8个字符')
}
options.iv = CryptoJS.enc.Utf8.parse(secretIv)
}
// 执行加密
const encryptData = CryptoJS.TripleDES.encrypt(originalText, publicKey, options)
// 返回 Base64 格式的密文
return encryptData.toString()
}
3DES解密的基本用法
3DES 解密与加密类似,只是调用的是 decrypt 方法:
export const decrypt3DES = (ciphertext: string, publicKey: string, secretIv: string, mode: string) => {
if (!ciphertext || !publicKey) {
throw new Error('密文和密钥不能为空')
}
if (publicKey.length !== 8) {
throw new Error('密钥必须为8个字符')
}
const options = {
mode: mode === 'ECB' ? CryptoJS.mode.ECB : CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}
if (secretIv) {
if (secretIv.length !== 8) {
throw new Error('IV必须为8个字符')
}
options.iv = CryptoJS.enc.Utf8.parse(secretIv)
}
// 执行解密
const encryptData = CryptoJS.TripleDES.decrypt(ciphertext, publicKey, options)
// 将解密后的数据转换为 UTF-8 字符串
return encryptData.toString(CryptoJS.enc.Utf8)
}
加密解密工具组件
<script setup lang="ts">
import CryptoJS from 'crypto-js';
import { ref} from 'vue';
import {decrypt3DES, encrypt3DES} from "@/hooks/CryptoJSUtils.ts";
const mode=ref('ECB');
const key= ref('12345678');
const iv=ref('');
const plainText= ref('');
const encryptedText= ref('');
const decryptedText= ref('');
/**
* 生成随机密钥
*/
const generateKey = () => {
key.value = CryptoJS.lib.WordArray.random(8).toString();
}
/**
* 加密
*/
const encrypt = () => {
encryptedText.value = encrypt3DES(plainText.value, key.value, iv.value,mode.value)
}
/**
* 解密
*/
const decrypt = () => {
decryptedText.value = decrypt3DES(encryptedText.value, key.value, iv.value,mode.value)
}
</script>
<template>
<div class="container mx-auto p-6 max-w-2xl">
<h1 class="text-2xl font-bold mb-6 text-blue-600">3DES 加密解密工具</h1>
<!-- 加密模式选择 -->
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
<div class="mb-4">
<label class="block text-gray-700 mb-2">加密模式</label>
<select v-model="mode" class="w-full p-2 border rounded">
<option value="ECB">ECB模式</option>
<option value="CBC">CBC模式</option>
</select>
</div>
<!-- 密钥生成 -->
<div class="mb-4">
<label class="block text-gray-700 mb-2">密钥 (8字节)</label>
<div class="flex">
<input v-model="key" type="text" class="flex-1 p-2 border rounded-l" placeholder="输入8位密钥">
<button @click="generateKey" class="bg-blue-500 text-white px-4 rounded-r hover:bg-blue-600">
<i class="fas fa-sync-alt"></i> 生成
</button>
</div>
</div>
<!-- CBC模式IV -->
<div v-if="mode === 'CBC'" class="mb-4">
<label class="block text-gray-700 mb-2">IV偏移量 (8字节)</label>
<input v-model="iv" type="text" class="w-full p-2 border rounded" placeholder="输入8位IV">
</div>
<!-- 文本输入 -->
<div class="mb-4">
<label class="block text-gray-700 mb-2">原始文本</label>
<textarea v-model="plainText" rows="3" class="w-full p-2 border rounded" placeholder="输入要加密的内容"></textarea>
</div>
<!-- 操作按钮 -->
<div class="flex space-x-3 mb-6">
<button @click="encrypt" class="flex-1 bg-green-500 text-white py-2 rounded hover:bg-green-600">
<i class="fas fa-lock"></i> 加密
</button>
<button @click="decrypt" class="flex-1 bg-purple-500 text-white py-2 rounded hover:bg-purple-600">
<i class="fas fa-unlock"></i> 解密
</button>
</div>
<!-- 结果展示 -->
<div class="mb-4">
<label class="block text-gray-700 mb-2">加密结果</label>
<textarea v-model="encryptedText" rows="3" readonly class="w-full p-2 border rounded bg-gray-50"></textarea>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-2">解密结果</label>
<textarea v-model="decryptedText" rows="3" readonly class="w-full p-2 border rounded bg-gray-50"></textarea>
</div>
</div>
</div>
</template>
<style>
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css');
@import url('https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css');
body {
background-color: #f7fafc;
}
</style>
小结
在 3DES 加密中,加密模式和填充方式的选择会影响加密结果的安全性。常见的加密模式有ECB、CBC等,填充方式有Pkcs7、ZeroPadding等。在实际应用中,应根据具体需求选择合适的加密模式和填充方式。虽然 3DES 比 DES 更安全,但在现代加密标准中,3DES已经逐渐被AES等更安全的算法取代。如果对安全性要求较高,建议使用AES等更现代的加密算法。|
五、HMAC 数据验证
5.1 HMAC加密
对称加密只能保证机密性,即对手无法从密文恢复明文,但并不能保证数据在传输过程中未被篡改。为此,可在密文外层再加一层签名(HMAC)。HMAC 是一种基于密钥的消息认证码算法,用于验证消息在传输过程中是否被篡改,以及确认消息来源的真实性,通常用于消息身份验证、API 签名等。HMAC 算法具有以下特点:
| 特点 | 简要说明 |
|---|---|
| 安全性高 | HMAC 算法使用密钥对原始数据进行加密,可以有效防止数据被篡改 |
| 灵活性强 | HMAC 算法可以使用多种哈希函数,如SHA256、SHA512等 |
| 计算速度快 | HMAC 算法的计算速度比较快,适用于对大量数据进行认证计算 |
以下是 CryptoJS 实现 HMAC 算法的示例代码:
const plaintitle = 'hello world'
const key = CryptoJS.enc.Utf8.parse('1234567890123456')
const hmac = CryptoJS.HmacSHA256(plaintitle , key).toString()
5.2 PBKDF2加密
PBKDF2 是一种常用的密码加密算法,用于将用户密码转换成一个固定长度的密钥。PBKDF2 算法的全称是“基于密码的密钥派生函数”,它通过在用户密码上附加一个随机盐值,然后对附加了盐值的密码进行多次哈希计算,最后将计算结果作为密钥。PBKDF2 算法具有以下特点:
| 特点 | 简要说明 |
|---|---|
| 安全性高 | PBKDF2 算法使用随机盐值和多次哈希计算,可以有效防止密码被破解 |
| 灵活性强 | PBKDF2 算法可以使用多种哈希函数,如SHA256、SHA512等 |
| 计算速度慢 | PBKDF2 算法的计算速度比较慢,适用于对密码进行加密计算 |
PBKDF2 基于伪随机函数(PRF)构建,通过对密码和盐值进行多次迭代计算来增强密钥的安全性。其数学表达式可以表示为:
PBKDF2(password: WordArray | string, salt: WordArray | string, cfg?: KDFOption)
| 配置项 | 简要说明 | |
|---|---|---|
| password | 用户输入的密码 | |
| salt | 随机盐值,确保即使是相同密码产生不同的派生密钥,有效防止预计算攻击 | |
| cfg | ||
| keySize | 密钥大小(以字为单位) | |
| hasher | 使用的哈希算法 | |
| iterations | 迭代次数 |
// 使用默认配置(SHA256, 250000次迭代)
var derivedKey = CryptoJS.PBKDF2("password", "somesalt");
// 自定义配置
var customKey = CryptoJS.PBKDF2("password", "somesalt", {
keySize: 256/32, // 256位密钥
iterations: 1000000, // 100万次迭代
hasher: CryptoJS.algo.SHA512 // 使用SHA512
});
六、总结
CryptoJS 解决的是在不受控的客户端环境中实施可控安全策略的矛盾命题,它无法替代 HTTPS 传输层加密,也不能弥补弱密钥管理、明文密钥硬编码、缺乏服务端二次校验等架构缺陷,其真正价值在于赋能开发者在“最小信任模型”下构建纵深防御。因此,通过合理地引入和使用 crypto-js,我们可以有效地保护前端数据的安全性,为用户提供更加安全、可靠的服务。同时,对crypto-js进行封装可以让我们更好地组织和管理代码,提高开发效率和代码质量。