TCL 和 openssl 之间的加密兼容性

TCL 和 openssl 之间的加密兼容性

我有一个使用加密机制的 shell 脚本和一个 tcl 脚本,并且希望两个脚本都具有相同的密码输出。

例如,tcl 脚本和 shell 脚本的输出密码应该相同。我希望使用的加密机制是 AES 或 DES。(事实上,我愿意使用任何加密机制)

问题是这两个脚本都产生了不同的密文。

在 tcl 中我使用以下命令:

[aes::aes -mode cbc -dir encrypt -key 1234567891012345 hi]

在 shell 脚本中:

echo -n "hi" | openssl enc -aes-128-cbc -nosalt -pass pass:1234567891012345

我以为这两个命令的结果相同,但事实并非如此。我没有使用 salt 选项,因此如果命令执行两次,shell 脚本就会生成相同的密码。

有什么办法可以使用不同的脚本来实现相同的密文吗?

答案1

如果您指定openssl enc使用密码,则密码将始终通过 KDF 提供,而不会直接用作密钥;使用-nosalt不会禁用此功能。(您可以使用该openssl enc -p选项查看实际使用的密钥和 IV。)要指定原始密钥,您需要选项-K

(请注意,openssl enc -K预期值为以十六进制表示,同时aes::aes -key被解释为原始二进制数据。)

另一个问题是填充。由于 AES 是分组密码,所有输入数据必须填充为 16 字节(AES 块大小)的倍数,并且有多种具有不同安全属性的填充方法。Tcl 模块aes使用简单的零填充,用 0x00 字节扩展数据。

同时,OpenSSL 使用 PKCS#7 填充,并使用与填充大小匹配的值填充块。例如,如果您的输入只有 2 个字节,则需要 14 个字节的填充,因此根据 PKCS#7,每个填充字节的值也将为 14(0x0E)。

man enc谈到 PKCS#5,这是一个较旧的文档,仅定义 8 字节块的填充方案。PKCS#7 后来定义了完全相同的方案对于任何块大小

对于 CBC 模式,您还需要指定 IV(16 字节,等于 AES 块大小)。Tcl 模块默认使用全零 IV。尽管 CBC 仅对第二个和后续块使用 IV,因此它不会影响短文本的输出。

因此,总而言之,这些将给您相同的结果(使用零填充):

aes::aes -mode cbc -dir encrypt -key 1234567891012345 -hex "hi"

printf 'hi\0\0\0\0\0\0\0\0\0\0\0\0\0\0' \
  | openssl enc -aes-128-cbc -nopad \
    -K 31323334353637383931303132333435 \
    -iv 00000000000000000000000000000000 \
  | hexdump -C

这些也是(使用 PKCS#7 填充):

aes::aes -mode cbc -dir encrypt -key 1234567891012345 -hex \
         "hi\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e"

printf 'hi' \
  | openssl enc -aes-128-cbc \
    -K 31323334353637383931303132333435 \
    -iv 00000000000000000000000000000000 \
  | hexdump -C

实现填充:

set data "hi"
set pad [expr {16 - ([string length $data] % 16)}]
append data [string repeat [format %c $pad] $pad]
aes::aes -mode cbc -dir encrypt -key 1234567891012345 -hex $data

相关内容