必须先用TextEncoder将HTML字符串编码为ArrayBuffer,再用crypto.subtle.encrypt()加密;IV和salt须每次随机生成并随密文持久化,否则解密必败。

不能直接对 HTML 字符串调用 crypto.subtle.encrypt() —— 必须先编码为 ArrayBuffer,且每次加密必须用全新 iv,否则解密失败或被攻击。
HTML 编辑器内容怎么转成加密可用的二进制数据
Web Crypto API 的 encrypt() 只接受 ArrayBuffer,编辑器里拿到的 innerHTML 或 value 是字符串,不能跳过编码步骤。
- 用
TextEncoder编码:它比unescape(encodeURIComponent())更可靠,能正确处理 emoji、中文、控制字符 - 编码后得到
Uint8Array,再用.buffer提取ArrayBuffer - 大文档(比如 >5MB)要考虑内存压力;可截断提示或分块加密(但 Web Crypto 不支持流式,需手动切分 + 拼接 IV/Tag)
示例:
const editorContent = document.getElementById("editor").innerHTML;
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(editorContent).buffer; // ← 关键一步
AES-GCM 加密时哪些参数绝对不能省略或复用
漏掉或写错任意一项,解密时会静默失败(Promise reject)或返回乱码,而不是报明确错误。
立即学习“前端免费学习笔记(深入)”;
-
iv必须是Uint8Array(12)(GCM 推荐长度),每次调用crypto.getRandomValues()生成新值,绝不可用固定值或时间戳 -
key必须有["encrypt", "decrypt"]权限,即使只加密不用解密,也得写上——否则后续无法导出或用于解密 - 算法对象必须含
name: "AES-GCM"和iv,tagLength建议显式设为128(默认也是 128,但不写容易在旧浏览器出兼容问题) - 不要传
additionalData(AAD)除非你真需要认证额外字段;加了就得解密时原样传回,否则验证失败
加密后的数据怎么安全封装并供后续解密使用
密文本身不含 IV 和认证标签,解密时缺一不可。不能只存 encrypted 的 ArrayBuffer,必须把三者打包。
- 推荐结构:
{ iv: Uint8Array, data: Uint8Array, tag: Uint8Array }→ 转成JSON.stringify()→btoa()编码为 Base64 字符串(便于存 localStorage 或嵌入 HTML 注释) - 如果要嵌入 HTML,避免放在
<script>里明文暴露;可塞进<meta name="encrypted-content" content="...">>或注释节点,读取时再atob()还原 - 别用
exportKey("jwk")存密钥——JWK 是明文 JSON,localStorage 不安全;若需持久化密钥,应先用 PBKDF2 派生主密钥,再用它wrapKey()加密 AES 密钥
用户输入密码时怎么派生出加密密钥(而不是直接当密钥用)
用户输“123456”不能直接当 AES 密钥——太弱,且长度不对。必须用 PBKDF2 拉伸,加盐,迭代足够次数。
- 盐值
salt必须每次独立生成(crypto.getRandomValues(new Uint8Array(16))),且和加密结果一起保存 - 迭代次数建议 ≥ 100_000(StatiCrypt 用 600k),
hash: "SHA-256"是底线 - 派生目标必须指定
{ name: "AES-GCM", length: 256 },否则生成的密钥可能不兼容 - 整个过程异步,需
await链:import password → deriveKey → encrypt
关键链路:
const keyMaterial = await crypto.subtle.importKey(
"raw", encoder.encode(password), { name: "PBKDF2" }, false, ["deriveKey"]
);
const key = await crypto.subtle.deriveKey(
{ name: "PBKDF2", salt, iterations: 100_000, hash: "SHA-256" },
keyMaterial,
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
最易被忽略的是:IV 和 salt 都是一次性随机值,但它们必须和密文一起持久化,并在解密时原样提供——少一个字段,解密就彻底失败,而且错误信息非常模糊(通常是 DataError 或 OperationError)。别假设“我记住了”,一定要序列化进去。


















