如何使用多个源或输入在 Bash 中创建哈希或 sha256sum?推荐的方法是什么?

如何使用多个源或输入在 Bash 中创建哈希或 sha256sum?推荐的方法是什么?

我想在 Bash 中创建多个源的哈希值。

我知道我可以:

echo -n "STRING" | sha256sum

或者

sha256sum [FILE]

我需要的是:

  1. STRING + FILE
  2. FILE + FILE
  3. STRING + STRING
  4. STRING + FILE + STRING

例如STRING + FILE

  1. 将 的哈希值保存STRING在变量中,并将 的哈希值保存[FILE]在变量中。计算并创建总和的哈希值。

  2. 将 的哈希值保存STRING在一个文件中,并将 的哈希值保存[FILE]在同一个文件中,并创建该文件的哈希值。

我可以使用单个命令创建哈希吗?

例如:echo "STRING" + [FILE] | sha256sum

我怎样才能做到这一点,推荐或正确的方法是什么?

更新

根据罗密欧·尼诺夫的回答,实施例1:

echo -n "STRING" && cat [FILE] | sha256sum

当我做:

实施例2:

echo $(echo -n "STRING" | sha256sum) $(sha256sum [FILE]) | sha256sum

我应该用什么?我得到不同的结果。实现这一目标的正确方法是什么?

答案1

您可以创建一个像这样的脚本来散列多个文件,然后对它们的散列的串联进行散列。像这样的两部分散列而不是首先连接所有数据应该可以防止混淆,因为连接会丢失输入之间边界的信息(例如ab+ c!= a+ bc)。

#!/bin/bash

# function to get the hashes
H() {
    sha256sum "$@" |
      LC_ALL=C sed '
        s/[[:blank:]].*//; # retain only the hash
        s/^\\//; # remove a leading \ that GNU sha256sum at least
                 # inserts for file names where it escapes some
                 # characters (such as CR, LF or backslash).'
}   

# workaround for command substitution removing final newlines
hashes=$(H "$@"; echo .)
hashes=${hashes%.}

# just for clarity
printf "%s\n" "----"
printf "%s" "$hashes"
printf "%s\n" "----"

# hash the hashes
final=$(printf "%s" "$hashes" | H)

echo "final hash of $# files: $final"

有两个文件的示例:

$ echo hello > hello.txt
$ echo world > world.txt
$ bash hash.sh hello.txt world.txt
----
5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
e258d248fda94c63753607f7c4494ee0fcbe92f1a76bfdac795c9d84101eb317
----
final hash of 2 files: 27201be8016b0793d29d23cb0b1f3dd0c92783eaf5aa7174322c95ebe23f9fe8

您还可以使用进程替换来插入字符串,这应该给出相同的输出:

$ bash hash.sh hello.txt <(echo world)
[...]
final hash of 2 files: 27201be8016b0793d29d23cb0b1f3dd0c92783eaf5aa7174322c95ebe23f9fe8

给相同的输入数据 ( hello\nworld\n) 不同的分隔会得到不同的哈希值:

$ bash hash.sh <(printf h) <(printf "ello\nworld\n")
[...]
final hash of 2 files: 0453f1e6ba45c89bf085b77f3ebb862a4dbfa5c91932eb077f9a554a2327eb8f

当然,改变输入文件的顺序也会改变哈希值。

输出中破折号之间的部分只是为了清楚起见,它显示了进入最终sha256sum.您可能应该将其删除以供实际使用。


上面,我曾经sedsha256sum.如果删除该| sed ...部分,文件名将被包含在内,例如hash.sh hello.txt world.txt将散列字符串

5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03  hello.txt
e258d248fda94c63753607f7c4494ee0fcbe92f1a76bfdac795c9d84101eb317  world.txt

子哈希是相同的,但最终哈希的输入不同,给出的f27b5175dec88c76dc6a7b368167cd18875da266216506e10c503a56befd7e14结果是不同的。显然,更改文件名(包括从 到hello.txt./hello.txt会更改哈希值。此外,使用进程替换在这里不太有用,因为它们会显示奇怪的依赖于实现的文件名(就像/dev/fd/63Linux 上的 Bash)。


在上面,最终哈希的输入是十六进制编码输入元素的哈希值,每个元素都以换行符结尾。我不思考您需要比这更多的分离,并且从技术上讲甚至可以删除换行符,因为无论如何散列都有固定的长度(但我们免费获得换行符,它们使人类更容易阅读)。

但请注意,它只sha256sum给出简单的哈希值。如果您正在寻找生成身份验证标签的工具,您可能应该研究 HMAC 等,并警惕长度扩展攻击(直截了当的攻击H(key + data)可能容易受到攻击)等。

根据您的用例,您可能需要考虑安全性或者加密SE,或聘请真正的专家。

答案2

在收到所有信息和评论后,我认为一种可能的解决方案如下:

  • 分别对每个源进行哈希处理。
  • 避免连接源,除非它们事先已单独散列。
  • 对源进行哈希处理时,请考虑使用分隔符或盐。
  • 对于进一步的处理和存储,例如在带有区块的分类账中,最好的方法是使用哈希树(Merkle 哈希树),类似于当前大多数私有和公共区块链的操作方式。

例子:

相同的哈希结果:

HASH_OF((abc) + (def))

HASH_OF((ab) + (cdef))

HASH_OF((abcde) + (f))

不同的哈希结果:

HASH_OF( (HASH_OF(abc)) + (HASH_OF(def)) )

HASH_OF( (HASH_OF(ab)) + (HASH_OF(cdef)) )

HASH_OF( (HASH_OF(abcde)) + (HASH_OF(f)) )

我目前的方法,结合分隔符/盐,如下:

HASH_OF( (HASH_OF(abcde + [delimters/salt])) + (HASH_OF(f + [delimters/salt])) )

我将继续并扩展这个示例以满足我的特定要求。

如果用脚本来实现会更方便、更清晰。

echo $(echo -n "STRING1" | sha256sum)$(echo -n "STRING2" | sha256sum) | sha256sum

相关内容