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

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

このコミットは、Go言語のcrypto/ecdsaパッケージにおける楕円曲線デジタル署名アルゴリズム(ECDSA)の実装に対して、米国国立標準技術研究所(NIST)が提供する包括的なテストベクターを追加するものです。これにより、ECDSAの実装がNISTの標準に準拠していることを検証し、その堅牢性と正確性を向上させます。具体的には、既存のテストファイルecdsa_test.goを修正し、NISTの署名検証テストスイートであるSigVer.rsp.bz2を読み込み、解析し、検証するロジックが追加されています。

コミット

commit 5759c6022c7d5fe43357fc69b5b0b2eec28c01a9
Author: Adam Langley <agl@golang.org>
Date:   Tue May 22 10:33:14 2012 -0400

    crypto/ecdsa: add full set of NIST test vectors.
    
    This includes the NIST test suite for ECDSA and alters the test to
    parse and evaluate it.
    
    R=golang-dev, bradfitz, rsc, b
    CC=golang-dev
    https://golang.org/cl/6219058

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

https://github.com/golang/go/commit/5759c6022c7d5fe43357fc69b5b0b2eec28c01a9

元コミット内容

このコミットは、crypto/ecdsaパッケージにNIST(米国国立標準技術研究所)の完全なテストベクターセットを追加します。これには、ECDSAのNISTテストスイートが含まれており、テストコードがそれを解析し評価するように変更されています。

変更の背景

暗号ライブラリの正確性とセキュリティは極めて重要です。特に、デジタル署名アルゴリズムのような基盤となるコンポーネントは、厳格なテストと検証が必要です。NISTは、暗号アルゴリズムの実装が正しく機能し、標準に準拠していることを確認するためのテストベクターを提供しています。

このコミットの背景には、Go言語のcrypto/ecdsaパッケージが、NISTによって定義されたECDSAの標準実装として信頼できることを保証するという目的があります。以前のテストは、おそらく限定的なテストケースしかカバーしていなかったため、より広範で公式なテストベクターを導入することで、実装の堅牢性を大幅に向上させることができます。これにより、将来的なバグの混入を防ぎ、Go言語の暗号ライブラリの信頼性を高めることが期待されます。

前提知識の解説

ECDSA (Elliptic Curve Digital Signature Algorithm)

ECDSAは、楕円曲線暗号(ECC)を利用したデジタル署名アルゴリズムです。デジタル署名は、メッセージの認証、完全性、否認防止を提供するために使用されます。

  • 認証: メッセージが正当な送信者によって作成されたことを確認します。
  • 完全性: メッセージが送信中に改ざんされていないことを保証します。
  • 否認防止: 送信者がメッセージの送信を後で否認できないようにします。

ECDSAは、従来のRSAなどのデジタル署名アルゴリズムと比較して、同等のセキュリティレベルをより短い鍵長で実現できるため、計算量、ストレージ、帯域幅の面で効率的です。これは、モバイルデバイスやリソースが限られた環境での利用に適しています。

ECDSAの署名プロセスは以下のステップを含みます。

  1. メッセージのハッシュ値を計算します。
  2. 秘密鍵とランダムな数値(k値)を使用して、署名(2つの整数rsのペア)を生成します。

署名検証プロセスは以下のステップを含みます。

  1. 署名者の公開鍵、メッセージ、および署名(r, s)を使用して、一連の楕円曲線計算を実行します。
  2. 計算結果が特定の曲線上の点と一致する場合、署名は有効と見なされます。

NIST (National Institute of Standards and Technology)

NISTは、米国商務省に属する非規制機関であり、測定科学、標準、技術においてイノベーションと産業競争力を促進することを目的としています。暗号分野においては、FIPS(Federal Information Processing Standards)として知られる連邦情報処理標準を策定し、暗号アルゴリズムの安全性と相互運用性を確保するためのガイドラインとテストベクターを提供しています。NISTの標準は、世界中の政府機関や企業で広く採用されています。

NIST Test Vectors

NISTテストベクターは、暗号アルゴリズムの実装がNISTの標準に準拠していることを検証するために使用される一連の入力と期待される出力のペアです。これらのテストベクターは、アルゴリズムの各ステップが正しく実行され、期待される結果が生成されることを確認するために設計されています。

  • SigVer.rspファイル: これは、NISTの暗号アルゴリズム検証プログラム(CAVP)で使用される応答ファイルの一種です。特にデジタル署名検証のために使用されます。実装が提供された署名を検証し、その結果(成功または失敗)をこのファイルに記録します。NISTは、この応答ファイルを処理して実装の正確性を評価します。

bzip2

bzip2は、Julian Sewardによって開発されたフリーでオープンソースのデータ圧縮フォーマットです。単一ファイルの圧縮に特化しており、複数のファイルをアーカイブする機能は持っていません(ZIPやTARとは異なります)。そのため、複数のファイルを圧縮する場合は、通常tarなどのアーカイブツールと組み合わせて使用され、.tar.bz2.tbz2といった拡張子になります。

bzip2は、Burrows-Wheeler変換(BWT)とそれに続くMove-to-Front変換、ハフマン符号化を利用して高い圧縮率を実現します。データは通常100KBから900KBのブロックで処理されます。このコミットでは、NISTのテストベクターファイルがSigVer.rsp.bz2として圧縮されているため、Goのテストコード内でこの形式を解凍する機能が必要となります。

技術的詳細

このコミットの主要な変更は、src/pkg/crypto/ecdsa/ecdsa_test.goファイルにあります。既存のテストコードは、ハードコードされた少数のテストベクターを使用していましたが、この変更により、外部の圧縮されたNISTテストベクターファイルtestdata/SigVer.rsp.bz2を読み込み、動的にテストを実行するようになりました。

新しいテストロジックは、以下の主要なステップで構成されます。

  1. テストデータの読み込みと解凍:

    • os.Open("testdata/SigVer.rsp.bz2")を使用して、圧縮されたテストベクターファイルを開きます。
    • bzip2.NewReader(f)を使用して、bzip2形式のデータを解凍するためのリーダーを作成します。
    • bufio.NewReaderでバッファリングされたリーダーをラップし、効率的な行単位の読み込みを可能にします。
  2. テストベクターの解析:

    • ファイルは行ごとに読み込まれ、各行はテストベクターの異なる要素(曲線タイプ、ハッシュアルゴリズム、メッセージ、公開鍵のX/Y座標、署名R/S値、期待される結果)を表します。
    • [P-XXX,SHA-YYY]形式の行は、使用する楕円曲線(P-224, P-256, P-384, P-521)とハッシュアルゴリズム(SHA-1, SHA-224, SHA-256, SHA-384, SHA-512)を設定します。
    • Msg = , Qx = , Qy = , R = , S = , Result = で始まる行は、それぞれメッセージ、公開鍵のX座標、公開鍵のY座標、署名R値、署名S値、および期待される検証結果(P for Pass, F for Fail)を抽出します。これらの値は16進数文字列としてエンコードされているため、hex.DecodeStringfromHex*big.Intに変換するヘルパー関数)を使用してデコードされます。
  3. 署名検証の実行:

    • 解析されたメッセージ、公開鍵、署名値を使用して、ecdsa.Verify関数が呼び出されます。
    • Verify関数に渡すメッセージのハッシュ値は、設定されたハッシュアルゴリズム(SHA-1, SHA-256, SHA-512など)を使用して計算されます。
    • Verify関数の戻り値(trueまたはfalse)は、テストベクターで指定された期待される結果と比較されます。
  4. エラーハンドリングとテスト結果の報告:

    • ファイルの読み込みエラー、解析エラー、および署名検証の不一致は、t.Fatalfまたはt.Errorfを使用して報告され、テストの失敗を示します。
    • testing.Short()がチェックされ、go test -shortが実行された場合はテストがスキップされます。これは、NISTテストベクターが非常に大規模であり、通常の開発サイクルで毎回実行するには時間がかかりすぎる可能性があるためです。

この変更により、GoのECDSA実装は、NISTの厳格なテストスイートに対して自動的に検証されるようになり、その信頼性と標準準拠が大幅に向上します。

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

このコミットで変更された主要なファイルは以下の通りです。

  • src/pkg/crypto/ecdsa/ecdsa_test.go: 既存のテストファイルが大幅に修正され、NISTテストベクターを読み込み、解析し、検証するロジックが追加されました。
  • src/pkg/crypto/ecdsa/testdata/SigVer.rsp.bz2: 新しく追加されたファイルで、NISTのECDSA署名検証テストベクターがbzip2形式で圧縮されて含まれています。

コアとなるコードの解説

ecdsa_test.goTestVectors関数が全面的に書き換えられています。

func TestVectors(t *testing.T) {
	// This test runs the full set of NIST test vectors from
	// http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip
	//
	// The SigVer.rsp file has been edited to remove test vectors for
	// unsupported algorithms and has been compressed.

	if testing.Short() {
		return
	}

	f, err := os.Open("testdata/SigVer.rsp.bz2")
	if err != nil {
		t.Fatal(err)
	}

	buf := bufio.NewReader(bzip2.NewReader(f))

	lineNo := 1
	var h hash.Hash // 現在のハッシュアルゴリズム
	var msg []byte
	var hashed []byte
	var r, s *big.Int
	pub := new(PublicKey) // 現在の公開鍵

	for {
		line, err := buf.ReadString('\n')
		if len(line) == 0 {
			if err == io.EOF {
				break // ファイルの終端に到達
			}
			t.Fatalf("error reading from input: %s", err)
		}
		lineNo++
		// Windowsの改行コード(\r\n)を考慮し、末尾の\r\nを削除
		if !strings.HasSuffix(line, "\r\n") {
			t.Fatalf("bad line ending (expected \\r\\n) on line %d", lineNo)
		}
		line = line[:len(line)-2]

		if len(line) == 0 || line[0] == '#' {
			continue // 空行またはコメント行はスキップ
		}

		if line[0] == '[' { // セクションヘッダーの解析 (例: [P-256,SHA-256])
			line = line[1 : len(line)-1]
			parts := strings.SplitN(line, ",", 2)

			switch parts[0] { // 楕円曲線の設定
			case "P-224":
				pub.Curve = elliptic.P224()
			case "P-256":
				pub.Curve = elliptic.P256()
			case "P-384":
				pub.Curve = elliptic.P384()
			case "P-521":
				pub.Curve = elliptic.P521()
			default:
				pub.Curve = nil // 未サポートの曲線
			}

			switch parts[1] { // ハッシュアルゴリズムの設定
			case "SHA-1":
				h = sha1.New()
			case "SHA-224":
				h = sha256.New224()
			case "SHA-256":
				h = sha256.New()
			case "SHA-384":
				h = sha512.New384()
			case "SHA-512":
				h = sha512.New()
			default:
				h = nil // 未サポートのハッシュ
			}
			continue
		}

		if h == nil || pub.Curve == nil {
			continue // 曲線またはハッシュが未設定の場合はスキップ
		}

		switch { // 各テストベクター要素の解析
		case strings.HasPrefix(line, "Msg = "):
			if msg, err = hex.DecodeString(line[6:]); err != nil {
				t.Fatalf("failed to decode message on line %d: %s", lineNo, err)
			}
		case strings.HasPrefix(line, "Qx = "):
			pub.X = fromHex(line[5:])
		case strings.HasPrefix(line, "Qy = "):
			pub.Y = fromHex(line[5:])
		case strings.HasPrefix(line, "R = "):
			r = fromHex(line[4:])
		case strings.HasPrefix(line, "S = "):
			s = fromHex(line[4:])
		case strings.HasPrefix(line, "Result = "): // 署名検証の実行と結果の比較
			expected := line[9] == 'P' // 'P'ならtrue、'F'ならfalse
			h.Reset()
			h.Write(msg)
			hashed = h.Sum(hashed[:0]) // メッセージのハッシュ値を計算
			if Verify(pub, hashed, r, s) != expected { // 署名検証を実行し、期待値と比較
				t.Fatalf("incorrect result on line %d", lineNo)
			}
		default:
			t.Fatalf("unknown variable on line %d: %s", lineNo, line)
		}
	}
}

このコードは、SigVer.rsp.bz2ファイルからNISTテストベクターを読み込み、各テストケースに対してECDSA署名検証を実行します。

  • testing.Short(): go test -shortコマンドでテストを実行した場合に、時間のかかるテストをスキップするためのGoの標準的な慣習です。NISTテストベクターは非常に大規模であるため、このチェックは重要です。
  • bufio.NewReader(bzip2.NewReader(f)): bzip2パッケージを使用して圧縮ファイルを透過的に読み込むための設定です。
  • 行の解析ロジック: strings.HasPrefixstrings.SplitNを組み合わせて、テストベクターファイル内の異なる情報(曲線、ハッシュ、メッセージ、公開鍵、署名、結果)を抽出します。
  • fromHex関数: 16進数文字列を*big.Intに変換するヘルパー関数です。これは、公開鍵の座標や署名値が16進数で表現されているため必要です。
  • ハッシュアルゴリズムの動的な選択: switch parts[1]ブロックで、テストベクターで指定されたハッシュアルゴリズム(SHA-1, SHA-224, SHA-256, SHA-384, SHA-512)に対応するhash.Hashインターフェースの実装を動的に選択します。
  • Verify(pub, hashed, r, s): crypto/ecdsaパッケージの主要な署名検証関数を呼び出します。
  • 結果の比較: Verify関数の結果と、テストベクターで指定された期待される結果(PまたはF)を比較し、不一致があればテストを失敗させます。

この変更により、GoのECDSA実装は、NISTの厳格なテストスイートに対して自動的に検証されるようになり、その信頼性と標準準拠が大幅に向上します。

関連リンク

参考にした情報源リンク