惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
有赞技术团队
有赞技术团队
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
F
Fox-IT International blog
Recorded Future
Recorded Future
T
ThreatConnect
T
The Exploit Database - CXSecurity.com
SecWiki News
SecWiki News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
人人都是产品经理
人人都是产品经理
T
Tenable Blog
L
LINUX DO - 最新话题
博客园_首页
Hugging Face - Blog
Hugging Face - Blog
罗磊的独立博客
博客园 - 司徒正美
The Hacker News
The Hacker News
博客园 - 聂微东
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Scott Helme
Scott Helme
博客园 - 【当耐特】
O
OpenAI News
Schneier on Security
Schneier on Security
Latest news
Latest news
S
Security @ Cisco Blogs
S
Secure Thoughts
F
Full Disclosure
L
Lohrmann on Cybersecurity
S
SegmentFault 最新的问题
T
Tor Project blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
量子位
小众软件
小众软件
T
Threat Research - Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
N
News and Events Feed by Topic
E
Exploit-DB.com RSS Feed
J
Java Code Geeks
Last Week in AI
Last Week in AI
酷 壳 – CoolShell
酷 壳 – CoolShell
Application and Cybersecurity Blog
Application and Cybersecurity Blog
S
Schneier on Security
Cisco Talos Blog
Cisco Talos Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
P
Proofpoint News Feed
Recent Commits to openclaw:main
Recent Commits to openclaw:main
雷峰网
雷峰网

掘金

AI应用开发七:可以替代 RAG 的技术 juejin.cn 小书匠:一款本地优先、去中心化的全能笔记软件 juejin.cn juejin.cn juejin.cn Shadow实战接入与生产落地:从零搭建到稳定运行 Shadow Transform:编译期的魔法——字节码替换实战 juejin.cn juejin.cn Hermes Agent:一个真正“会成长”的开源 AI Agent,正在改变 AI 自动化玩法 juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn 【节点】[Distance节点]原理解析与实际应用 juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn ArkClaw AI 盯盘管家 —— 从手动口令到自动推送,4 套预置定时任务模版一键启用 juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn “杀!杀!杀!”、“我最讨厌事后道歉”——骂“杀哥”之前,谁还没当过情绪崩溃的人 juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn Crawlee StagehandCrawler:自然语言点 Load More 的工程化爬虫 juejin.cn juejin.cn juejin.cn juejin.cn 人人都在鼓吹的OPC,我想给你泼盆冷水 juejin.cn juejin.cn juejin.cn Redis内存用爆了,原来我们都忽略了这个配置 juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn Android 专家岗 Kotlin 面试题:能答出这些,说明你对语言设计有自己的理解 juejin.cn juejin.cn 业务系统集成 OpenClaw 多 Agent 方案:从架构到落地的完整指南 juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn 四、Agent 评估与可观测性:LangSmith 与客服 A/B 测试 🍃 MongoDB 从入门到上手:一篇写给新手的科普指南 juejin.cn juejin.cn juejin.cn juejin.cn RAG 系列(十九):增量更新——知识库如何保持新鲜 juejin.cn juejin.cn juejin.cn juejin.cn juejin.cn 当 00 后开始用 token 给学校送礼 juejin.cn SwiftUI 多线程与并发编程深度总结 juejin.cn juejin.cn juejin.cn Combine 架构模式:构建响应式应用的蓝图 Combine 高级实践:多线程调度、调试与测试 SSE(Server-Sent Events)完全指南 juejin.cn
CryptoJS:数据安全的JavaScript加密利器
独泪了无痕 · 2026-05-23 · via 掘金

image

前言

  在传统的客户端-服务器交互中,用户在前端输入的敏感信息(如用户名、密码、信用卡号等)通常会以明文通过 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()WordArrayBase64字符串执行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)
Base64Java 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进行封装可以让我们更好地组织和管理代码,提高开发效率和代码质量。