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

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

コミット

  • コミットハッシュ: fcd5fd2ad4c9283307c0e0b9f15c00b32c57483a
  • 作者: Shane Hansen shanemhansen@gmail.com
  • コミット日時: 2012年10月17日 14:29:00 -0400
  • コミットメッセージ:
    crypto/cipher: panic on invalid IV length
    
    Give better user feedback when invalid IV is used
    to construct a cipher.
    
    Fixes #3411
    
    R=golang-dev, agl
    CC=golang-dev
    https://golang.org/cl/6652053
    

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

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

元コミット内容

このコミットは、Go言語の標準ライブラリであるcrypto/cipherパッケージにおいて、無効な初期化ベクトル(IV: Initialization Vector)の長さが指定された場合にパニック(panic)を発生させるように変更を加えるものです。これにより、暗号を構築する際にユーザーが不適切なIVを使用した場合に、より明確なエラーフィードバックを提供する目的があります。

具体的には、以下のファイルが変更されています。

  • src/pkg/crypto/cipher/cbc.go
  • src/pkg/crypto/cipher/cfb.go
  • src/pkg/crypto/cipher/ctr.go

これらのファイル内のNewCBCEncrypter, NewCBCDecrypter, NewCFBEncrypter, NewCFBDecrypter, NewCTRといった関数に、IVの長さがブロックサイズと一致しない場合にパニックを発生させるチェックが追加されています。

変更の背景

この変更は、Go言語のIssue #3411(Fixes #3411とコミットメッセージに記載)に対応するものです。元の実装では、暗号化または復号化のコンテキストで初期化ベクトル(IV)の長さが不正な場合に、ユーザーに対して明確なエラーメッセージが提供されず、予期せぬ動作やクラッシュを引き起こす可能性がありました。

暗号処理においてIVの長さがブロックサイズと一致することは極めて重要であり、これが守られないとセキュリティ上の問題や、単に処理が正しく行われないといった問題が発生します。このコミットは、このような不正な状態を早期に検出し、開発者に対して「IVの長さがブロックサイズと等しくなければならない」という明確なフィードバックを即座に提供することで、デバッグを容易にし、より堅牢なアプリケーション開発を支援することを目的としています。

前提知識の解説

初期化ベクトル (IV: Initialization Vector)

初期化ベクトル(IV)は、ブロック暗号の運用モードにおいて、暗号化プロセスを開始するために使用される固定サイズの入力です。IVは、同じ平文と鍵を使用しても、異なる暗号文が生成されるようにするために不可欠です。これにより、攻撃者が同じ平文の繰り返しパターンを識別することを防ぎ、セキュリティを向上させます。

IVは通常、ランダムまたは擬似ランダムに生成され、暗号文とともに送信されます。IVは秘密である必要はありませんが、予測不可能である必要があります。

ブロック暗号の運用モード

ブロック暗号は、固定長のブロック単位でデータを暗号化・復号化するアルゴリズムです。しかし、実際のデータは通常、ブロックサイズよりもはるかに長いため、データを連続的に処理するための「運用モード」が定義されています。このコミットで変更された主な運用モードは以下の通りです。

  • CBC (Cipher Block Chaining) モード:

    • 各平文ブロックが、前の暗号文ブロックとXORされてから暗号化されます。
    • 最初の平文ブロックは、IVとXORされます。
    • この連鎖的な性質により、同じ平文ブロックが複数回出現しても、異なる暗号文ブロックが生成されます。
    • 暗号化は並列化できませんが、復号化は並列化可能です。
    • IVの長さはブロックサイズと厳密に一致する必要があります。
  • CFB (Cipher Feedback) モード:

    • ブロック暗号をストリーム暗号のように動作させるモードです。
    • 前の暗号文ブロック(または最初のIV)がブロック暗号で暗号化され、その出力の一部が平文とXORされて暗号文が生成されます。
    • 暗号化と復号化の両方でブロック暗号の暗号化関数のみを使用します。
    • IVの長さはブロックサイズと厳密に一致する必要があります。
  • CTR (Counter) モード:

    • ブロック暗号をストリーム暗号のように動作させるモードです。
    • カウンター(通常はIVから派生)がブロックごとにインクリメントされ、そのカウンター値がブロック暗号で暗号化されます。その出力が平文とXORされて暗号文が生成されます。
    • 各ブロックの暗号化は独立しているため、並列処理が可能です。
    • IVは初期カウンター値として機能し、その長さはブロックサイズと厳密に一致する必要があります。

これらのモードでは、IVの長さが基盤となるブロック暗号のブロックサイズと一致することが、モードの定義上、そしてセキュリティ上も必須です。IVの長さが不適切だと、暗号化・復号化のロジックが破綻し、データが正しく処理されなかったり、セキュリティ上の脆弱性が生じたりする可能性があります。

技術的詳細

このコミットは、Go言語のcrypto/cipherパッケージ内の主要なブロック暗号運用モードのコンストラクタ関数に、IVの長さチェックを追加しています。具体的には、以下の関数が影響を受けます。

  1. NewCBCEncrypter(b Block, iv []byte) BlockMode (src/pkg/crypto/cipher/cbc.go)

    • CBCモードの暗号化器を生成する関数です。
    • 追加されたチェック: if len(iv) != b.BlockSize() { panic("cipher.NewCBCEncrypter: IV length must equal block size") }
    • b.BlockSize()は、基盤となるブロック暗号(例: AES)のブロックサイズを返します。IVの長さがこのブロックサイズと異なる場合、パニックが発生します。
  2. NewCBCDecrypter(b Block, iv []byte) BlockMode (src/pkg/crypto/cipher/cbc.go)

    • CBCモードの復号化器を生成する関数です。
    • 追加されたチェック: if len(iv) != b.BlockSize() { panic("cipher.NewCBCDecrypter: IV length must equal block size") }
    • 暗号化時と同様に、復号化時もIVの長さがブロックサイズと一致する必要があります。
  3. NewCFBEncrypter(block Block, iv []byte) Stream (src/pkg/crypto/cipher/cfb.go)

    • CFBモードの暗号化ストリームを生成する関数です。
    • 追加されたチェック: if len(iv) != block.BlockSize() { panic("cipher.NewCBFEncrypter: IV length must equal block size") }
    • CFBモードでもIVはブロックサイズと一致する必要があります。
  4. NewCFBDecrypter(block Block, iv []byte) Stream (src/pkg/crypto/cipher/cfb.go)

    • CFBモードの復号化ストリームを生成する関数です。
    • 追加されたチェック: if len(iv) != block.BlockSize() { panic("cipher.NewCBFEncrypter: IV length must equal block size") }
    • 復号化時も同様です。
  5. NewCTR(block Block, iv []byte) Stream (src/pkg/crypto/cipher/ctr.go)

    • CTRモードのストリームを生成する関数です。
    • 変更されたチェック: if len(iv) != block.BlockSize() { panic("cipher.NewCTR: IV length must equal block size") }
    • 元々この関数には同様のチェックがありましたが、パニックメッセージがより明確になるように修正されています(iv lengthからIV lengthへ)。

これらの変更により、開発者がこれらの関数を呼び出す際に、誤った長さのIVを渡した場合、即座に実行時エラー(パニック)が発生し、問題の原因を特定しやすくなります。これは、不正な入力に対する「フェイルファスト(fail-fast)」原則の適用であり、プログラムの堅牢性を高める上で非常に有効なアプローチです。

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

各ファイルの変更箇所は以下の通りです。

src/pkg/crypto/cipher/cbc.go

--- a/src/pkg/crypto/cipher/cbc.go
+++ b/src/pkg/crypto/cipher/cbc.go
@@ -33,6 +33,9 @@ type cbcEncrypter cbc
 // mode, using the given Block. The length of iv must be the same as the
 // Block's block size.
 func NewCBCEncrypter(b Block, iv []byte) BlockMode {
+	if len(iv) != b.BlockSize() {
+		panic("cipher.NewCBCEncrypter: IV length must equal block size")
+	}
 	return (*cbcEncrypter)(newCBC(b, iv))
 }

@@ -58,6 +61,9 @@ type cbcDecrypter cbc
 // mode, using the given Block. The length of iv must be the same as the
 // Block's block size and must match the iv used to encrypt the data.
 func NewCBCDecrypter(b Block, iv []byte) BlockMode {
+	if len(iv) != b.BlockSize() {
+		panic("cipher.NewCBCDecrypter: IV length must equal block size")
+	}
 	return (*cbcDecrypter)(newCBC(b, iv))
 }

src/pkg/crypto/cipher/cfb.go

--- a/src/pkg/crypto/cipher/cfb.go
+++ b/src/pkg/crypto/cipher/cfb.go
@@ -17,6 +17,9 @@ type cfb struct {
 // using the given Block. The iv must be the same length as the Block's block
 // size.
 func NewCFBEncrypter(block Block, iv []byte) Stream {
+	if len(iv) != block.BlockSize() {
+		panic("cipher.NewCBFEncrypter: IV length must equal block size")
+	}
 	return newCFB(block, iv, false)
 }

@@ -24,6 +27,9 @@ func NewCFBEncrypter(block Block, iv []byte) Stream {
 // using the given Block. The iv must be the same length as the Block's block
 // size.
 func NewCFBDecrypter(block Block, iv []byte) Stream {
+	if len(iv) != block.BlockSize() {
+		panic("cipher.NewCBFEncrypter: IV length must equal block size")
+	}
 	return newCFB(block, iv, true)
 }

src/pkg/crypto/cipher/ctr.go

--- a/src/pkg/crypto/cipher/ctr.go
+++ b/src/pkg/crypto/cipher/ctr.go
@@ -23,7 +23,7 @@ type ctr struct {
 // counter mode. The length of iv must be the same as the Block's block size.
 func NewCTR(block Block, iv []byte) Stream {
 	if len(iv) != block.BlockSize() {
-		panic("cipher.NewCTR: iv length must equal block size")
+		panic("cipher.NewCTR: IV length must equal block size")
 	}

 	return &ctr{

コアとなるコードの解説

追加されたコードの核心は、各コンストラクタ関数内で実行される以下の形式の条件チェックです。

if len(iv) != b.BlockSize() {
    panic("エラーメッセージ")
}
  • len(iv): これは、関数に渡された初期化ベクトル(iv)のスライスの現在の長さを取得します。
  • b.BlockSize() (または block.BlockSize()): これは、基盤となるブロック暗号インターフェース(cipher.Block)が提供するメソッドで、そのブロック暗号が処理するブロックのサイズ(バイト単位)を返します。例えば、AES-128の場合、ブロックサイズは16バイトです。
  • len(iv) != b.BlockSize(): この条件は、渡されたIVの長さが、使用されているブロック暗号の期待されるブロックサイズと一致しない場合にtrueとなります。
  • panic("エラーメッセージ"): 条件がtrueの場合、Goのpanic関数が呼び出されます。panicは、回復不可能なエラーが発生したことを示し、現在のゴルーチンを停止させ、スタックをアンワインドします。これにより、プログラムはクラッシュするか、recoverメカニズムによって捕捉されない限り終了します。

この変更の意図は、暗号化操作の開始時に、最も基本的な前提条件の一つであるIVの長さの正当性を厳密にチェックすることです。これにより、不正なIVが後続の暗号化ロジックに渡され、予期せぬ動作、データ破損、または潜在的なセキュリティ脆弱性を引き起こすことを未然に防ぎます。開発者は、このパニックメッセージを見ることで、IVの長さを修正する必要があることを即座に理解できます。

ctr.goの変更は、既存のパニックメッセージをより明確にするためのものです。"cipher.NewCTR: iv length must equal block size"から"cipher.NewCTR: IV length must equal block size"へと、ivIV(Initialization Vectorの略)と大文字表記に統一され、より公式な用語に合わせた形になっています。

関連リンク

参考にした情報源リンク