メインコンテンツへスキップ
#82456active

crypto/aead/...: new packages

新規提案

要約

AIによる要約であり、誤りを含む場合があります。

概要

対称鍵暗号(AEAD)の新しい標準パッケージ群 crypto/aead/... の提案です。今の crypto/cipher.AEAD は手順が多く、使い方を誤りやすい低レベル API です。これに代わり、ノンスの生成や連結を自動で行う高レベル関数 aead.Seal/aead.Open と、5 種類のアルゴリズムを実装するサブパッケージを追加します。

ステータス変更

(新規) → active
2026年10月23日に Filippo Valsorda 氏が起票し、11月12日に @aclements が proposal review group を代表して active 列に追加しました。これで週次の Proposal Review Meeting で正式に審査されます。起票から間もないですが、golang.org/x/crypto/chacha20poly1305 の標準ライブラリ化を求めた #76294 などの要望をまとめる「AEAD API の刷新」として出されたもので、crypto/tls などの関係者からも前向きな反応が出ています。このことが早い段階での審査入りにつながったと考えられます。

技術的背景

現状の問題点

今の cipher.AEAD で暗号化するには、次の手順をすべて自分で行う必要があります。

  • aes.NewCipher で得た Block を、直接使わずに cipher.NewGCM に渡す
  • ノンス(使い捨ての値)を自前で生成する。AES-GCM の 96 ビットノンスは、乱数で生成すると同じ鍵で約 2³² 件までしか安全に暗号化できない
  • Seal(nonce, nonce, plaintext, nil) という、append 形式で直感的でない呼び出し方をする
  • 復号時に長さを確認してから nonce と暗号文に分割する。確認を忘れると panic する
    提案者は、この状態を「Does not spark joy」と表現しています。

提案された解決策

  • crypto/aead パッケージ
    • AEAD インターフェース: NonceSize、TagSize、SealRaw(out, tag, nonce, plaintext, ad)、OpenRaw(out, nonce, ciphertext, tag, ad) を持つ。append 形式ではないので、メモリ重複(エイリアシング)のルールが単純になる
    • Seal/Open: ランダムなノンスを生成し、出力を nonce || ciphertext || tag の形式に連結・分解する
    • SealWithBuffer/OpenWithBuffer: 事前に確保したバッファを使う版。その場での暗号化・復号(in-place)にも対応する
    • Overhead: NonceSize() + TagSize() を返す
  • Seal に渡せるのは、ランダムなノンスで安全に使える AEAD だけです。AllowsRandomNonces() bool メソッドが true を返すか、このメソッドがなくノンスが 16 バイト以上の場合に限られます。それ以外の AEAD ではエラーを返します。
  • サブパッケージ
    • ランダムなノンスに対応するもの
      • xaes256gcm: 推奨。FIPS 140-3 準拠を保ったままノンスを拡張した方式
      • xchacha20poly1305
      • aesgcmsiv: ノンスを再利用しても安全性が大きく崩れない「nonce-misuse 耐性」を持ち、決定的暗号化にも使える
    • ノンスの手動管理が必要なもの(SealRaw を使う)
      • aesgcm
      • chacha20poly1305
  • aesgcm には、FIPS 140-3 IG C.H の各シナリオに対応するコンストラクタがあります。
    • NewWithCounterNonces: SSH などで使われる RFC 5647 方式
    • NewWithXORCounterNonces: QUIC で使われる RFC 9001 方式
    • NewWithUnsafeRandomNonces
      カウンタ方式の 2 つは、カウンタが単調に増えることを強制します。その代わり、これらが返すインスタンスの SealRaw は並行に呼び出すと安全ではありません。

これによって何ができるようになるか

  • アプリのデータ暗号化: ファイル、Cookie、DB カラムなどを、ノンスの扱いに悩まず安全に暗号化できる
  • プロトコル実装: Nebula、TLS、QUIC、SSH のように決まった形式のノンスが必要な場面では、SealRaw とカウンタ方式のノンスでノンスの再利用を防げる
  • FIPS 140-3 準拠が必要な環境: 準拠するシナリオを API の選び方で明示できる
  • 決定的暗号化: AES-GCM-SIV を使える

コード例

// Before: crypto/cipher
block, err := aes.NewCipher(key)
if err != nil { return err }
gcm, err := cipher.NewGCM(block)
if err != nil { return err }
nonce := make([]byte, gcm.NonceSize())
rand.Read(nonce)
out := gcm.Seal(nonce, nonce, plaintext, nil)
// 復号
if len(out) < gcm.NonceSize() { return errors.New("too short") }
pt, err := gcm.Open(nil, out[:gcm.NonceSize()], out[gcm.NonceSize():], nil)
// After: crypto/aead
a, err := xaes256gcm.New(key)
if err != nil { return err }
out, err := aead.Seal(a, plaintext, nil)
// 復号
pt, err := aead.Open(a, out, nil)

議論のハイライト

  • 提案者は、XAES-256-GCM を加える理由として次を挙げています。ランダムなノンスで安全に使える AES 系の方式という空白を埋めること、Google Tink など複数の実装があること、AWS によるセキュリティ解析があること、Microsoft の SDK で採用されていること。
  • AES-GCM-SIV は、決定的暗号化の手段として、また XAES-256-GCM がまだ新しい方式であることへの代替として含めています。
  • SealWithBuffer の重複ルールは少し変則的です。その場で暗号化するときは、出力の先頭にノンス分の領域を残す必要があるためです。提案者は「この複雑さは元々呼び出し側のどこかにあったもの」と説明しています。
  • Nebula の @wadey は、aesgcm.NewWithCounterNonces と SealRaw/OpenRaw で要件を満たせると回答しました。@n2vi は、SealWithBuffer の追加データ(associated data)にユーザー ID を入れる XChaCha20-Poly1305 の実例を示しています。
  • #76294(crypto/chacha20poly1305 の追加)は、この提案に統合される形でクローズされました。#76294 の提案者 @qmuntal も「#82456 で問題ない」と同意しています。

関連リンク