首先:要在默认设置 AES-128-CBC 和明文 hello 上重现已发布的密文 NrjrStoGrmkLAvWaJuKtvg== 上已发布的 NrjrStoGrmkLAvWaJuKtvg==,密钥 12345678(和 不是 123456 已发布)必须应用。
网站使用PKCS7 填充。密钥使用 UTF8 编码并用 0x00 值填充到所需长度(AES 128 为 16 个字节)。在 CBC 模式中,零向量用作 IV。由于没有描述(至少我没有找到文档),这只能通过与参考实现或网站的比较来推断。
在 OpenSSL 中,密钥使用 -K 选项(以十六进制表示)指定,请参阅 here。如果应用了 IV,则必须使用 -iv 选项(也以十六进制数字)指定此 IV。所以要得到和网站一样的结果,需要在OpenSSL语句中添加:
-K 31323334353637380000000000000000 -iv 00000000000000000000000000000000
如果没有传递密钥,OpenSSL 会要求输入密码,生成一个随机的 8 字节 salt,并使用 OpenSSL 函数 EVP_BytesToKey 从 salt 和密码中派生密钥和 IV。默认情况下,使用摘要 SHA256(从 1.1.0 版本开始,包括 MD5 之前),迭代次数为 1。输出格式为Salted__ 的 ASCII 编码,后跟 8 字节盐和实际密文,所有 Base64 编码。因此密文总是以U2FsdGVkX1 开头。由于每次加密随机确定盐值,因此每次都会产生不同的密钥和 IV,从而产生不同的密文。可以使用-p 选项显示密钥和 IV。
使用密码123456(如发布)和摘要MD5,发布的OpenSSL密文U2FsdGVkX1+FBre1MZ1YDfgZRmRyt/hMogfMhYeiq8Q=可以解密为明文hello。 -p 选项也可用于解密和显示:
Key: F1A16DEEFFEE4AB705BB72C21C1F1CA2
IV: 000A7A05E99BF90C025EFE40B534E836
反之,这个密钥和IV可以直接用来加密明文hello,得到密文F819466472B7F84CA207CC8587A2ABC4。如果发布的 OpenSSL 密文 U2FsdGVkX1+FBre1MZ1YDfgZRmRyt/hMogfMhYeiq8Q= 是 Base64 解码的,并且前 16 个字节(前缀和盐)被丢弃,那么与预期相同的密文结果。
需要注意的是,OpenSSL 使用的密钥派生不是很安全,here。从 1.1.1 版开始,OpenSSL 支持 PBKDF2,但必须明确指定。