web-dev-qa-db-ja.com

SHA1を取得するさまざまな方法でさまざまな結果が得られます

私はSHA1(具体的にはGit)について学習しており、さまざまな方法で文字列のSHA1を計算して、サニティチェックを行いたいと思っていました。同じSHA1ハッシュを期待していましたが、代わりに4つの方法のうち3つから異なる結果が得られました。

>git hash-object --stdin <<< "Apple Pie"
23991897e13e47ed0adb91a0082c31c82fe0cbe5

>sha1sum <<< "blob 9\0Apple Pie"
332cd56150dc8b954c0b859bd4aa6092beafa00f  -

>printf 'blob 9\0Apple Pie' > foo.txt
>sha1sum foo.txt
9eed377bbdeb4aa5d14f8df9cd50fed042f41023  foo.txt

>openssl sha1 foo.txt
SHA1(foo.txt)= 9eed377bbdeb4aa5d14f8df9cd50fed042f41023

このStack Overflowの質問 に対する受け入れられた回答は、git hash-objectは、「blob [ファイルサイズ]/0」で始まる指定されたコンテンツに対してSHA1ハッシュを実行します。したがって、非gitメソッドでテストした文字列の前にそのテキストを明示的に付けました。

なぜこれらすべての異なる結果ですか? SHA1は特定の文字列の特定の一意のハッシュであり、SHA1には異なる「タイプ」はないと思いましたが、そうではありませんか?

2
StoneThrow

違いはSHA1によるものではなく、入力によるものです。 here-string構文は、odでわかるように、改行を追加します。

$ od -c <<< foo
0000000   f   o   o  \n

したがって、gitコマンドでは、入力は10文字のApple Pie\nです。

さらに、ヒア文字列で使用した二重引用符は、\n\nnnのようなバックスラッシュエスケープをサポートしていないため、<<< "blob 9\0Apple Pie"はリテラルのバックスラッシュとゼロを含む文字列を提供します。

ただし、printf\0をNULバイトとして解釈し、末尾の改行を追加しないため、改行を追加して長さを固定すると、期待される出力が得られるはずです。

$ printf 'blob 10\0Apple Pie\n' | sha1sum
23991897e13e47ed0adb91a0082c31c82fe0cbe5  -

NULバイトを表すものとして$''をサポートする\0引用符を使用して、here-stringで同じことを試みることができますが、NULバイトが文字列を終了するため、すべてのシェルで機能するとは限りません。 。例えば。 Bashはそれを処理できません。zshは次のことができます。

$ zsh -c "sha1sum <<< $'blob 10\0Apple Pie'"
23991897e13e47ed0adb91a0082c31c82fe0cbe5  -
4
ilkkachu