Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 18625] ファイルの概要

このコミットは、Go言語の標準ライブラリ crypto/md5 および crypto/sha1 パッケージに、Sum 関数の使用例を追加するものです。これにより、これらのハッシュ関数をより簡単に、かつ意図した通りに利用するためのコード例が提供されます。

コミット

commit c687be423cd004a74c12acfb8816e3dcca919f70
Author: Rob Pike <r@golang.org>
Date:   Mon Feb 24 10:40:55 2014 -0800

    crypto/md5,sha1: add examples for Sum
    
    LGTM=dave
    R=golang-codereviews, dave
    CC=golang-codereviews
    https://golang.org/cl/66900044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/c687be423cd004a74c12acfb8816e3dcca919f70

元コミット内容

crypto/md5,sha1: add examples for Sum
    
LGTM=dave
R=golang-codereviews, dave
CC=golang-codereviews
https://golang.org/cl/66900044

変更の背景

Go言語の標準ライブラリには、暗号学的ハッシュ関数を提供する crypto/md5crypto/sha1 といったパッケージが含まれています。これらのパッケージは、データの整合性チェックやデジタル署名など、様々なセキュリティ関連の用途で利用されます。

ハッシュ関数を使用する一般的なパターンとして、New() 関数でハッシュインターフェース(hash.Hash)のインスタンスを作成し、Write() メソッドでデータを書き込み、最後に Sum() メソッドでハッシュ値を取得するという流れがあります。しかし、Go 1.0から導入された Sum() 関数は、New()Write() を組み合わせた簡潔なAPIとして提供されており、特に一度に全てのデータをハッシュ化する場合に便利です。

このコミットの背景には、Sum() 関数が提供する簡潔なAPIの存在にもかかわらず、その利用方法がドキュメントや既存の例で十分に示されていなかったという状況があります。開発者がこの便利な関数を容易に発見し、正しく利用できるようにするため、公式のExampleコードを追加する必要がありました。ExampleコードはGoのドキュメント生成ツール godoc によって自動的にテストされ、ドキュメントに埋め込まれるため、利用者がコードの動作を理解する上で非常に有効です。

前提知識の解説

暗号学的ハッシュ関数 (Cryptographic Hash Function)

暗号学的ハッシュ関数は、任意の長さの入力データ(メッセージ)を受け取り、固定長の短い出力(ハッシュ値、メッセージダイジェスト、フィンガープリントとも呼ばれる)を生成する一方向関数です。主な特性は以下の通りです。

  • 一方向性 (One-way property): ハッシュ値から元の入力データを効率的に復元することは非常に困難です。
  • 衝突耐性 (Collision resistance): 異なる2つの入力データが同じハッシュ値を生成することは非常に困難です。
  • 原像計算困難性 (Preimage resistance): 特定のハッシュ値を持つ入力データを効率的に見つけることは非常に困難です。
  • 第2原像計算困難性 (Second preimage resistance): 特定の入力データと同じハッシュ値を持つ別の入力データを効率的に見つけることは非常に困難です。

これらの特性により、ハッシュ関数はデータの改ざん検出、パスワードの保存、デジタル署名、ブロックチェーンなど、多岐にわたるセキュリティアプリケーションで利用されます。

MD5 (Message-Digest Algorithm 5)

MD5は、1991年にロナルド・リベストによって設計されたハッシュ関数です。128ビット(16バイト)のハッシュ値を生成します。かつては広く利用されていましたが、現在では衝突攻撃に対する脆弱性が発見されており、セキュリティが重要な用途(特にデジタル署名など)での使用は推奨されていません。しかし、ファイルの整合性チェックなど、セキュリティ要件が比較的低い用途では依然として使用されることがあります。

SHA-1 (Secure Hash Algorithm 1)

SHA-1は、アメリカ国家安全保障局(NSA)によって設計されたハッシュ関数で、160ビット(20バイト)のハッシュ値を生成します。MD5と同様に、かつては広く利用されていましたが、こちらも衝突攻撃に対する脆弱性が発見されており、現在ではセキュリティが重要な用途での使用は推奨されていません。より強力なSHA-2(SHA-256, SHA-512など)やSHA-3が推奨されています。

Go言語の crypto パッケージ

Go言語の標準ライブラリには、暗号学的操作をサポートする crypto パッケージ群が含まれています。

  • crypto/md5: MD5ハッシュ関数を提供します。
  • crypto/sha1: SHA-1ハッシュ関数を提供します。
  • crypto/sha256, crypto/sha512: SHA-2ファミリーのハッシュ関数を提供します。
  • crypto/rand: 暗号学的に安全な乱数ジェネレータを提供します。
  • crypto/tls: TLS (Transport Layer Security) プロトコルを実装します。

hash.Hash インターフェース

Go言語の hash パッケージは、ハッシュ関数が満たすべき共通のインターフェース hash.Hash を定義しています。

type Hash interface {
    // Write は p をハッシュ関数に書き込み、書き込まれたバイト数とエラーを返す。
    io.Writer
    // Sum は、現在のハッシュ値に b を追加し、結果のスライスを返す。
    // b が nil の場合、ハッシュ値のみを返す。
    Sum(b []byte) []byte
    // Reset はハッシュを初期状態にリセットする。
    Reset()
    // Size は、ハッシュ値のバイト数を返す。
    Size() int
    // BlockSize は、ハッシュ関数が一度に処理するブロックのバイト数を返す。
    BlockSize() int
}

crypto/md5.New()crypto/sha1.New() は、この hash.Hash インターフェースを実装した型を返します。

Sum() 関数と Sum() メソッドの違い

Goのハッシュパッケージには、Sum() という名前の関数とメソッドの両方が存在し、これが混乱の原因となることがあります。

  • hash.Hash インターフェースの Sum(b []byte) []byte メソッド: これは、hash.Hash インターフェースのメソッドであり、h.Sum(nil) のように呼び出されます。hmd5.New()sha1.New() などで作成されたハッシュインスタンスです。このメソッドは、それまでに Write() メソッドで書き込まれたデータから計算されたハッシュ値に、引数 b の内容を追加した新しいバイトスライスを返します。通常、b には nil を渡して、純粋なハッシュ値のみを取得します。

  • md5.Sum(data []byte) [Size]byte 関数 / sha1.Sum(data []byte) [Size]byte 関数: これは、crypto/md5crypto/sha1 パッケージに直接定義されている関数です。この関数は、引数 data を直接受け取り、そのデータのハッシュ値を計算して固定長の配列([16]byte for MD5, [20]byte for SHA-1)として返します。この関数は、一度に全てのデータをハッシュ化する場合に非常に簡潔に記述できます。内部的には New(), Write(), Sum(nil) を呼び出しています。

このコミットは、後者のパッケージレベルの Sum() 関数の使用例を追加するものです。

技術的詳細

このコミットは、Go言語のExampleテストの仕組みを利用して、md5.Sum() 関数と sha1.Sum() 関数の使用例を追加しています。

GoのExampleテストは、Example というプレフィックスを持つ関数として定義されます。これらの関数は、通常のテスト関数(Test プレフィックス)とは異なり、go test コマンドで実行される際に、その出力がコメントとして記述された Output: 行と一致するかどうかが検証されます。これにより、コード例が常に正しく動作し、ドキュメントと同期していることが保証されます。

crypto/md5/example_test.go への追加

ExampleSum() 関数が追加されています。

func ExampleSum() {
	data := []byte("These pretzels are making me thirsty.")
	fmt.Printf("%x", md5.Sum(data))
	// Output: b0804ec967f48520697662a204f5fe72
}

この例では、md5.Sum() 関数に直接バイトスライスを渡し、その結果を16進数文字列として出力しています。Output: コメントは、期待されるMD5ハッシュ値を示しています。

crypto/sha1/example_test.go への追加

ExampleSum() 関数が追加されています。

func ExampleSum() {
	data := []byte("This page intentionally left blank.")
	fmt.Printf("% x", sha1.Sum(data))
	// Output: af 06 49 23 bb f2 30 15 96 aa c4 c2 73 ba 32 17 8e bc 4a 96
}

同様に、sha1.Sum() 関数にバイトスライスを渡し、その結果をスペース区切りの16進数文字列として出力しています。Output: コメントは、期待されるSHA-1ハッシュ値を示しています。

また、既存の ExampleNew() 関数も修正されています。

// 変更前
// io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")

// 変更後
io.WriteString(h, "His money is twice tainted:")
io.WriteString(h, " 'taint yours and 'taint mine.")

これは、長い文字列を io.WriteString で一度に書き込むのではなく、2つの部分に分割して書き込むように変更されています。機能的な変更はありませんが、Exampleコードの可読性や、io.WriteString を複数回呼び出す場合の動作を示すための調整と考えられます。

これらのExampleコードは、godoc コマンドで生成されるドキュメントに自動的に組み込まれ、Goの公式ドキュメントサイト (pkg.go.dev) などで参照できるようになります。これにより、開発者はこれらのハッシュ関数の Sum 関数をどのように使用すればよいかを、実際の動作するコード例を通じて簡単に学ぶことができます。

コアとなるコードの変更箇所

--- a/src/pkg/crypto/md5/example_test.go
+++ b/src/pkg/crypto/md5/example_test.go
@@ -17,3 +17,9 @@ func ExampleNew() {
 	fmt.Printf("%x", h.Sum(nil))
 	// Output: e2c569be17396eca2a2e3c11578123ed
 }
+
+func ExampleSum() {
+	data := []byte("These pretzels are making me thirsty.")
+	fmt.Printf("%x", md5.Sum(data))
+	// Output: b0804ec967f48520697662a204f5fe72
+}
diff --git a/src/pkg/crypto/sha1/example_test.go b/src/pkg/crypto/sha1/example_test.go
index 25fe5f3085..42aec8afa2 100644
--- a/src/pkg/crypto/sha1/example_test.go
+++ b/src/pkg/crypto/sha1/example_test.go
@@ -12,7 +12,14 @@ import (
 
 func ExampleNew() {
 	h := sha1.New()
-	io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
+	io.WriteString(h, "His money is twice tainted:")
+	io.WriteString(h, " 'taint yours and 'taint mine.")
 	fmt.Printf("% x", h.Sum(nil))
 	// Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd
 }
+
+func ExampleSum() {
+	data := []byte("This page intentionally left blank.")
+	fmt.Printf("% x", sha1.Sum(data))
+	// Output: af 06 49 23 bb f2 30 15 96 aa c4 c2 73 ba 32 17 8e bc 4a 96
+}

コアとなるコードの解説

src/pkg/crypto/md5/example_test.go の変更

  • ExampleSum() 関数が追加されました。
    • data := []byte("These pretzels are making me thirsty."): ハッシュ化する対象のバイトスライスを定義しています。
    • fmt.Printf("%x", md5.Sum(data)): md5.Sum() 関数を呼び出し、data のMD5ハッシュ値を計算しています。%x フォーマット指定子により、結果は16進数文字列として出力されます。
    • // Output: b0804ec967f48520697662a204f5fe72: この行はGoのExampleテストの特別なコメントで、上記の fmt.Printf の出力がこの文字列と完全に一致することを go test が検証します。

src/pkg/crypto/sha1/example_test.go の変更

  • 既存の ExampleNew() 関数が修正されました。
    • io.WriteString(h, "His money is twice tainted:")io.WriteString(h, " 'taint yours and 'taint mine.") の2行に分割されました。これは、長い文字列を一度に書き込むのではなく、複数回に分けて書き込む場合の io.WriteString の使用例を示すための変更です。機能的な意味合いは変わりません。
  • ExampleSum() 関数が追加されました。
    • data := []byte("This page intentionally left blank."): ハッシュ化する対象のバイトスライスを定義しています。
    • fmt.Printf("% x", sha1.Sum(data)): sha1.Sum() 関数を呼び出し、data のSHA-1ハッシュ値を計算しています。% x フォーマット指定子により、結果はスペース区切りの16進数文字列として出力されます。
    • // Output: af 06 49 23 bb f2 30 15 96 aa c4 c2 73 ba 32 17 8e bc 4a 96: md5 の例と同様に、期待される出力がコメントとして記述されています。

これらの変更により、Goのドキュメントに md5.Sum()sha1.Sum() の簡潔な使用例が追加され、開発者がこれらの関数をより容易に理解し、利用できるようになりました。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (pkg.go.dev)
  • Go言語のソースコード (特に src/pkg/crypto/md5/md5.gosrc/pkg/crypto/sha1/sha1.goSum 関数の実装)
  • Go言語のExampleテストに関する一般的な情報源 (Goブログなど)