eagleye

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 类型声明)。

posted on 2025-06-20 11:25  GoGrid  阅读(41)  评论(0)    收藏  举报

导航