【问题标题】:String -> SHA -> base64, 3 ways and 3 different results via cmd tools (openssl/xxd/base64) why?String -> SHA -> base64,通过 cmd 工具(openssl/xxd/base64)的 3 种方式和 3 种不同的结果,为什么?
【发布时间】:2020-04-15 02:46:24
【问题描述】:
method1:
$echo -n "The quick brown fox jumps over the lazy dog" | openssl sha1 | base64
MmZkNGUxYzY3YTJkMjhmY2VkODQ5ZWUxYmI3NmU3MzkxYjkzZWIxMgo=

method2:
$ echo -n "The quick brown fox jumps over the lazy dog" | openssl sha1 | xxd -r -p | base64
L9ThxnotKPzthJ7hu3bnORuT6xI=

method3:
echo -n "The quick brown fox jumps over the lazy dog" | openssl sha1 | xxd -b -p | base64
MzI2NjY0MzQ2NTMxNjMzNjM3NjEzMjY0MzIzODY2NjM2NTY0MzgzNDM5NjU2NTMxNjI2MjM3MzY2NTM3CjMzMzkzMTYyMzkzMzY1NjIzMTMyMGEK

我基本上是在尝试通过 sha1 对输入字符串 The quick brown fox jumps over the lazy dog 进行校验和作为校验和,然后对结果进行 base64,我有上面两种方法,我认为 method2 是正确的答案,但我必须采取额外的步骤要通过xxd -r 和普通格式-p 将十六进制转换回二进制,然后再将其输入base64,为什么我必须做这个额外的步骤?

我在任何地方都找不到 base64 cmd 工具期望输入是二进制的?但是假设当我将其显式转换为二进制并通过mehod3 xxd -b option 将其提供给base64 时,结果再次不同。

如果使用编程语言 bcos 可能会更容易,因为我们可以完全控制但通过一些 cmd 工具会有点混乱,有人可以帮我解释一下吗?

【问题讨论】:

  • 如果没有-d 选项,base64 会对其输入进行编码。
  • 我知道并且我没有对base64 bcos 使用任何选项,因为我只想编码。当我在上面说选项时,主要是针对xxd
  • 所有数据都是二进制的; text 只是表示文本编码(ASCII、UTF-8 等)的字节流。 base64xxd,在某种意义上,以不同的方式做同样的事情:提供任意二进制数据的 ASCII 表示。
  • @chepner 是的,我知道,但我想知道 base64 cmd 工具将如何集成编码的字符串,它会假定它是字符串中的十六进制还是字符串或 ASCII 字符串中的二进制。

标签: bash openssl base64 sha xxd


【解决方案1】:

这里有三个不同的结果,因为您将三个不同的字符串传递给base64

根据您对base64 的问题,期望输入是二进制的,@chepner 就在这里:

所有数据都是二进制的; text 只是表示文本编码(ASCII、UTF-8 等)的字节流。

中间步骤

为了清楚起见,让我们将共享命令存储在一个变量中。

$ msg='The quick brown fox jumps over the lazy dog'
$ sha_val="$(printf "$msg" | openssl sha1 | awk '{ print $2 }')"
$ printf "$sha_val"
2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

需要注意的几点:

  • 使用 printf 因为it is more consistent,尤其是在我们比较字节和哈希时。
  • 通过管道连接到 awk '{ print $2 }' 作为 openssl may prepend(stdin)=

比较字节

我们可以使用 xxd 来比较每个字节,使用 -c 1000 来使用 1000 字符的行(即不要为

方法一

这是 sha 值的十六进制表示。例如,sha 输出中的第一个 2 在此结果中是 32,因为 hex 32 dec 50 ASCII/UTF-8 "2"。如果这令人困惑,请查看ASCII table

$ printf "$sha_val" | xxd -p -c 1000
32666434653163363761326432386663656438343965653162623736653733393162393365623132

方法2

这个输出与 $sha_val 完全相同,因为我们正在从十六进制转换为 ASCII 二进制,然后用 xxd 返回。请注意,base64 不需要将 sha 值从十六进制转换为二进制。

$ printf "$sha_val" | xxd -r -p | xxd -p -c 1000
2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

方法3

xxd 的-p 选项覆盖了-b 选项,所以xxd -b -p xxd -p

$ printf "$sha_val$" | xxd -p -c 1000 | xxd -p -c 1000
33323636363433343635333136333336333736313332363433323338363636333635363433383334333936353635333136323632333733363635333733333339333136323339333336353632333133323061

如您所见,base64 生成三个不同的字符串,因为它接收三个不同的字符串。

【讨论】:

  • 感谢您抽出宝贵的时间来回答我认为有一点很清楚,openssll 的输出是二进制编码为 ASCII/UTF8。但仍不清楚 base64 工具如何解释输入?你说它需要二进制?那么我是否可以假设 base64 会采用 ASCII?UTF8 字符串并解码为二进制并使用它们?如果是这样,哪种方法有正确的答案来获取 base64 格式的字符串 SHA1?
  • Baae64 将字节作为输入。 ASCII/utf8 之类的编码不相关(编码可能会说这是“A”或“B”,但表示它们的字节将保持不变)。第一个可能是您想要的。
  • 如果是这种情况会容易得多,因此我说This might be easier if it's in programing language bcos 我们可以简单地传入字节数组。你怎么能在这里直接将字节数组传递给 cmd 工具?在方法 1 中,它传递 SHA 的十六进制字符串格式,在方法 2 中,它传递 SHA 的二进制格式字符串。为什么你认为 method1 是正确的答案,因为你说 base64 将二进制作为输入?
  • "你怎么能在这里直接将字节数组传递给 cmd 工具?" => 你怎么知道我们不是?我们正在写入由 1 和 0 组成的字节,按字节顺序排列到标准输入文件描述符,该文件描述符将其作为输入传递给 base64
  • @Gob00st 不清楚这里的“正确”是什么意思。我已尽力解释这一点,但听起来您的要求很模糊。
猜你喜欢
  • 1970-01-01
  • 2012-02-09
  • 1970-01-01
  • 1970-01-01
  • 2020-04-15
  • 1970-01-01
  • 1970-01-01
  • 2021-05-28
  • 2019-12-16
相关资源
最近更新 更多