#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 準拠を保ったままノンスを拡張した方式xchacha20poly1305aesgcmsiv: ノンスを再利用しても安全性が大きく崩れない「nonce-misuse 耐性」を持ち、決定的暗号化にも使える
- ノンスの手動管理が必要なもの(
SealRawを使う)aesgcmchacha20poly1305
- ランダムなノンスに対応するもの
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 で問題ない」と同意しています。