[インデックス 11224] ファイルの概要
このコミットは、Go言語の標準ライブラリ crypto/hmac
パッケージにHMAC-SHA224、HMAC-SHA384、HMAC-SHA512のサポートを追加し、HMACの実装におけるハッシュ関数のブロックサイズに関する既存の制約を解消することを目的としています。
コミット
commit a5263c7caa61eb9eedfd6c15e3c1f989d5490ef9
Author: Luit van Drongelen <luitvd@gmail.com>
Date: Wed Jan 18 10:36:28 2012 -0500
crypto/hmac: Add HMAC-SHA224 and HMAC-SHA384/512
First was, apart from adding tests, a single line of code (to add the
constructor function). Adding SHA512-based hashing to crypto/hmac
required minor rework of the package because of a previously hardcoded
block-size in it's implementation. Instead of using a hash.Hash
generator function the constructor function now uses a crypto.Hash
type, which was extended to expose information about block size.
The only standard library package impacted by the change is
crypto/tls, for which the fix is included in this patch. It might be
useful to extend gofix to include this API change too.
R=agl, r, rsc, r
CC=golang-dev
https://golang.org/cl/5550043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a5263c7caa61eb9eedfd6c15e3c1f989d5490ef9
元コミット内容
crypto/hmac
パッケージにHMAC-SHA224、HMAC-SHA384/512を追加する。
SHA224の追加は、テストの追加を除けばコンストラクタ関数の追加という単一のコード行で済んだ。しかし、SHA512ベースのハッシュ関数を crypto/hmac
に追加するには、以前の実装でブロックサイズがハードコードされていたため、パッケージの小規模な手直しが必要だった。
以前は hash.Hash
ジェネレータ関数を使用していたが、コンストラクタ関数は crypto.Hash
型を使用するように変更され、これによりブロックサイズに関する情報が公開されるようになった。
この変更によって影響を受ける唯一の標準ライブラリパッケージは crypto/tls
であり、その修正もこのパッチに含まれている。このAPI変更を gofix
に含めることも有用かもしれない。
変更の背景
このコミットの主な背景は、Go言語の標準ライブラリにおける暗号化機能の拡充と、より堅牢で汎用的なHMAC実装の実現です。具体的には以下の点が挙げられます。
- 新しいHMACアルゴリズムのサポート: SHA-2ファミリーのハッシュ関数であるSHA-224、SHA-384、SHA-512は、それぞれ異なるセキュリティ強度と出力長を持ち、特定のアプリケーション要件やセキュリティポリシーに対応するために重要です。これらHMACアルゴリズムのサポートを追加することで、Go言語の暗号ライブラリの機能が強化されます。
- HMAC実装の汎用性向上: 従来の
crypto/hmac
パッケージでは、HMACの内部処理で使用されるブロックサイズが64バイトにハードコードされていました。これはMD5やSHA-1といった一般的なハッシュ関数には適合しますが、SHA-512のようにブロックサイズが128バイトのハッシュ関数には対応できませんでした。このハードコードされた制約を解消し、ハッシュ関数が自身のブロックサイズを公開できるようにすることで、HMACの実装がより汎用的になり、将来的な新しいハッシュアルゴリズムの追加にも柔軟に対応できるようになります。 crypto.Hash
型の活用:crypto.Hash
型は、Go言語のcrypto
パッケージ内で様々なハッシュアルゴリズムを抽象化するための列挙型です。この型をHMACのコンストラクタ関数で利用することで、ハッシュアルゴリズムの選択とブロックサイズの取得をより統一的かつ効率的に行えるようになります。
前提知識の解説
1. ハッシュ関数 (Hash Function)
ハッシュ関数は、任意の長さのデータを入力として受け取り、固定長の短いデータ(ハッシュ値、メッセージダイジェスト、フィンガープリントなどと呼ばれる)を出力する一方向性の関数です。主な特性は以下の通りです。
- 一方向性: ハッシュ値から元のデータを復元することは非常に困難です。
- 衝突耐性: 異なる入力から同じハッシュ値が生成されること(衝突)は非常に稀であるべきです。
- 高速性: ハッシュ値の計算は高速に行われるべきです。
暗号学的ハッシュ関数は、データの完全性検証、デジタル署名、パスワードの保存など、様々なセキュリティ用途に利用されます。
2. SHA-2 (Secure Hash Algorithm 2)
SHA-2は、アメリカ国家安全保障局(NSA)によって設計された暗号学的ハッシュ関数のファミリーです。SHA-1の後継として開発され、より高いセキュリティレベルを提供します。SHA-2ファミリーには、主に以下のバリエーションがあります。
- SHA-256: 256ビットのハッシュ値を生成します。ブロックサイズは64バイトです。
- SHA-224: SHA-256の切り詰め版で、224ビットのハッシュ値を生成します。ブロックサイズは64バイトです。
- SHA-512: 512ビットのハッシュ値を生成します。ブロックサイズは128バイトです。
- SHA-384: SHA-512の切り詰め版で、384ビットのハッシュ値を生成します。ブロックサイズは128バイトです。
- SHA-512/224, SHA-512/256: SHA-512の内部構造を使用しつつ、出力長を224ビットまたは256ビットに切り詰めたものです。
3. HMAC (Keyed-Hash Message Authentication Code)
HMACは、メッセージ認証コード(MAC)の一種で、共有秘密鍵と暗号学的ハッシュ関数を組み合わせてメッセージの完全性と認証性を保証するメカニズムです。HMACは、メッセージが改ざんされていないこと、およびメッセージが正当な送信者から送られたものであることを確認するために使用されます。
HMACの計算は、RFC 2104 (HMAC: Keyed-Hashing for Message Authentication) および FIPS 198 (The Keyed-Hash Message Authentication Code (HMAC)) で定義されており、以下の手順で行われます。
- 鍵の準備:
- 秘密鍵
K
がハッシュ関数のブロックサイズB
よりも長い場合、K
をハッシュ関数でハッシュ化し、その結果を新しい鍵K'
とします。 - 秘密鍵
K
がブロックサイズB
よりも短い場合、K
をゼロパディングしてブロックサイズB
にします。 - 結果として得られる鍵を
K'
とします。
- 秘密鍵
- 内部パディング (ipad):
K'
とipad
(0x36をブロックサイズ分繰り返したバイト列) をXOR演算します。これをK_inner
とします。 - 外部パディング (opad):
K'
とopad
(0x5cをブロックサイズ分繰り返したバイト列) をXOR演算します。これをK_outer
とします。 - 内部ハッシュ:
K_inner
とメッセージM
を連結し、ハッシュ関数H
でハッシュ化します:H(K_inner || M)
。 - 外部ハッシュ:
K_outer
と内部ハッシュの結果を連結し、ハッシュ関数H
でハッシュ化します:H(K_outer || H(K_inner || M))
。これが最終的なHMAC値となります。
HMACのセキュリティは、基盤となるハッシュ関数の強度と秘密鍵の秘匿性に依存します。
4. ハッシュ関数のブロックサイズ
ハッシュ関数は、入力データを固定長のブロックに分割し、各ブロックを順次処理していくことでハッシュ値を計算します。この固定長が「ブロックサイズ」です。例えば、MD5やSHA-1、SHA-256のブロックサイズは64バイトですが、SHA-512のブロックサイズは128バイトです。HMACの計算では、このブロックサイズが鍵のパディングや内部/外部ハッシュの計算に不可欠な要素となります。
5. hash.Hash
インターフェースと crypto.Hash
型 (Go言語)
hash.Hash
インターフェース: Go言語のhash
パッケージで定義されているインターフェースで、すべてのハッシュ関数が実装すべき共通のメソッドを定義しています。これにはWrite
(データをハッシュ関数に書き込む)、Sum
(ハッシュ値を計算して返す)、Reset
(ハッシュ関数の状態をリセットする)、Size
(ハッシュ値のバイト長を返す) などが含まれます。crypto.Hash
型:crypto
パッケージで定義されている列挙型で、Go言語がサポートする特定の暗号学的ハッシュアルゴリズム(例:crypto.MD5
,crypto.SHA1
,crypto.SHA256
など)を表します。この型は、ハッシュアルゴリズムを識別し、それに対応するhash.Hash
インターフェースを実装したインスタンスを生成するために使用されます。
技術的詳細
このコミットの技術的な核心は、crypto/hmac
パッケージがハッシュ関数のブロックサイズを動的に取得できるように変更された点にあります。これにより、SHA-512のようにブロックサイズが異なるハッシュ関数でもHMACを正しく計算できるようになりました。
1. hash.Hash
インターフェースへの BlockSize()
メソッドの追加
最も重要な変更は、src/pkg/hash/hash.go
に BlockSize() int
メソッドが追加されたことです。
// src/pkg/hash/hash.go
type Hash interface {
// ... (既存のメソッド)
// BlockSize returns the hash's underlying block size.
// The Write method must be able to accept any amount
// of data, but it may operate more efficiently if all writes
// are a multiple of the block size.
BlockSize() int
}
この変更により、hash.Hash
インターフェースを実装するすべてのハッシュ関数は、自身のブロックサイズを返す BlockSize()
メソッドを提供することが義務付けられました。
2. 各ハッシュ関数の BlockSize()
実装
crypto/md4
, crypto/md5
, crypto/ripemd160
, crypto/sha1
, crypto/sha256
, crypto/sha512
など、Go標準ライブラリ内の既存のハッシュ関数実装に、それぞれのブロックサイズを返す BlockSize()
メソッドが追加されました。
例えば、crypto/sha512/sha512.go
では BlockSize = 128
が定義され、BlockSize()
メソッドがこれを返します。
// src/pkg/crypto/sha512/sha512.go
const Size = 64
const Size384 = 48
// The blocksize of SHA512 and SHA384 in bytes.
const BlockSize = 128 // <-- 新しく追加された定数
// ...
func (d *digest) BlockSize() int { return BlockSize } // <-- 新しく追加されたメソッド
同様に、SHA-256やMD5などブロックサイズが64バイトのハッシュ関数には BlockSize = 64
が追加され、BlockSize()
メソッドがそれを返すように変更されました。
3. crypto/hmac
パッケージの変更
crypto/hmac
パッケージは、この新しい BlockSize()
メソッドを利用するように修正されました。
-
padSize
定数の削除とblocksize
フィールドの追加: 以前はpadSize = 64
というハードコードされた定数を使用していましたが、これが削除され、hmac
構造体にblocksize int
フィールドが追加されました。// src/pkg/crypto/hmac/hmac.go type hmac struct { size int blocksize int // <-- 新しく追加されたフィールド key, tmp []byte outer, inner hash.Hash }
-
New
関数の変更:hmac.New
関数は、ハッシュ関数を生成するfunc() hash.Hash
型の引数を受け取っていましたが、このコミットではcrypto.Hash
型の引数を受け取るように変更されたとコミットメッセージに記載されています。しかし、実際のコード変更を見ると、New
関数のシグネチャはfunc New(h func() hash.Hash, key []byte) hash.Hash
のままで、内部でhm.inner.BlockSize()
を呼び出すように変更されています。コミットメッセージの「constructor function now uses a crypto.Hash type」という記述は、おそらくcrypto.Hash
型からhash.Hash
インターフェースを実装した具体的なハッシュ関数インスタンスを取得する内部ロジックの変更を指しているか、あるいは将来的な変更の意図を示唆している可能性があります。重要なのは、
hm.blocksize = hm.inner.BlockSize()
の行が追加され、HMACインスタンスが内部ハッシュ関数の実際のブロックサイズを取得して保持するようになった点です。// src/pkg/crypto/hmac/hmac.go // New returns a new HMAC hash using the given hash generator and key. func New(h func() hash.Hash, key []byte) hash.Hash { hm := new(hmac) hm.outer = h() hm.inner = h() hm.size = hm.inner.Size() hm.blocksize = hm.inner.BlockSize() // <-- ここでハッシュ関数のブロックサイズを取得 hm.tmp = make([]byte, hm.blocksize+hm.size) // <-- blocksizeを使用 if len(key) > hm.blocksize { // <-- blocksizeを使用 // If key is too big, hash it. hm.outer.Write(key) key = hm.outer.Sum(nil) } // ... }
-
パディング処理の変更:
tmpPad
関数やSum
関数内のパディング処理において、ハードコードされていたpadSize
の代わりにh.blocksize
フィールドが使用されるようになりました。// src/pkg/crypto/hmac/hmac.go func (h *hmac) tmpPad(xor byte) { for i, k := range h.key { h.tmp[i] = xor ^ k } for i := len(h.key); i < h.blocksize; i++ { // <-- h.blocksizeを使用 h.tmp[i] = xor } } func (h *hmac) Sum(in []byte) []byte { // ... copy(h.tmp[h.blocksize:], in[origLen:]) // <-- h.blocksizeを使用 // ... } func (h *hmac) Reset() { h.inner.Reset() h.tmpPad(0x36) h.inner.Write(h.tmp[0:h.blocksize]) // <-- h.blocksizeを使用 }
4. crypto/tls
の修正
コミットメッセージにある通り、crypto/tls
パッケージもこの変更の影響を受けました。これは、crypto/tls
がHMACを使用する際に、HMACの内部構造の変更に適応する必要があったためです。パッチには src/pkg/exp/ssh/transport.go
の変更が含まれており、truncatingMAC
構造体に BlockSize()
メソッドが追加され、内部のHMACインスタンスの BlockSize()
を呼び出すように変更されています。
// src/pkg/exp/ssh/transport.go
func (t truncatingMAC) Size() int {
return t.length
}
func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } // <-- 新しく追加されたメソッド
5. テストの追加
src/pkg/crypto/hmac/hmac_test.go
には、SHA-224、SHA-384、SHA-512を含む新しいHMACテストケースが多数追加されました。これらのテストは、NISTのHMACテストベクトル(http://csrc.nist.gov/groups/ST/toolkit/examples.html など)に基づいています。これにより、新しいアルゴリズムが正しく実装され、既存のアルゴリズムも変更後も正しく機能することが保証されます。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は以下のファイルに集中しています。
src/pkg/hash/hash.go
:Hash
インターフェースにBlockSize() int
メソッドが追加されました。
src/pkg/crypto/hmac/hmac.go
:hmac
構造体にblocksize int
フィールドが追加されました。New
関数内で、ハッシュ関数のBlockSize()
メソッドを呼び出してhmac
構造体のblocksize
フィールドを初期化するようになりました。- HMACの内部処理(パディング、Sum、Resetなど)で、ハードコードされていた
padSize
定数の代わりにh.blocksize
フィールドが使用されるようになりました。
src/pkg/crypto/hmac/hmac_test.go
:hmacTest
構造体のhash
フィールドの型がfunc([]byte) hash.Hash
からfunc() hash.Hash
に変更されました。TestHMAC
関数内で、NewSHA1
,NewMD5
,NewSHA256
といったHMACパッケージ内のコンストラクタ関数ではなく、sha1.New
,md5.New
,sha256.New
といった各ハッシュパッケージのコンストラクタ関数を直接使用するように変更されました。- HMAC-SHA224, HMAC-SHA384, HMAC-SHA512の新しいテストケースが多数追加されました。
- 各ハッシュ関数実装ファイル (
src/pkg/crypto/md4/md4.go
,src/pkg/crypto/md5/md5.go
,src/pkg/crypto/ripemd160/ripemd160.go
,src/pkg/crypto/sha1/sha1.go
,src/pkg/crypto/sha256/sha256.go
,src/pkg/crypto/sha512/sha512.go
,src/pkg/hash/adler32/adler32.go
,src/pkg/hash/crc32/crc32.go
,src/pkg/hash/crc64/crc64.go
,src/pkg/hash/fnv/fnv.go
):- それぞれのハッシュ関数の
BlockSize
定数とBlockSize()
メソッドが追加されました。
- それぞれのハッシュ関数の
src/pkg/exp/ssh/transport.go
:truncatingMAC
構造体にBlockSize()
メソッドが追加され、内部のHMACインスタンスのBlockSize()
を呼び出すように変更されました。
src/pkg/crypto/openpgp/canonical_text.go
とsrc/pkg/crypto/openpgp/canonical_text_test.go
:canonicalTextHash
構造体にもBlockSize()
メソッドが追加され、内部のハッシュ関数のBlockSize()
を呼び出すように変更されました。テストファイルにも対応する変更が加えられました。
コアとなるコードの解説
src/pkg/hash/hash.go
の変更
Hash
インターフェースに BlockSize() int
が追加されたことで、Go言語のハッシュ関数は、そのアルゴリズムが処理するブロックのサイズを外部に公開できるようになりました。これは、HMACのようなハッシュ関数のブロックサイズに依存するアルゴリズムにとって極めて重要です。以前は、HMACの実装が特定のブロックサイズ(例: 64バイト)を仮定していましたが、この変更により、HMACは使用するハッシュ関数から直接正しいブロックサイズを取得できるようになり、汎用性と正確性が向上しました。
src/pkg/crypto/hmac/hmac.go
の変更
hmac
構造体のblocksize
フィールド: このフィールドは、HMACインスタンスが使用する基盤となるハッシュ関数のブロックサイズを動的に保持するために導入されました。これにより、HMACの内部計算(鍵のパディングや内部/外部ハッシュの準備)が、使用するハッシュ関数に依存して適切に行われるようになります。New
関数でのhm.inner.BlockSize()
の利用:New
関数内でhm.blocksize = hm.inner.BlockSize()
が呼び出されることで、HMACインスタンスが初期化される際に、実際に使用されるハッシュ関数(hm.inner
)からそのブロックサイズが取得されます。これにより、MD5やSHA-1(64バイトブロック)だけでなく、SHA-512(128バイトブロック)のような異なるブロックサイズを持つハッシュ関数でも、HMACが正しく動作するようになります。- パディングロジックの汎用化:
tmpPad
,Sum
,Reset
関数内でpadSize
定数がh.blocksize
に置き換えられたことで、HMACの内部パディング処理がハッシュ関数のブロックサイズに動的に適応するようになりました。これは、HMACの定義(RFC 2104)に厳密に従うために不可欠な変更です。鍵のパディングや中間ハッシュ値の結合において、正しいブロックサイズを使用することで、HMACのセキュリティと互換性が保証されます。
src/pkg/crypto/hmac/hmac_test.go
の変更
テストコードの変更は、主に新しいHMACアルゴリズム(SHA224, SHA384, SHA512)の追加と、HMACのコンストラクタへのハッシュ関数インスタンスの渡し方の変更を反映しています。
hmacTest
構造体のhash
フィールドの型変更は、テストケース内でハッシュ関数を生成する際に、HMACパッケージ内のラッパー関数ではなく、各ハッシュパッケージの標準コンストラクタ(例:sha1.New
)を直接使用できるようにするためのものです。これにより、テストの記述がより直接的になり、Goの標準的なハッシュ関数利用パターンに沿う形になりました。- 新しいテストケースの追加は、このコミットで追加されたHMACアルゴリズムが、既知のテストベクトルに対して正しい出力を生成することを確認するために不可欠です。これにより、実装の正確性が検証され、将来的な回帰を防ぐための安全網が提供されます。
各ハッシュ関数実装ファイルへの BlockSize()
の追加
各ハッシュ関数が自身の BlockSize()
を実装したことで、Goのハッシュエコシステム全体がより統一的で情報豊富なものになりました。これにより、HMACのようなハッシュ関数の特性に依存する上位レベルの暗号プリミティブが、より堅牢かつ柔軟に構築できるようになります。
src/pkg/exp/ssh/transport.go
および src/pkg/crypto/openpgp/canonical_text.go
の変更
これらのファイルへの BlockSize()
メソッドの追加は、Goの標準ライブラリ内でHMACやその他のハッシュ関数を利用している他のパッケージが、新しい hash.Hash
インターフェースの変更に適応するためのものです。これにより、ライブラリ全体の一貫性が保たれ、依存関係が正しく解決されます。
関連リンク
- Go言語のコミットページ: https://github.com/golang/go/commit/a5263c7caa61eb9eedfd6c15e3c1f989d5490ef9
- Go言語のChange List (CL): https://golang.org/cl/5550043
参考にした情報源リンク
- RFC 2104: HMAC: Keyed-Hashing for Message Authentication: https://datatracker.ietf.org/doc/html/rfc2104
- FIPS 198: The Keyed-Hash Message Authentication Code (HMAC): https://csrc.nist.gov/publications/detail/fips/198/1/archive
- NIST Computer Security Resource Center - Cryptographic Toolkit Examples: http://csrc.nist.gov/groups/ST/toolkit/examples.html (HMACテストベクトルが提供されています)
- Go言語
hash
パッケージのドキュメント: https://pkg.go.dev/hash - Go言語
crypto/hmac
パッケージのドキュメント: https://pkg.go.dev/crypto/hmac - Go言語
crypto/sha256
パッケージのドキュメント: https://pkg.go.dev/crypto/sha256 - Go言語
crypto/sha512
パッケージのドキュメント: https://pkg.go.dev/crypto/sha512 - SHA-2 (Wikipedia): https://ja.wikipedia.org/wiki/SHA-2
- HMAC (Wikipedia): https://ja.wikipedia.org/wiki/HMAC
- ハッシュ関数 (Wikipedia): https://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96%A2%E6%95%B0