很高兴您了解 CBC,因为它肯定比使用 ECB 模式加密更好(尽管也存在更好的模式,例如认证模式 GCM 和 EAX)。
我认为有几件事你应该知道,所以我将在这里解释它们。
密钥和密码不一样。通常,您使用密钥派生函数从密码中创建用于对称加密的密钥。这里讨论的最常见的是 PBKDF2(基于密码的密钥派生函数 #2),它用于 PBE(基于密码的加密)。这是 RSA 实验室在最新的开放 PKCS#5 标准中定义的。输入密码前需要检查密码是否正确翻译成字节(字符编码)。
盐用作密钥推导函数的另一个输入。它用于防止使用“彩虹表”的暴力攻击,其中密钥是为特定密码预先计算的。由于盐,攻击者不能使用预先计算的值,因为他不能为每个盐生成一个。 salt 通常应为 8 字节(64 位)或更长;使用 128 位 salt 将为您提供最佳安全性。 salt 还确保(不同用户的)相同密码不会派生相同的密钥。
密钥派生函数的输出是dkLen字节的秘密,其中dkLen是要生成的密钥的长度,以字节为单位。由于 AES 密钥不包含这些字节以外的任何内容,因此 AES 密钥将与生成的密钥相同。对于 AES 的密钥长度,dkLen 应为 16、24 或 32 字节:128、192 或 256 位。
好的,现在您终于可以使用 AES 密钥了。但是,如果您只是使用此密钥加密每个纯文本块,如果纯文本块相同,您将获得相同的结果。 CBC 模式通过在进行加密之前将下一个纯文本块与最后一个加密块进行异或运算来解决此问题。最后一个加密块是“向量”。这不适用于第一个块,因为 没有最后一个加密块。这就是为什么您需要指定第一个向量:“初始化向量”或 IV。
AES 的块大小是 16 个字节独立的密钥大小。因此,包括初始化向量在内的向量也需要为 16 个字节。现在,如果您只使用密钥进行加密,例如单个文件,则 IV 可以简单地包含 16 个字节,其值为 00h。
这不适用于多个文件,因为如果文件包含相同的文本,您将能够检测到加密文件的第一部分是相同的。这就是为什么您需要为使用密钥执行的每个加密指定不同的 IV。它包含什么并不重要,只要它是唯一的,16 个字节并且对于执行解密的应用程序是已知的。
[6 年后编辑] 上面的部分并不完全正确:对于 CBC,IV 需要对攻击者来说是不可预测的,但事实并非如此只是需要是独一无二的。因此,例如不能使用计数器。
现在有一个技巧可以让您始终对 IV 使用全零:对于您使用 AES-CBC 加密的每个纯文本,您可以使用相同的密码但使用不同的盐来计算密钥。在这种情况下,您只会将生成的密钥用于一条信息。如果您无法为实现基于密码的加密的库提供 IV,这可能是个好主意。
[EDIT] 另一个常用的技巧是使用 PBKDF2 的附加输出来导出 IV。这样就满足了官方建议,即 CBC 的 IV 不应被对手预测。但是,您应该确保不要求 PBKDF2 函数的输出超过底层哈希函数可以提供的输出。 PBKDF2 的弱点会使对手在这种情况下获得优势。因此,如果 SHA-256 用作 PBKDF2 的散列函数,则不要要求超过 256 位。请注意,SHA-1 是 PBKDF2 的常见默认值,因此只允许使用单个 128 位 AES 密钥。
IV's 和 salts 是完全独立的术语,尽管经常混淆。在您的问题中,您还将位和字节、密钥大小和块大小以及彩虹表与 MD5 表混淆(没有人说加密很容易)。有一件事是肯定的:在密码学中,尽可能安全是值得的;冗余安全通常不是问题,除非你真的(真的)负担不起额外的资源。
当您了解这一切的工作原理后,我会认真地为您找到一个执行 PBE 加密的库。您可能只需要输入密码、盐、纯数据和 - 如果单独配置 - IV。
[编辑] 你现在应该寻找一个使用 Argon2 的库。 PBKDF2 仍然被认为是安全的,但在某些情况下它确实给攻击者带来了不公平的优势,让攻击者执行的计算少于该函数的普通用户。对于 PBKDF / 密码哈希来说,这不是一个好的属性。