我有兴趣了解 OpenSSL 如何以及在何处将生成的盐插入 AES 加密数据。为什么?我在 Java 类中加密数据,需要保证我可以使用 OpenSSL 来解密它们。
例如,假设我有这个使用密码生成的加密 base64 字符串"abc":
U2FsdGVkX1+tfvgUkjErP6j2kUAVwWZzNlaAmTqhzTk=
# generated with "openssl enc -aes-256-cbc -a"
要解密它,我们可以使用:
echo U2FsdGVkX1+tfvgUkjErP6j2kUAVwWZzNlaAmTqhzTk= | openssl enc -d -a -aes-256-cbc -p
# enc -d
# decryption
# -a
# input is base64
# -aes-256-cbc
# the aes algorithm used in encryption
# -p
# print salt, key and iv params
使用密码运行此"abc"命令将导致:
salt=AD7EF81492312B3F
key=DEC1F5A1E5EAAA7DD539BBCFCEB1BB18868B974186ED056C27046ADD3A752C8B
iv =95A770DE9E0130E77C8E5D796D1B4EF5
Polaco
现在,我们知道 AES 解密数据需要密钥和初始化向量。
在 OpenSSL 的情况下,手册说密钥是从密码短语和盐生成的,初始化向量是从密钥本身派生的(如果没有手动指定)。这意味着生成的数据不需要有 IV,但它确实需要有盐,否则将永远无法正确生成解密密钥。
所以,关键是,盐在哪里以及它是如何插入到结果数据中的?对生成的数据进行一些基本分析(从 base64 解码并输出十六进制值),我们可以看到盐没有预先或附加到结果数据中,但不知何故它就在那里:
# salt: AD7EF81492312B3F
echo U2FsdGVkX1+tfvgUkjErP6j2kUAVwWZzNlaAmTqhzTk= | openssl enc -d -base64 | od -x
0000000 6153 746c 6465 5f5f 7ead 14f8 3192 3f2b
0000020 f6a8 4091 c115 7366 5636 9980 a13a 39cd
0000040
您可以看到盐"AD7E..."并不直接存在于加密数据中。看起来发生了一些转变。
看起来盐是一对一对地切换并插入数据中,从字节 #9 开始。这是一种常见的做法还是只有 OpenSSL 实现的东西?
# salt: AD7E F814 9231 2B3F
# switch pair by pair: 7EAD 14F8 3192 3F2B
# data: 6153 746c 6465 5f5f 7ead 14f8 3192 3f2b f6a8 4091 c115 7366 5636 9980 a13a 39cd
编辑
正如 Thomas Pornin 所说,这里的问题是od -x输出原始数据。因为我的电脑是 x86_64,所以数据是小端的,salt 看起来是“交换的”。我忘记了字节序是多么棘手。现在我会永远记得使用od -t x1
无论如何,我仍然想知道在第 9 个字节处插入盐是一种常见做法还是 OpenSSL 特定的实现。我还注意到第一个字节是字符Salted__