@agentdock/crypto
v0.0.11
Published
E2E encryption for AgentDock — AES-256-GCM, key derivation, Web Crypto API
Downloads
1,385
Readme
@agentdock/crypto
E2E 加密模块 — AES-256-GCM + Ed25519 + NaCl Box/SecretBox,浏览器与 Node.js 22+ 通用。
概述
crypto 包实现 AgentDock 的端到端加密。所有敏感数据在离开用户设备前加密,服务端永远看不到明文。
支持两种运行环境:
- 浏览器:Web Crypto API(AES-GCM、HKDF、HMAC)
- Node.js 22+:同样走 Web Crypto API(
globalThis.crypto.subtle) - tweetnacl:NaCl Box / SecretBox(跨平台兼容)
在架构中的位置
wire → crypto → sdk → web
wire → crypto → daemon依赖 wire 的类型定义,被 sdk/daemon/web 使用。
模块结构
src/
├── aes.ts # AES-256-GCM 加密/解密(Web Crypto API)
├── auth.ts # Ed25519 认证挑战(签名/验签)
├── box.ts # NaCl Box 非对称加密(密钥交付)
├── secretbox.ts # NaCl SecretBox 对称加密(legacy 兼容)
├── content.ts # Content keypair 派生(从密钥树推导 Box 密钥对)
├── keys.ts # 密钥派生树(HKDF-SHA512 分层派生)
├── hmac.ts # HMAC-SHA512(消息认证码)
├── encoding.ts # Base64 / Base64URL 编解码
├── random.ts # 安全随机数生成
└── index.ts # Barrel exportsAPI 参考
AES-256-GCM (aes.ts)
import { encryptAesGcm, decryptAesGcm } from '@agentdock/crypto';
// 加密:返回 { c: base64(iv + ciphertext + tag), n: base64(nonce) }
const bundle = await encryptAesGcm(data: Uint8Array, key: Uint8Array);
// 解密:返回原始明文 Uint8Array
const plaintext = await decryptAesGcm(bundle, key);Bundle 格式:iv(12 bytes) + ciphertext + tag(16 bytes),整体 Base64 编码。
Ed25519 认证 (auth.ts)
import { authChallenge, verifyChallenge } from '@agentdock/crypto';
// 从 seed 生成 Ed25519 密钥对 + 签名挑战
const result = await authChallenge(seed: Uint8Array);
// { publicKey, secretKey, challenge, signature }
// 验证签名
const valid = await verifyChallenge(challenge, signature, publicKey);注意:直接使用 seed 作为 Ed25519 种子,不做额外 deriveKey(与 Happy 对齐,见 L23)。
NaCl Box (box.ts)
import { encryptBox, decryptBox, boxPublicKeyFromSecretKey } from '@agentdock/crypto';
// 非对称加密(发送方用接收方公钥加密)
const bundle = encryptBox(data: Uint8Array, recipientPublicKey: Uint8Array);
// 解密(接收方用自己的私钥 + 发送方公钥解密)
const plaintext = decryptBox(bundle, secretKey: Uint8Array);
// 从 X25519 私钥推导公钥
const publicKey = boxPublicKeyFromSecretKey(secretKey);NaCl SecretBox (secretbox.ts)
import { encryptSecretBox, decryptSecretBox } from '@agentdock/crypto';
// 对称加密(legacy 兼容)
const bundle = encryptSecretBox(data: Uint8Array, secret: Uint8Array);
const plaintext = decryptSecretBox(bundle, secret);密钥派生树 (keys.ts)
import { deriveSecretKeyTreeRoot, deriveSecretKeyTreeChild, deriveKey } from '@agentdock/crypto';
// 从根密钥 + 标签派生子密钥
const root = await deriveSecretKeyTreeRoot(masterSecret, 'Happy EnCoder');
const child = await deriveSecretKeyTreeChild(root, 'content');
// 底层:HKDF-SHA512 派生
const key = await deriveKey(secret, label, segments);Content Keypair (content.ts)
import { deriveContentKeyPair } from '@agentdock/crypto';
// 'Happy EnCoder' + ['content'] + SHA-512[0:32] → NaCl Box keypair
const { publicKey, secretKey } = await deriveContentKeyPair(secret);HMAC-SHA512 (hmac.ts)
import { hmacSha512 } from '@agentdock/crypto';
const mac = await hmacSha512(key, data);编码 (encoding.ts)
import { encodeBase64, decodeBase64, encodeBase64Url, decodeBase64Url } from '@agentdock/crypto';开发
# 运行测试(111 tests)
pnpm --filter @agentdock/crypto test
# 覆盖率(目标 95%+)
pnpm --filter @agentdock/crypto test:coverage设计决策
- Web Crypto API 优先:AES-GCM、HKDF、HMAC 全走
crypto.subtle,不引入额外依赖 - tweetnacl 用于 NaCl:Box/SecretBox 使用 tweetnacl,因为 Web Crypto 不支持 X25519 Box
- 密钥派生路径与 Happy 完全一致:确保两端互操作(L23 教训)
- TypeScript
as BufferSource断言:TS 5.7 的 Uint8Array 类型不兼容 Web Crypto(L7 教训)
