TypeScript 加密工具库企业级实现文档
TypeScript 加密工具库企业级实现文档(AES-GCM 模式)
(一)一、概述
本工具库基于原生 Web Crypto API 实现,支持 AES-GCM 加密模式(认证加密,兼具加密与完整性校验),通过 TypeScript 类型增强、环境区分策略、密钥安全管理等优化,提供开发友好、生产安全的加密解决方案。核心功能包括:
• 对象/字符串加密(自动序列化/反序列化)
• 动态 IV 生成与存储
• 开发/生产环境差异化行为
• 完整错误处理与安全后备机制
(二)二、核心模块解析
1.1. 密钥管理服务(EncryptionKeyService)
集中管理密钥逻辑,确保开发环境友好、生产环境严格验证。
(1)核心逻辑:
• 开发环境(DEV):
– 若未设置 VITE_ENCRYPTION_KEY 环境变量,输出警告并使用固定开发密钥(32字节)。
– 允许使用任意长度密钥(仅开发调试)。
• 生产环境(PROD):
– 强制要求设置 VITE_ENCRYPTION_KEY 环境变量,否则抛出错误。
– 严格验证密钥长度(必须 32 字节,对应 AES-256),不满足则抛出错误。
class EncryptionKeyService {
static getEncryptionKey(): string {
const envKey = import.meta.env.VITE_ENCRYPTION_KEY;
// 开发环境处理
if (import.meta.env.DEV) {
if (!envKey) {
console.warn(`[DEV] 未设置 VITE_ENCRYPTION_KEY,使用开发密钥。生产环境必须设置 32 字节安全密钥!`);
return 'dev-secure-key-32bytes-long!'; // 固定开发密钥(32字节)
}
return envKey;
}
// 生产环境验证
if (!envKey) throw new Error('生产环境必须设置 VITE_ENCRYPTION_KEY');
const keyBytes = new TextEncoder().encode(envKey);
if (keyBytes.length !== 32) throw new Error(`密钥需 32 字节,当前 ${keyBytes.length} 字节`);
return envKey;
}
}
2.2. 加密函数(encrypt)
支持字符串或对象加密,自动处理序列化、IV 生成与密文封装。
(1)关键流程:
1. 数据预处理:对象自动序列化为 JSON 字符串。
2. IV 生成:使用 crypto.getRandomValues 生成 12 字节随机 IV(AES-GCM 推荐长度)。
3. 密钥导入:从环境变量获取密钥并验证长度(生产环境强制 32 字节)。
4. 加密执行:调用 crypto.subtle.encrypt 完成 AES-GCM 加密。
5. 结果封装:将 IV 与密文拼接为 Uint8Array,转为 Base64 字符串返回。
export const encrypt = async (data: string | object): Promise<string> => {
const ENCRYPTION_KEY = EncryptionKeyService.getEncryptionKey();
const dataString = typeof data === 'object' ? JSON.stringify(data) : data as string;
const iv = crypto.getRandomValues(new Uint8Array(12)); // 生成随机 IV
const encodedData = new TextEncoder().encode(dataString);
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(ENCRYPTION_KEY),
{ name: 'AES-GCM' },
false,
['encrypt']
);
const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encodedData);
const result = new Uint8Array([...iv, ...new Uint8Array(encrypted)]); // IV + 密文
return btoa(String.fromCharCode(...result)); // 转为 Base64
};
3.3. 解密函数(decrypt)
支持解密字符串或对象,自动处理 Base64 解码、IV 提取与反序列化。
(1)关键流程:
1. Base64 解码:将密文转为 Uint8Array。
2. IV 与密文分离:前 12 字节为 IV,剩余为加密数据。
3. 密钥导入:从环境变量获取密钥(同加密逻辑)。
4. 解密执行:调用 crypto.subtle.decrypt 完成 AES-GCM 解密。
5. 结果处理:解密后字符串尝试解析为 JSON 对象(支持泛型类型推断)。
export const decrypt = async <T = string>(encryptedData: string): Promise<T> => {
const ENCRYPTION_KEY = EncryptionKeyService.getEncryptionKey();
const bytes = new Uint8Array([...atob(encryptedData)].map(c => c.charCodeAt(0)));
const iv = bytes.slice(0, 12); // 提取 IV
const data = bytes.slice(12); // 提取密文
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(ENCRYPTION_KEY),
{ name: 'AES-GCM' },
false,
['decrypt']
);
const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, data);
const result = new TextDecoder().decode(decrypted);
try {
return JSON.parse(result) as T; // 自动解析对象(支持泛型)
} catch {
return result as T; // 解析失败返回原始字符串
}
};
(三)三、核心优化亮点
1.1. 环境区分策略
环境 |
密钥要求 |
后备方案 |
目标 |
开发(DEV) |
可选(警告提示) |
返回 dev_fallback:原始数据 |
降低调试门槛,保留数据可读性 |
生产(PROD) |
强制 32 字节,严格验证 |
返回 err_时间戳_随机串(混淆值) |
防止敏感数据泄露,保障安全 |
2.2. 类型安全增强
• 加密对象:直接传入对象(如 { id: 1, name: 'Alice' }),自动序列化为 JSON 字符串。
• 解密类型推断:通过泛型 decrypt<T>() 自动推断返回类型,无需手动类型断言。
3.3. 错误处理优化
• 生产环境:加密/解密失败时返回混淆值(如 err_1q2w3e_4r5t6y),避免暴露原始数据。
• 开发环境:返回标记为 dev_fallback: 的原始数据,便于调试(如 dev_fallback:{"id":1,"name":"Alice"})。
(四)四、使用示例
1.1. 加密字符串
// 加密敏感文本
const encryptedText = await encrypt("用户密码:123456");
console.log("加密结果:", encryptedText); // 输出类似:'U2FsdGVkX1+...'
2.2. 解密字符串
// 解密字符串(指定返回类型为 string)
const decryptedText = await decrypt<string>(encryptedText);
console.log("解密文本:", decryptedText); // 输出:'用户密码:123456'
3.3. 加密对象
// 加密用户对象
const user = { id: "U1001", role: "admin", token: "abc123" };
const encryptedObj = await encrypt(user);
console.log("加密对象结果:", encryptedObj); // 输出 Base64 字符串
4.4. 解密对象(类型推断)
// 解密对象(自动推断为 { id: string; role: string; token: string })
const decryptedUser = await decrypt<typeof user>(encryptedObj);
console.log("用户对象:", decryptedUser); // 输出原始对象
(五)五、密钥设置指南
1.1. 生成 32 字节安全密钥
# 方法1:使用 Node.js 生成
node -e "console.log(crypto.randomBytes(32).toString('base64'))"
# 方法2:使用 OpenSSL 生成
openssl rand -base64 32
2.2. 配置环境变量
在项目根目录创建 .env.local 文件(Vite 项目):
# .env.local
VITE_ENCRYPTION_KEY=your-32-byte-secure-key-here! # 替换为生成的 32 字节密钥
3.3. 项目配置(Vite)
确保环境变量注入到客户端代码:
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
define: {
'import.meta.env.VITE_ENCRYPTION_KEY': JSON.stringify(process.env.VITE_ENCRYPTION_KEY)
}
});
(六)六、总结
本工具库通过以下设计保障安全与开发效率:
• 生产环境强制安全:32 字节密钥验证、随机 IV、混淆错误值。
• 开发环境友好:自动后备方案、明文标记、宽松密钥要求。
• 类型安全:支持对象加密/解密,泛型自动推断类型。
注意:本方案依赖 Web Crypto API,仅适用于现代浏览器(Chrome ≥ 37、Firefox ≥ 34、Edge ≥ 12)或 Node.js ≥ 15.4.0。如需兼容旧环境(如 IE),可回退至 crypto-js 方案(需配合 @types/crypto-js 类型声明)。