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

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

このコミットは、Go言語の標準ライブラリ crypto/cipher パッケージに Galois/Counter Mode (GCM) を追加するものです。GCMは、認証付き暗号 (Authenticated Encryption with Associated Data, AEAD) モードの一種であり、データの機密性、完全性、および認証性を提供します。特にAES(Advanced Encryption Standard)と組み合わせて使用されることが一般的です。

コミット

commit 20a2b960898a37e646bf76dcf0e3fd067a387c5f
Author: Adam Langley <agl@golang.org>
Date:   Mon Aug 5 14:31:58 2013 -0400

    crypto/cipher: add GCM mode.
    
    GCM is Galois Counter Mode, an authenticated encryption mode that is,
    nearly always, used with AES.
    
    R=rsc
    CC=golang-dev
    https://golang.org/cl/12375043

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

https://github.com/golang/go/commit/20a2b960898a37e646bf76dcf0e3fd067a387c5f

元コミット内容

このコミットは、Go言語の crypto/cipher パッケージにGCM (Galois Counter Mode) を追加することを目的としています。GCMは、認証付き暗号化モードであり、ほとんどの場合AESと組み合わせて使用されます。これにより、データの暗号化だけでなく、改ざん検出と認証も同時に行えるようになります。

変更の背景

GCMは、現代の暗号化において非常に重要なモードです。従来の暗号化モード(例: CBCモード)では、データの機密性(暗号化)は提供されますが、データの完全性(改ざんされていないこと)や認証性(送信者が正当であること)は別途MAC(Message Authentication Code)などのメカニズムで保証する必要がありました。これは「Encrypt-then-MAC」などの構成を必要とし、実装が複雑になりがちで、誤った実装はセキュリティ上の脆弱性につながる可能性がありました。

GCMは、認証付き暗号 (AEAD) の一種として、暗号化と認証を単一のアルゴリズムで効率的に提供します。これにより、実装の複雑さが軽減され、より安全な暗号化通信が実現できます。特にTLS/SSLなどのプロトコルでは、GCMのようなAEADモードが推奨されており、そのパフォーマンスとセキュリティ特性から広く採用されています。Go言語の標準ライブラリにGCMが追加されることで、Goアプリケーションで安全かつ効率的な認証付き暗号化を容易に利用できるようになることが、この変更の背景にあります。

前提知識の解説

認証付き暗号 (Authenticated Encryption with Associated Data, AEAD)

AEADは、データの機密性(暗号化)、完全性(改ざん検出)、および認証性(送信元認証)を同時に提供する暗号化方式です。さらに、"Associated Data" (追加データ、AD) と呼ばれる、暗号化されないが認証の対象となるデータを含めることができます。これは、ヘッダー情報など、暗号化する必要はないが、改ざんされると問題が生じるデータに利用されます。

Galois/Counter Mode (GCM)

GCMは、NISTによって標準化された認証付き暗号モードです。カウンタモード (CTR) と Galois Field Multiplication (GF(2^128) 上の乗算) を組み合わせたものです。

  • カウンタモード (CTR): ブロック暗号をストリーム暗号のように動作させるモードです。各ブロックは、ユニークなカウンタ値と鍵を使って暗号化され、その結果と平文がXORされます。並列処理が可能で高速です。
  • GHASH: GCMの認証部分を担うハッシュ関数です。Galois Field GF(2^128) 上での乗算に基づいています。暗号文と追加データを処理し、認証タグを生成します。

ノンス (Nonce)

Nonce (Number used once) は、暗号化操作ごとに一度だけ使用されるランダムまたは擬似ランダムな値です。GCMでは、同じ鍵で複数のメッセージを暗号化する際に、各メッセージに異なるノンスを使用することが極めて重要です。ノンスが重複すると、セキュリティ上の重大な脆弱性(例: 認証タグの偽造)につながります。

関連データ (Associated Data, AD)

前述の通り、暗号化はされないが認証の対象となるデータです。例えば、ネットワークプロトコルのヘッダー情報などがこれに該当します。

ガロア体 (Galois Field) GF(2^128)

GCMの認証部分であるGHASHは、有限体(ガロア体)GF(2^128) 上での演算に基づいています。これは、ビット列を多項式と見なし、特定の既約多項式を法として演算を行う数学的な構造です。GF(2^128) は、128ビットのブロックを扱うのに適しており、高速なハードウェア実装が可能です。

定数時間操作 (Constant-Time Operations)

暗号化アルゴリズムの実装において、処理時間が入力データ(特に秘密鍵や平文)に依存しないようにする技術です。処理時間がデータに依存すると、サイドチャネル攻撃(例: タイミング攻撃)によって秘密情報が漏洩する可能性があります。crypto/subtle パッケージは、このような定数時間操作を支援する関数を提供します。

技術的詳細

Go言語の crypto/cipher パッケージに追加されたGCM実装は、以下の主要なコンポーネントで構成されています。

  1. AEAD インターフェース: GCMは、AEAD インターフェースを実装します。このインターフェースは、認証付き暗号の標準的なAPIを定義しており、NonceSize()Overhead()Seal()(暗号化と認証)、Open()(復号と認証)の各メソッドを含みます。

  2. gcm 構造体: GCMモードの内部状態を保持する構造体です。

    • cipher Block: 基盤となるブロック暗号(例: AES)のインスタンス。
    • productTable [16]gcmFieldElement: GHASHの計算を高速化するための事前計算されたテーブル。GCMの鍵 H の16倍(0から15倍)の値を保持します。これらの値は、GF(2^128) 上の要素であり、ビット順序が逆転して格納されるという特殊な形式で扱われます。
  3. gcmFieldElement 構造体: GF(2^128) 上の要素を表す構造体です。lowhigh の2つの uint64 フィールドで128ビットの値を表現します。GCM標準に合わせて、ビットが逆順に格納されるという特徴があります。

  4. NewGCM 関数: Block インターフェースを実装するブロック暗号(例: AES)を受け取り、新しい AEAD インターフェース(gcm のインスタンス)を返します。この関数内で、GHASHの計算に必要な productTable が初期化されます。productTable の生成では、GF(2^128) 上での倍算 (gcmDouble) と加算 (gcmAdd) が使用されます。

  5. Seal メソッド: 平文 (plaintext) と追加データ (data) を暗号化・認証し、結果を dst に追記します。

    • ノンス (nonce) とカウンタ値から初期カウンタブロックを生成します。
    • 初期カウンタブロックを基に、ブロック暗号で tagMask を生成します。
    • カウンタモードで平文を暗号化します (counterCrypt)。
    • GHASHを計算し、認証タグを生成します (auth)。このタグは tagMask とXORされます。
    • 暗号文の末尾に認証タグを付加します。
  6. Open メソッド: 暗号文 (ciphertext) と追加データ (data) を復号・認証し、成功すれば平文を dst に追記します。

    • 暗号文から認証タグを分離します。
    • Seal と同様に、ノンスとカウンタ値から初期カウンタブロックを生成し、tagMask を生成します。
    • GHASHを計算し、期待される認証タグを生成します (auth)。
    • 生成された認証タグと受信した認証タグを subtle.ConstantTimeCompare を用いて比較します。これにより、タイミング攻撃を防ぎます。
    • 認証が成功した場合のみ、カウンタモードで暗号文を復号し (counterCrypt)、平文を返します。
  7. GHASHの内部演算:

    • gcmAdd: GF(2^128) 上の加算(ビットごとのXOR)。
    • gcmDouble: GF(2^128) 上の倍算。ビット順序が逆転しているため、実際には右シフトと既約多項式による剰余演算(0xe100000000000000 とのXOR)を行います。
    • mul: GHASHのコアとなるGF(2^128) 上の乗算。productTable を利用して高速化されています。
    • updateBlocks / update: GHASHの計算中に、入力データ(追加データや暗号文)を処理し、gcmFieldElement の状態を更新します。
  8. crypto/subtle の利用: Open メソッドでの認証タグの比較に subtle.ConstantTimeCompare が使用されています。これは、比較処理の実行時間が入力データに依存しないようにすることで、タイミング攻撃による情報漏洩を防ぐための重要なセキュリティ対策です。

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

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

  • src/pkg/crypto/cipher/gcm.go: GCMモードの主要な実装が含まれる新規ファイル。
  • src/pkg/crypto/cipher/gcm_test.go: GCMモードのテストケースが含まれる新規ファイル。NISTのテストベクトルを使用して、実装の正確性を検証しています。
  • src/pkg/go/build/deps_test.go: Goのビルドシステムにおけるパッケージ依存関係のテストファイル。crypto/ciphercrypto/subtle に依存するようになった変更が反映されています。

コアとなるコードの解説

src/pkg/crypto/cipher/gcm.go

このファイルは、GCMモードのGo言語での実装を提供します。

  • AEAD インターフェースの定義:

    type AEAD interface {
        NonceSize() int
        Overhead() int
        Seal(dst, nonce, plaintext, data []byte) []byte
        Open(dst, nonce, ciphertext, data []byte) ([]byte, error)
    }
    

    認証付き暗号の標準的なインターフェースを定義しています。

  • gcmFieldElement 構造体:

    type gcmFieldElement struct {
        low, high uint64
    }
    

    GF(2^128) の要素を表現します。ビット順序が逆転して格納される点が特徴です。

  • gcm 構造体:

    type gcm struct {
        cipher Block
        productTable [16]gcmFieldElement
    }
    

    GCMインスタンスの内部状態を保持します。cipher は基盤となるブロック暗号、productTable はGHASH計算用の事前計算テーブルです。

  • NewGCM 関数:

    func NewGCM(cipher Block) (AEAD, error) {
        // ...
        // productTableの初期化ロジック
        // ...
        return g, nil
    }
    

    GCMインスタンスを生成し、GHASHの計算に必要な productTable を初期化します。

  • Seal メソッド:

    func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
        // ...
        // カウンタモードでの暗号化 (g.counterCrypt)
        // GHASH計算と認証タグ生成 (g.auth)
        // ...
        return ret
    }
    

    平文を暗号化し、追加データと共に認証タグを生成して暗号文に付加します。

  • Open メソッド:

    func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
        // ...
        // GHASH計算と期待される認証タグの生成 (g.auth)
        // 定数時間比較 (subtle.ConstantTimeCompare)
        // カウンタモードでの復号 (g.counterCrypt)
        // ...
        return ret, nil
    }
    

    暗号文を復号し、認証タグを検証します。認証に失敗した場合はエラーを返します。

  • ヘルパー関数群: reverseBits, gcmAdd, gcmDouble, mul, updateBlocks, update, gcmInc32, sliceForAppend, counterCrypt, auth, getUint64, putUint64 など、GCMの内部演算(GF(2^128) 演算、カウンタ管理、GHASH計算など)を実装する多数のヘルパー関数が定義されています。

src/pkg/crypto/cipher/gcm_test.go

このファイルには、GCM実装の正確性を検証するためのテストケースが含まれています。

  • aesGCMTests 変数: NISTのAES-GCMテストベクトルが構造体のスライスとして定義されています。これには、鍵、ノンス、平文、追加データ、期待される結果(暗号文と認証タグの結合)が含まれます。

  • TestAESGCM 関数: aesGCMTests の各テストベクトルに対して、以下の検証を行います。

    1. aes.NewCiphercipher.NewGCM を使用してGCMインスタンスを生成します。
    2. Seal メソッドで暗号化を行い、結果が期待される値と一致するかを確認します。
    3. Open メソッドで復号を行い、復号された平文が元の平文と一致するかを確認します。
    4. 追加データ、ノンス、または暗号文の一部を意図的に変更し、Open メソッドが正しく認証エラーを返すことを確認します。これにより、GCMの認証機能が正しく動作していることを検証します。
  • BenchmarkAESGCM 関数: GCMの暗号化パフォーマンスを測定するためのベンチマークテストです。

src/pkg/go/build/deps_test.go

このファイルは、Goのビルドシステムがパッケージ間の依存関係を正しく解決できることを確認するためのテストです。

  • crypto/cipher の依存関係に crypto/subtle が追加されています。これは、GCM実装が subtle.ConstantTimeCompare を使用するためです。
  • CRYPTO-SUPPORT という中間的な依存関係グループが削除され、crypto/hmac などが直接 L3 に依存するように変更されています。これは、crypto/subtle が直接 crypto/cipher から参照されるようになったため、より直接的な依存関係の記述に整理されたことを示唆しています。

関連リンク

参考にした情報源リンク