一句话:AES 加密数据,RSA 交换密钥——本博客工具页与可选 API 加密都按这套约定实现。
写在前面
敏感信息传输常见两种算法:
| 类型 | 代表 | 特点 | 典型用途 |
|---|---|---|---|
| 对称 | AES | 加解密同一密钥,快 | 请求体 bulk 加密 |
| 非对称 | RSA | 公钥加密、私钥解密,慢 | 交换 AES 密钥、小 payload |
本博客 C 端:utils/crypto.ts(AES)、utils/jsencrypt.ts(RSA);工具页 /tool/crypto 可在线试验。
依赖安装
bash
npm install crypto-js jsencrypt
npm install -D @types/crypto-js
# Node 侧 RSA 可用 node-jsencrypt 或同库 isomorphic 用法
前后端约定:密文统一转大写 Hex 字符串传输,避免 Base64 在 URL 中的 +/= 问题。
AES 对称加密(CBC + PKCS7)
本博客默认 AES-256-CBC(32 字节 key + 16 字节 iv):
typescript
// blog-home-nuxt/utils/crypto.ts(示意)
import CryptoJS from 'crypto-js';
export function aesEncrypt(word: string, key: string, iv: string) {
const wordUTF8 = CryptoJS.enc.Utf8.parse(word);
const keyUTF8 = CryptoJS.enc.Utf8.parse(key);
const ivUTF8 = CryptoJS.enc.Utf8.parse(iv);
const encrypted = CryptoJS.AES.encrypt(wordUTF8, keyUTF8, {
iv: ivUTF8,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return encrypted.toString(CryptoJS.format.Hex).toUpperCase();
}
export function aesDecrypt(hex: string, key: string, iv: string) {
const parsed = CryptoJS.format.Hex.parse(hex);
const bytes = CryptoJS.AES.decrypt(parsed, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(iv),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return bytes.toString(CryptoJS.enc.Utf8);
}
注意:
- key 长度 16 / 24 / 32 字节对应 AES-128/192/256
- iv 必须随机且不可复用同一 key(生产环境勿写死 iv)
- 本仓库历史文章 key 为示例,生产请环境变量注入
在 API 请求中的用法
api/request.ts 在 VITE_NUXT_OPEN_ENCRYPT=true 时对 body 做 aesEncrypt(JSON.stringify(body)),响应同理解密——仅对约定路径生效(见 home-03-api-request-contract 规则)。
RSA 非对称加密
typescript
// blog-home-nuxt/utils/jsencrypt.ts(示意)
import { enc } from 'crypto-js';
import { JSEncrypt } from 'jsencrypt';
export function rsaEncrypt(word: string, pubKey: string) {
const encrypt = new JSEncrypt();
encrypt.setPublicKey(pubKey);
const encrypted = encrypt.encrypt(word) as string;
return enc.Hex.stringify(enc.Base64.parse(encrypted)).toUpperCase();
}
export function rsaDecrypt(hex: string, priKey: string) {
const decrypt = new JSEncrypt();
decrypt.setPrivateKey(priKey);
const base64 = enc.Base64.stringify(enc.Hex.parse(hex));
return decrypt.decrypt(base64);
}
典型流程:
- 客户端用服务端公钥 RSA 加密随机 AES 密钥
- 服务端私钥解密得到 AES 密钥
- 后续通信用 AES 加解密 body
RSA 不适合加密大文件(有长度限制),只适合小字符串。
选型对比
| 场景 | 推荐 |
|---|---|
| HTTPS 已启用 | 传输层已加密,业务层 AES 可选(防抓包内明文) |
| 密码存库 | bcrypt / scrypt,不要 AES 可逆加密密码 |
| 前端 localStorage 敏感数据 | 仍可被 XSS 读取,加密只是混淆 |
| 国密要求 | SM2/SM4(本博客工具页另有国密试验页) |
踩坑
- Hex 大小写:解密前统一
toUpperCase()或约定一方 - JSEncrypt encrypt 返回 false:明文过长或公钥格式错误
- 前后端 key 不一致:UTF-8 parse 方式必须一致
- 勿在 Git 提交真实 key:用
.env+ 服务端配置
小结
- AES 负责** bulk 数据**,RSA 负责密钥交换或小字段
- 本博客实现:
crypto.ts+jsencrypt.ts+ 可选/encrypt前缀 API - 在线试用:加解密工具


全部评论(0)