一句话概括
基于密码的 AES 加密是一种标准方法,它使用一个由你自选密码生成的单一密钥,来对数据进行加密和解密。
它解决了什么问题
自从人类开始写东西以来,我们就想写点别人看不懂的东西。从罗马将军在信息中移动字母(凯撒密码)到冷战时期间谍使用的一次性密码本,目标始终如一:保密。如果信息落入坏人手中,它应该是一堆乱码。
在数字时代,这个问题无处不在。你的数据飞过不靠谱的公共 Wi-Fi,存放在巨头公司拥有的服务器上,还被备份到可能最终被扔进垃圾填埋场的硬盘里。你如何确保你的私人信息、API 密钥列表或秘密饼干配方不被泄露?
老式的密码很容易被破解,特别是用上每秒能尝试数十亿次组合的计算机之后。我们需要更好的东西,好得多的东西。于是,高级加密标准(Advanced Encryption Standard,简称 AES)登场了。
在 1990 年代末,美国国家标准与技术研究院(NIST)举办了一场公开竞赛,以寻找老化的数据加密标准(DES)的替代品。他们不是在寻找政府地下室里炮制的秘密算法;他们想要一个透明、公开、经过残酷测试、全世界都能信赖的密码。经过多年的密码学界“笼中格斗”,一种名为“Rijndael”(其发明者 Rijmen 和 Daemen 名字的合成词)的比利时算法在 2001 年加冕为王。
它快速、高效,最重要的是,它顶住了全球黑客的轮番攻击。它成为了我们今天用来锁定从安全网站(HTTPS)到加密硬盘和敏感文件的所有东西的标准——AES。它用现代数学的严谨解决了古老的保密问题。
它的底层工作原理
AES 看起来就像魔法:你默念一句咒语,你的文本就变成了一团无法阅读的乱麻。再念一遍,它又回来了。但在底层,它只是一系列巧妙、可重复的数学步骤。
对称 vs. 非对称
首先,一个关键概念。加密主要有两种类型。AES 是对称的,这意味着同一个密钥既用于上锁(加密)也用于解锁(解密)。这就像你家的钥匙——它能锁门,也能用同一把钥匙开门。这种方式快速高效。
另一种类型是非对称(或公钥)加密。它使用两个不同的密钥:一个公钥用于上锁,一个私钥用于解锁。这就像一个邮箱:任何人都可以投信进去(使用公共的投信口),但只有你拥有私钥才能打开它阅读信件。当你无法预先安全地共享一个密钥时,这很棒,但它比对称加密慢得多。
基于密码的加密使用对称模型,因为你和任何需要解密数据的人都会共享相同的密码。
从密码到密钥:KDF 的角色
这里有一个关键细节:你的密码,比如“SuperSecretP@ssw0rd123”,并不是加密密钥本身。人类能记住的密码不够随机,长度也不足以成为安全的加密密钥。
相反,你的密码会被送入一个密钥派生函数(Key Derivation Function, KDF)。你可以把 KDF 想象成一个专门的算法,旨在将密码转换成一个强大的、固定大小的加密密钥。像 PBKDF2(Password-Based Key Derivation Function 2)或 Argon2 这样的现代 KDF 会做三件重要的事情:
- 加盐(Add a Salt): “盐”(salt)是在每次新加密时生成的一段随机数据。在处理密码之前,它会与你的密码混合在一起。这意味着即使两个用户有相同的密码,他们生成的加密密钥也将完全不同。这一招就挫败了“彩虹表”攻击,黑客在这种攻击中使用预先计算好的常见密码及其哈希值的表格。Salt 会和加密数据一起存储;它不是秘密,只是一个独特的配料。
- 密钥拉伸(Stretch the Key): KDF 会将密码和 salt 通过一个哈希算法(如 SHA-256)运行,不是一次,而是数千甚至数百万次。这被称为“迭代”或“工作因子”。它故意让这个过程变慢。对你来说,多等几百毫秒不算什么。但对于试图暴力破解你密码的攻击者来说,这简直是噩梦,使得尝试数十亿次猜测的计算成本变得极其高昂。
- 生成密钥(Produce the Key): 完成所有这些工作后,KDF 会吐出一个所需长度(例如 256 位)的密钥,它看起来就像纯粹的随机噪声。这才是 AES 使用的真正密钥。
你的密码 + 随机 Salt + 大量迭代 -> 强加密密钥
("hunter2" + "a3f9d..." + 100,000 轮) -> 256 位 AES 密钥
AES 密码本身:状态与轮
现在是重头戏。AES 对固定大小的数据块进行操作——每次总是 128 位(16 字节)。你的明文消息被切成这些 16 字节的块。每个块被加载到一个 4x4 的字节网格中,称为状态矩阵。
然后,这个状态会经历一系列被称为**轮(rounds)**的相同变换。轮数取决于密钥大小:
- AES-128:10 轮
- AES-192:12 轮
- AES-256:14 轮
每一轮(除了最后一轮)都包括四个步骤:
- SubBytes(字节替换): 状态矩阵中的每个字节都使用一个标准的查找表(“Rijndael S-box”)替换成另一个字节。这是引入混淆的主要非线性步骤。
- ShiftRows(行移位): 矩阵中每一行的字节都进行循环移位。第一行不移位,第二行移一位,第三行移两位,第四行移三位。这会把数据打乱。
- MixColumns(列混淆): 对每一列执行一个数学运算,将各列的字节混合在一起。这提供了扩散性,将单个明文字节的影响扩散到整个块。
- AddRoundKey(轮密钥加): 将主加密密钥的一部分(特定于此轮的“轮密钥”)与状态进行异或(XOR)运算。这就是你的秘密密钥真正混入数据的地方。
这个 SubBytes -> ShiftRows -> MixColumns -> AddRoundKey 的序列会一遍又一遍地重复。每一轮都进一步地扰乱数据,直到最后一轮结束后,状态矩阵变成一个完全混乱的密文块。要解密,你只需用相同的密钥反向运行这些步骤即可。
整合一切:密码模式和填充
AES 只知道如何加密单个 16 字节的块。那你的 500 字节的消息怎么办?这就是**工作模式(modes of operation)**发挥作用的地方。工作模式是使用块密码加密任意长度数据流的“食谱”。
像 CBC(Cipher Block Chaining)这样的旧模式存在一些安全隐患。现代推荐的模式是 GCM(Galois/Counter Mode)。GCM 是一种“认证加密”模式,用一种花哨的说法就是它能一举两得,提供两样东西:
- 机密性(Confidentiality): 它加密你的数据,所以没人能读懂。
- 真实性(Authenticity): 它会生成一个简短的“认证标签”。如果在传输过程中,密文哪怕只有一个比特被翻转或篡改,解密时标签将不匹配,整个过程会失败。这不仅告诉你数据是保密的,还告诉你它没有被动过手脚。
真实世界的故事
自由职业者的客户机密
一位用户体验设计师安雅,需要将一个尚未发布的新产品的模型图发送给她的客户。模型图文件包含敏感的品牌和战略信息。用电子邮件发送感觉有风险——电子邮件是出了名的不安全。为了这一次性的交付而去设置一个安全的文件传输门户又太小题大做了。于是,安雅用一个密码加密了包含她作品的 ZIP 文件。然后她打电话告诉客户密码。现在她可以安全地通过电子邮件发送加密文件了,知道只有客户才能打开它。
经验之谈: 对于两个人之间临时、安全地共享敏感文件,基于密码的加密是一个极好的工具,无需复杂的基础设施。
开发者的配置文件
本正在构建一个需要连接数据库并使用第三方支付 API 的 Web 应用。数据库密码和 API 密钥都存储在 config.json 文件中。他需要将代码提交到一个共享的 Git 仓库,但如果把含有明文密钥的配置文件也提交上去,将是一场灾难性的安全漏洞。所以,他加密了 config.json,生成了 config.json.enc。用于解密的密码没有存储在代码中。在开发时,他只需在本地解密该文件。在生产环境中,密码通过环境变量安全地传递给应用程序,应用程序在启动时用它来解密配置。
经验之谈: 加密配置文件可以让你安全地将“静态”密钥与代码一起存储,将秘密数据与解锁它所需的密钥分离开来。
记者在云端的笔记
玛丽亚是一名调查记者,正在处理一个敏感的报道。她把采访笔记和研究资料保存在一个同步到某流行云存储服务的文件夹里。虽然她相信该服务的安全性,但她担心潜在的威胁:云公司的流氓员工、政府传票或重大数据泄露。为了保护她的信息来源,她在将每个文档保存到同步文件夹之前,都用一个强壮、独特的密码进行了加密。现在,即使她的整个云账户被攻破,她的笔记也只是一堆无法阅读的乱码。
经验之谈: 加密提供了一层个人的“零信任”安全,确保你的数据即使存储在你无法控制的系统上,也依然保持私密。
常见错误和陷阱
- 使用弱密码。 AES-256 实际上是无法通过暴力破解攻破的。但是,从你的密码生成密钥的 KDF,如果密码是“12345”或“password”,那它就很容易受到攻击。整个系统的安全性就崩溃到你密码的强度水平。请使用长、随机且独特的密码短语。
- 忘记密码。 对于基于密码的加密,可没有“忘记密码?”这个链接。密码就是密钥。如果你弄丢了它,数据就永远丢失了。它不仅仅是被锁住了;密钥本身已经灰飞烟灭了。请将你的密码安全地存储在密码管理器中。
- 自己造轮子实现加密算法。 这是软件安全的头号大罪。你可能知道 AES、GCM 和 PBKDF2 是什么,但要安全地将它们组合在一起充满了陷阱。你为 salt 使用了加密安全的随机数生成器吗?你的认证标签处理得当吗?请始终使用你所用编程语言中备受推崇、经过同行评审的密码学库。不要自己造锁;要向锁匠大师买一把。
- 重用 salt 或 IV。 salt(用于 KDF)和 IV/nonce(用于密码模式)在每次使用相同密钥进行加密操作时都必须是随机且唯一的。重用它们可能会灾难性地破坏密码的安全性。好的库会为你处理好这些,但这是一个需要注意的陷阱。
为什么它值得你关注
如果你是开发者,你总会跟机密信息打交道。这是无法避免的。无论是数据库连接字符串、API 密钥、用户的个人信息,还是仅仅是一个敏感的日志文件,你都会有不能暴露的数据。
基于密码的 AES 是你确保静态数据机密性的首选工具。它是用于以下场景的标准、身经百战的解决方案:
- 在你的代码库中加密应用程序的机密信息。
- 在将备份发送到云存储之前对其进行保护。
- 保护数据库中的敏感数据字段(例如,在存储社会安全号码之前对其进行加密)。
- 为用户创建一个简单、安全的方式来向你发送敏感文件。
在一个数据被复制、共享和存储在数不清地方的世界里,它是让秘密之所以成为秘密的基础构建块。
深入了解
- FIPS PUB 197: NIST 官方发布的 AES (Rijndael) 标准。内容很密集,但它才是最终的权威。
- 维基百科:高级加密标准: 关于 AES 的历史、设计和安全分析的全面且高度可读的概述。
- 维基百科:PBKDF2: 深入探讨与密码一起使用的最常见的密钥派生函数。
- NIST Special Publication 800-38D: GCM 工作模式的官方规范。
- Cryptography I (Coursera/Stanford): 由 Dan Boneh 主讲的免费大学水平课程,为应用密码学提供了坚实的基础。