为什么这两个bash命令的输出不同?

时间:2016-05-10 21:15:27

标签: bash openssl

为什么......

KEY=$(echo -ne "\x2e\x9e\x93\x83\x8c\xf5\xeb\x78\x2f\x9e\xd7\xbe\xaa\x27\xf6\x1f\xa5\x35\xe3\x37\x4c\x78\x22\xc9\x11\x24\x20\x22\xa6\x3e\x28\x30")
echo -e "$(echo -en aws4_request | openssl dgst -sha256 -hmac "$KEY" -binary | xxd)"

...产生

0000000: d77d 4050 8184 cbd2 44f0 f6c2 5b95 39d0  .}@P....D...[.9.
0000010: d9b4 bf25 a7ec a4f8 0dac cc00 6b2b 67d4  ...%........k+g.

和...

echo -ne "$(echo -en aws4_request | openssl dgst -sha256 -hmac "$KEY" -binary)" | xxd

产生(注意,与第一个输出相比,缺少字节28)?

0000000: d77d 4050 8184 cbd2 44f0 f6c2 5b95 39d0  .}@P....D...[.9.
0000010: d9b4 bf25 a7ec a4f8 0dac cc6b 2b67 d4    ...%.......k+g.

据我所知,openssl的输出通过子管道输出到xxd并不重要。

2 个答案:

答案 0 :(得分:4)

由于其强大的C基础,UNIX字符串无法容纳NUL '\0'个字符。如果要处理可能具有00字节的原始二进制数据,则需要避免将结果存储在字符串中。在文件和管道中有00个字节是安全的。

echo -e "$(echo -en aws4_request | openssl dgst -sha256 -hmac "$KEY" -binary | xxd)"

这里openssl使用嵌入的00字节吐出二进制数据。由于您将该输出直接传送到xxd,因此数据保存完好,00完好无损。

echo -ne "$(echo -en aws4_request | openssl dgst -sha256 -hmac "$KEY" -binary)" | xxd

这里openssl的输出在被传送到xxd之前存储在一个字符串中。 $(...)操作会删除NUL字符,因为这些字符无法成功存储在字符串中。如果它没有将它们剥离出来,那么第一个NUL就会发出字符串结束的信号。

为了它的价值,你可以删除一层回声。 echo "$(command)"是一种编写command的复杂方式。

echo -n aws4_request | openssl dgst -sha256 -hmac "$KEY" -binary | xxd

答案 1 :(得分:2)

问题是摘要是二进制的(具体来说,它包含一个零字节),而shell将c-strings作为参数传递给它的命令(例如echo),而那些不能包含0 bytes(/ null字符)。如果你看一下丢失的字节,那就是" 00"十六进制您可以使用字符串" aws4_request888"更清楚地看到这一点:

$ KEY=$(echo -ne "\x2e\x9e\x93\x83\x8c\xf5\xeb\x78\x2f\x9e\xd7\xbe\xaa\x27\xf6\x1f\xa5\x35\xe3\x37\x4c\x78\x22\xc9\x11\x24\x20\x22\xa6\x3e\x28\x30")
$ echo -e "$(echo -en aws4_request888 | openssl dgst -sha256 -hmac "$KEY" -binary | xxd)"
0000000: 3939 a1b7 b334 22e3 7ab6 d7f0 32be 2f62  99...4".z...2./b
0000010: e353 72f9 3152 a923 a3e3 0000 0006 85fb  .Sr.1R.#........
$ echo -ne "$(echo -en aws4_request888 | openssl dgst -sha256 -hmac "$KEY" -binary)" | xxd
0000000: 3939 a1b7 b334 22e3 7ab6 d7f0 32be 2f62  99...4".z...2./b
0000010: e353 72f9 3152 a923 a3e3 0685 fb         .Sr.1R.#.....

在这种情况下,摘要有三个空字节,它们都消失了。

这里唯一真正的解决方案是避免通过shell参数,变量等传递二进制数据(也可能包括$KEY)。 (管道,另一方面,处理二进制就好了。)

如果你需要处理shell中的二进制数据,可以在存储之前将其转换为十六进制(hexvar=$(somethingthatproducesbinary | xxd -p),然后再转换为二进制文件以供使用(echo "$hexvar" | xxd -r -p | somethingthatreadsbinary)。