Skip to content

AES 加密工具 — GCM、CBC 与 CTR 模式

免费在线 AES 加密工具 — 支持 AES-128/192/256、GCM/CBC/CTR 模式,可用口令(PBKDF2)或原始密钥。100% 浏览器本地运行,不上传任何数据。

无追踪 浏览器中运行 免费
一切都在你的浏览器中运行 —— 你的密钥和数据永远不会离开这个页面。
推荐
密钥长度
密钥类型
高级选项
密文
需要专门的解密页面?
已对照 FIPS 197、NIST SP 800-38D、OWASP 以及 W3C Web Crypto 规范核验密码学准确性 — Go Tools 安全团队 · 2026年7月16日

什么是 AES 加密?

AES(高级加密标准)是一种对称分组密码,由 NIST 于 2001 年在 FIPS 197 中标准化,基于 Joan Daemen 和 Vincent Rijmen 设计的 Rijndael 算法。它以固定的 128 位分组加密数据,使用 128、192 或 256 位密钥,同一个密钥既能加密也能解密。它是现代密码学的主力,从 HTTPS 流量到磁盘加密,几乎无处不在。

原始分组密码一次只能打乱一个 16 字节的分组,因此 AES 总是运行在把各分组串联起来的工作模式之内。本工具提供三种模式,均由浏览器的 Web Crypto API 原生支持:GCM、CBC 和 CTR。GCM(Galois/Counter 模式,NIST SP 800-38D)是推荐的默认选项,因为它带有认证 —— 它会在密文旁生成一个 128 位认证标签,因此任何篡改都会在解密时被发现。CBC 和 CTR 只提供机密性;它们本身无法告诉你密文是否被改动过,这也是 TLS 1.3(RFC 8446)放弃所有 CBC 密码套件、转而使用 GCM 这类认证模式的原因。

你会注意到这里没有 ECB 模式,这是刻意为之。ECB 会把每个相同的明文分组加密成相同的密文分组,因此大范围的结构会直接泄露出来 —— 著名的「ECB 企鹅」图像在加密后依然清晰可见是一只企鹅。Web Crypto API 正是出于这个原因省略了 ECB(它只实现了 AES-CBC、AES-CTR 和 AES-GCM),我们也是如此。如果你需要与使用 ECB 的老旧系统互通,应该把这当作迁移它的理由,而不是复制这个弱点的理由。

由于大多数人输入的是口令而不是 32 字节的随机密钥,本工具会用 PBKDF2-HMAC-SHA256、600,000 次迭代和一个 16 字节随机盐从你的口令派生出 AES 密钥,这与当前的 OWASP 密码存储指南(以及要求盐至少 128 位的 NIST SP 800-132)保持一致。这会让暴力破解一个弱口令变得缓慢,但这并不是魔法:这是一个用来学习模式、调试密文和处理一次性个人数据的工具 —— 而不是用来保护生产环境机密的工具,那些应该交给专门的密钥管理系统。要生成一个强口令,可以使用我们的随机密码生成器;要获得真正随机的密钥,请使用密钥生成器

// AES-256-GCM with a passphrase (PBKDF2-HMAC-SHA256, 600,000 iterations).
// Identical code runs in the browser and in Node.js 20+ via Web Crypto.
async function aesGcmEncrypt(plaintext, passphrase) {
  const enc = new TextEncoder();
  const salt = crypto.getRandomValues(new Uint8Array(16));
  const iv = crypto.getRandomValues(new Uint8Array(12));
  const baseKey = await crypto.subtle.importKey(
    'raw', enc.encode(passphrase), 'PBKDF2', false, ['deriveKey']);
  const key = await crypto.subtle.deriveKey(
    { name: 'PBKDF2', salt, iterations: 600000, hash: 'SHA-256' },
    baseKey, { name: 'AES-GCM', length: 256 }, false, ['encrypt']);
  const ct = new Uint8Array(await crypto.subtle.encrypt(
    { name: 'AES-GCM', iv }, key, enc.encode(plaintext)));
  const packed = new Uint8Array([...salt, ...iv, ...ct]); // salt(16) | iv(12) | ct+tag
  return btoa(String.fromCharCode(...packed));            // self-contained Base64
}

核心特性

默认使用 GCM 认证加密

GCM 会生成密文以及一个 128 位认证标签,因此只要有一个字节被改动,解密就会明确失败。需要与其他系统互通时,CBC 和 CTR 也只需一次点击即可切换。

自包含密文

口令模式会把随机盐、IV 和标签打包进同一个 Base64 字符串,因此解密方只需要口令即可 —— 不需要单独复制或担心遗漏其他字段。

口令或原始密钥

输入一个口令(会用 PBKDF2-HMAC-SHA256 迭代 600,000 次进行拉伸),或粘贴一个精确的 128/192/256 位密钥(十六进制或 Base64),实时的字节数徽章会确认长度是否正确。

与 OpenSSL 兼容的输出

开启 OpenSSL 模式即可生成 openssl enc 命令和 CryptoJS 都能读取的 Salted__ 格式,并实时显示等效的 CLI 命令,方便你在终端中复现。

100% 在你的浏览器中运行

每个字节都通过 Web Crypto API 在本地加密。打开「网络」面板,你会看到没有任何数据离开页面 —— 它甚至可以离线工作。

Base64 或 Hex 输出

以目标系统所需的编码复制结果,并在分段明细条中查看盐、IV、密文和标签的长度。

AES 加密示例

GCM + 口令(自包含、非确定性)

The quick brown fox jumps over the lazy dog.
盐 (16 字节) + IV (12 字节) + 密文 + 标签 (16 字节),经 Base64 编码 —— 每次运行都会得到不同的值

当模式为 GCM、密钥长度为 256、密钥类型为「口令」、口令为 hunter2 时,这句话会被加密成一个自包含的 Base64 字符串。加密两次会得到两个完全不同的结果 —— 这是有意为之。口令模式在每次加密时都会生成全新的 16 字节盐和全新的 12 字节 IV,因此相同的明文永远不会产生相同的密文,观察者也无法判断两条消息是否相同。输出下方的分段条会显示确切的结构:先是盐,然后是 IV,最后是附带 128 位 GCM 标签的密文。要解密,接收方只需要口令以及相同的模式和密钥长度 —— 盐、IV 和标签都包含在字符串内部。

与 OpenSSL 兼容的输出(CBC + 口令)

Attack at dawn!
U2FsdGVkX18AESIzRFVmd1PBwxIFQpF+VgIhTK0aDHQ=

开启「OpenSSL 兼容」模式,模式选 CBC,密钥类型选「口令」,口令为 correct-horse,KDF 选 PBKDF2,迭代次数 10,000。工具随即会生成 OpenSSL 的 Salted__ 格式:以 U2FsdGVkX1 开头的 Base64 字符串,这正是 8 字节 Salted__ 头部的 Base64 编码。由于每次都会生成一个全新的随机 8 字节盐,具体字符串每次都不同,但每一个都能在命令行用下面的命令解密:echo 'U2FsdGVkX18AESIzRFVmd1PBwxIFQpF+VgIhTK0aDHQ=' | openssl enc -d -aes-256-cbc -pbkdf2 -iter 10000 -pass pass:correct-horse -base64 -A —— 输出结果是 Attack at dawn!。若要匹配 CryptoJS 或 OpenSSL 1.0.2 及更早版本,请选择 EVP-MD5 而不是 PBKDF2。注意 openssl enc 不支持 GCM,因此 OpenSSL 模式仅支持 CBC。

如何用 AES 加密文本

  1. 1

    选择模式和密钥长度

    将模式保留为 GCM(推荐),密钥长度保留为 256,这是最合理的强安全默认值。只有当你要对接的系统要求时才切换到 CBC 或 CTR。

  2. 2

    选择口令或原始密钥

    将密钥类型保留为「口令」并输入一个强口令,或者切换到「原始密钥」并粘贴一个精确的 128/192/256 位密钥(十六进制或 Base64)。字节数徽章会确认你的原始密钥长度是否有效。

  3. 3

    输入要加密的文本

    输入或粘贴你的明文。加密会随着你的输入自动进行,完全在浏览器中运行 —— 无需点击按钮,也不会上传任何数据。

  4. 4

    复制自包含的密文

    右侧的 Base64 结果已经包含了盐、IV 和认证标签。使用分段条查看字节结构,然后点击「复制」。如果目标系统需要十六进制格式,可将输出编码切换为 Hex。

  5. 5

    需要时再解密回来

    把密文、口令以及相同的模式和密钥长度提供给接收方,或者打开 AES 解密页面自己反向解密。

常见的 AES 加密错误

把口令和原始密钥搞混

原始密钥必须恰好是 16、24 或 32 字节的随机数据(以十六进制或 Base64 输入);口令则可以是任意文本,必须先经过 KDF 拉伸。选择「原始密钥」却粘贴一段人类可读的口令,要么因长度不对而报错,要么会产生一个薄弱的密钥。

✗ 错误
Key type: Raw key
Key (hex): correct horse battery staple   (not hex, not 32 bytes)
✓ 正确
Key type: Passphrase
Passphrase: correct horse battery staple   (stretched with PBKDF2)

对同一密钥重复使用 IV

在给定密钥下,IV 必须对每条消息都是唯一的。重复使用它对 GCM 是致命的(可能泄露认证密钥),也会破坏 CBC 和 CTR 的机密性。让工具每次都生成一个全新的随机 IV。

✗ 错误
// same key, same IV for two messages
encrypt(key, iv, a); encrypt(key, iv, b);
✓ 正确
// fresh random IV each time (the default)
encrypt(key, randomIV(), a);

丢失了盐、IV 或标签

如果你只复制了密文字节,丢掉了前面拼接的盐/IV —— 或后面附加的 GCM 标签 —— 数据就永远无法解密。请保留完整的自包含字符串,而不只是其中的一部分。

✗ 错误
stored = ciphertext              // salt + IV + tag thrown away
✓ 正确
stored = salt + iv + ciphertext + tag   // the full Base64 string

以为 GCM 每次输出都应该一样

GCM(以及一般的口令模式)使用随机的盐和 IV,因此相同的文本每次加密都会得到不同的 Base64 字符串。这是一项安全特性,而不是缺陷 —— 它意味着窃听者无法判断两段密文是否加密的是同一条消息。

✗ 错误
assert(encrypt(msg) === encrypt(msg))   // fails — and should
✓ 正确
assert(decrypt(encrypt(msg)) === msg)   // this is what must hold

AES 加密能做什么

了解 AES 各模式的行为
用相同的输入在 GCM、CBC 和 CTR 之间切换,观察认证方式、IV 长度和密文大小如何变化 —— 这是理解 NIST SP 800-38D 具体规定内容的实践方式。
生成其他系统可读取的密文
以 OpenSSL 的 Salted__ 格式(或原始密钥加 IV 的形式)生成输出,让使用 openssl 或加密库的后端、脚本或队友可以毫无阻碍地解密它。
加密一段简短的笔记或片段
用只有你自己知道的口令保护一次性的个人文本 —— 比如在设备间迁移的恢复助记词,或工单里的一段片段。不适合受监管或生产环境的机密。
为加密格式做原型验证
在编写代码之前,先在这里确定好盐/IV/标签的排布和 KDF 设置,用分段明细来确认字节顺序和长度。
生成测试向量
用固定的口令和模式生成已知密文,用于你自己的解密测试,然后在 AES 解密页面验证往返是否正确。

AES 模式与密钥派生

GCM(Galois/Counter 模式)—— 带认证,推荐使用
在机密性之外还带有 128 位认证标签(NIST SP 800-38D)。它使用 96 位(12 字节)的 IV,每次加密都随机生成,加密和解密都能很好地并行化。有一条规则绝不能打破:绝不能对同一密钥重复使用 IV。SP 800-38D 将单个密钥限制为约 2^32 个随机生成的 IV,一旦重复,就会泄露两段明文的异或结果,甚至可能暴露保护标签的认证密钥。适合几乎所有场景。
CBC(密码分组链接)—— 仅提供机密性
每个分组都会与前一个密文分组进行异或运算,使用一个随机的 16 字节 IV。它没有内置认证,因此必须搭配单独的 MAC —— 先加密后 MAC,例如使用我们的 HMAC 生成器 —— 而且历史上容易受到填充预言机攻击(Vaudenay,EUROCRYPT 2002)。提供此模式是为了与 OpenSSL 和老旧系统互通。
CTR(计数器模式)—— 仅提供机密性,类似流密码
通过加密一个计数器,把 AES 变成流密码,因此任意字节长度都无需填充即可处理,各分组也能自由并行。和 CBC 一样,它本身不提供完整性保护,在同一密钥下重复使用计数器/IV 是灾难性的。适合需要随机访问或流式语义的场景。
ECB —— 未提供(刻意如此)
电子密码本模式独立加密每个分组,因此相同的明文分组会产生相同的密文,模式会因此泄露 —— 这就是臭名昭著的「ECB 企鹅」。Web Crypto API 刻意没有实现它,我们也是如此。如果某个老旧的对端要求使用 ECB,应该把它当作需要修复的问题,而不是需要复现的格式。
密钥派生:600,000 次 vs 10,000 次 vs 1 次迭代
在默认的口令模式下,本工具按照 OWASP 的建议使用 PBKDF2-HMAC-SHA256、迭代 600,000 次(相当于把同一个 SHA-256 哈希应用数十万次)并配合一个 16 字节的盐。在 OpenSSL 兼容模式下,PBKDF2 默认只迭代 10,000 次(openssl enc 的默认值),而 CryptoJS 和旧版 OpenSSL 使用的传统 EVP_BytesToKey KDF 只运行一次 MD5 —— 强度低了几个数量级。迭代次数越多,每次猜测的暴力破解速度就越慢,这也是现代默认值大幅提高的原因。Argon2 和 scrypt 更强,但不属于 Web Crypto 的一部分,因此不在本工具的范围内;对于密码存储,请遵循 OWASP 的建议,优先选择 Argon2id。

AES 加密最佳实践

优先选择 GCM,除非对端另有要求
认证加密能捕获 CBC 和 CTR 会悄悄放过的篡改。只有在需要互通时才降级到 CBC 或 CTR,如果这样做,请务必加上 MAC。
为每条消息使用全新的随机 IV
本工具会自动完成这一点。如果你手动覆盖 IV,切勿对同一密钥重复使用同一个 IV —— 对 GCM 而言重复是灾难性的,对 CBC 而言会破坏语义安全性。
选择强口令和真正随机的密钥
PBKDF2 能减慢暴力破解,但无法挽救一个薄弱的口令。用我们的密码生成器生成一个较长的口令,或用密钥生成器生成真正随机的密钥。
把盐、IV 和标签与密文放在一起
它们不是秘密,但没有它们解密就会失败。本工具的自包含格式已经把三者都打包在一起;如果你使用原始密钥的裸密文模式,请单独复制 IV,并把它和密文一起保存。
不要在任何在线工具中加密生产环境或受监管的机密
即便完全在客户端运行,浏览器工具也只适合学习、调试和个人一次性用途。真正的机密应该交给经过审核、拥有审计级密钥处理和轮换机制的密钥管理系统。AES-256 本身是强健的 —— 已被 NSA CNSA 2.0 套件批准用于「绝密」级别信息 —— 现实中的破解都源自实现上的失误,而不是密码算法本身。

AES 加密常见问题

在线加密文本安全吗?
使用本工具时,加密本身完全在你的浏览器中完成 —— 你的文本、口令和密钥永远不会传到服务器,你可以打开「网络」面板自行确认这一点。这使它适合用于学习、调试和一次性的个人数据。但它不适合用于生产环境的机密、受监管的数据,或任何需要长期密钥管理的场景,这一点对任何在线工具都成立:浏览器页面无法提供经过审计的密钥存储、轮换或访问控制。请在这里加密可丢弃的内容和个人数据,把真正的机密留给专门的系统。
AES 能在没有密钥的情况下被解密吗?
不能。AES 目前没有已知的实际破解方法,因此没有密钥或口令就没有捷径可走 —— 攻击者只能一个一个地尝试密钥。AES-256 有 2^256 种可能的密钥;即使每秒尝试一万亿万亿次,要搜索有意义的一部分也需要远超宇宙年龄的时间。现实中的风险从来都不是密码算法本身:而是薄弱的口令、被重复使用的 IV、泄露的密钥,或构建糟糕的系统中的填充预言机漏洞。选一个强口令,这些风险就都不成立。任何宣称无需密钥就能「恢复 AES」的说法都是骗局。
GCM 与 CBC —— 应该用哪种模式?
用 GCM。它既提供机密性,又内置了 128 位认证标签,因此只要密文中有一个字节被改动,解密就会失败,而不是悄悄返回被破坏的数据。CBC 只隐藏数据;它本身无法检测篡改,而且长期存在填充预言机漏洞(Vaudenay,EUROCRYPT 2002),这也是 TLS 1.3(RFC 8446)移除所有 CBC 密码套件的原因。在这里选择 CBC 的唯一正当理由是与现有系统互通 —— 例如 OpenSSL 的 enc 命令,它不支持 GCM。
AES-128 与 AES-256 —— 256 位值得选吗?
两者都被认为是安全的;AES-128 没有被攻破,速度也略快一些。AES-256 密钥更长、安全余量更大,也是 NSA CNSA 2.0 套件中被批准用于「绝密」级别信息的密钥长度,这也是它成为合理默认值的原因。代价很小 —— 每个分组只多几轮运算。除非你在优化一个非常关键的性能路径,否则用 AES-256 加密即可;额外的安全余量在实践中几乎是免费的。
在这里加密时,我的数据会被上传吗?
不会。所有加密都通过浏览器的 Web Crypto API(crypto.subtle)在本地运行,这正是浏览器用于 HTTPS 的同一套经过审计的实现。你输入的任何内容都不会发往任何地方 —— 你可以打开开发者工具的「网络」面板,加密一些内容,观察到零个请求被发出,或者干脆断开网络连接,工具依然能正常工作。SubtleCrypto 只在安全(HTTPS)上下文中可用,这也是这一保证得以成立的原因之一。
口令和密钥有什么区别?
密钥恰好是 128、192 或 256 位的随机数据 —— 对 AES-256 来说就是 32 个原始字节,通常写成十六进制或 Base64。口令则是人手动输入的任意长度文本,它本身并不是密钥:必须通过密钥派生函数把它拉伸成密钥。本工具在口令模式下会自动完成这一步,使用 PBKDF2-HMAC-SHA256、600,000 次迭代和一个随机盐。把两者搞混 —— 把口令粘贴到原始密钥字段,或反过来 —— 是两个系统对不上密文最常见的原因之一。(如果你需要的是签名令牌而非加密,请参阅 JWT 编码器。)
我能加密成 OpenSSL 或 CryptoJS 可以解密的格式吗?
可以。开启「OpenSSL 兼容」模式(使用 AES-CBC 和口令),工具就会生成 openssl enc 命令和 CryptoJS 都能理解的 Salted__ 格式,并显示与之完全对应的 openssl 命令。选择匹配的密钥派生函数:现代 OpenSSL 用 PBKDF2(openssl -pbkdf2 默认迭代 10,000 次),没有 -pbkdf2 的 OpenSSL 1.1+ 用 EVP-SHA256,CryptoJS 和 OpenSSL 1.0.2 及更早版本用 EVP-MD5。如果要反过来读取别人的密文,请使用 AES 解密工具