那里openssl enc描述了命令行选项的用法。下面,我将回答你的问题,但不要忘记看一下我的文本的最后一部分,我会看看幕后发生的事情。这是有启发性的。
OpenSSL 使用加盐密钥派生算法。salt是加密时产生的一段随机字节,存放在文件头中;解密后,从标头中检索盐,并根据提供的密码和盐重新计算密钥和 IV 。
在命令行中,您可以使用-P选项(大写 P)打印 salt、key 和 IV,然后退出。您还可以使用-p(小写的 P)打印盐、密钥和 IV,然后继续进行加密。首先试试这个:
openssl enc -aes-256-cbc -pass pass:MYPASSWORD -P
如果您多次运行此命令,您会注意到每次调用都返回不同的值!这是因为,在没有标志-d的情况下,每次都会进行加密并生成随机盐。由于盐有所不同,因此密钥和 IV 也有所不同。因此,该标志在加密时不是很有用;但是,可以使用该标志。让我们再试一次; 这一次,我们有了要加密的文件。让我们运行这个:openssl enc-P-pfoo_clearfoo_enc
openssl enc -aes-256-cbc -pass pass:MYPASSWORD -p -in foo_clear -out foo_enc
此命令将加密文件(从而创建foo_enc)并打印出如下内容:
salt=A68D6E406A087F05
key=E7C8836AD32C688444E3928F69F046715F8B33AF2E52A6E67A626B586DE8024E
iv=B9F128D827203729BE52A834CC0890B7
这些值是实际用于加密文件的 salt、key 和 IV。
如果我想在之后取回它们,我可以将-Pflag 与 flag 结合使用-d:
openssl enc -aes-256-cbc -pass pass:MYPASSWORD -d -P -in foo_enc
每次都会打印与上述相同的盐、密钥和 IV。怎么会这样?那是因为这次我们在解密,所以foo_enc读取了 的头部,并检索了盐。对于给定的盐值,密码到密钥和 IV 的派生是确定性的。
此外,即使文件很长,这种 key-and-IV 检索也很快,因为该-P标志阻止了实际解密;它读取标题,但停在那里。
或者,您可以使用标志指定盐值-S,或使用 完全停用盐-nosalt。完全不建议使用无盐加密,因为它可能允许使用预先计算的表加速密码破解(相同的密码总是产生相同的密钥和 IV)。如果您提供盐值,那么您将负责生成适当的盐,即尝试使它们尽可能独特(实际上,您必须随机生成它们)。最好让openssl处理它,因为有足够的空间让静默失败(“静默”意味着“弱且可破解,但代码仍然有效,因此您在测试期间不会检测到问题”)。
OpenSSL 使用的加密格式是非标准的:它是“OpenSSL 所做的”,如果所有版本的 OpenSSL 趋于一致,那么除了 OpenSSL 源代码之外,仍然没有描述这种格式的参考文档。标头格式相当简单:
magic value (8 bytes): the bytes 53 61 6c 74 65 64 5f 5f
salt value (8 bytes)
因此有一个固定的 16 字节标头,以 string 的 ASCII 编码开头Salted__,然后是 salt 本身。就这样!没有加密算法的指示;你应该自己跟踪。
将密码和盐转换为密钥和 IV 的过程没有记录,但源代码显示它调用了 OpenSSL 特定的EVP_BytesToKey()函数,该函数使用自定义密钥派生函数 (KDF),并带有一些重复的散列。这是一个非标准且未经严格审查的构造(!),它依赖于可疑声誉的 MD5 哈希函数(!!);可以在命令行上使用未记录 -md的标志 (!!!) 更改该功能;“迭代计数”由enc命令设置为1,不能更改(!!!!)。这意味着密钥的前 16 个字节将等于MD5(password||salt),仅此而已。
这个太弱了!任何知道如何在 PC 上编写代码的人都可以尝试破解这样的方案,并且将能够每秒“尝试”数千万个潜在密码(使用 GPU 可以实现数亿个密码)。如果您使用openssl enc,请确保您的密码具有很高的熵!(即高于通常推荐的;目标是至少 80 位)。或者,最好根本不使用它;相反,选择更健壮的东西(GnuPG,在对密码进行对称加密时,使用更强大的 KDF 和底层哈希函数的多次迭代)。