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

Z0O*_*0OM 0 linux command-line shell bash hashsum

我想在 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

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

更新

根据 Romeo Ninov 的回答,示例 1:

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

当我做:

实施例2:

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

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

ilk*_*chu 6

您可以创建一个像这样的脚本来散列多个文件,然后对它们的散列的串联进行散列。像这样的两部分散列而不是首先连接所有数据应该可以防止混淆,因为连接会丢失输入之间边界的信息(例如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"
Run Code Online (Sandbox Code Playgroud)

有两个文件的示例:

$ echo hello > hello.txt
$ echo world > world.txt
$ bash hash.sh hello.txt world.txt
----
5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
e258d248fda94c63753607f7c4494ee0fcbe92f1a76bfdac795c9d84101eb317
----
final hash of 2 files: 27201be8016b0793d29d23cb0b1f3dd0c92783eaf5aa7174322c95ebe23f9fe8
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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


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

5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03  hello.txt
e258d248fda94c63753607f7c4494ee0fcbe92f1a76bfdac795c9d84101eb317  world.txt
Run Code Online (Sandbox Code Playgroud)

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


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

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

根据您的用例,您可能需要考虑使用security.SEcrypto.SE,或者聘请真正的专家。