OpenPGP
RFC 9580 OpenPGP
RFC 6637 (廃止) Elliptic Curve Cryptography (ECC) in OpenPGP RFC 5581 (廃止) The Camellia Cipher in OpenPGP → 9580
RFC 4880 (廃止) OpenPGP Message Format → 9580
RFC 2440 (廃止) OpenPGP Message Format → 4880
PGP 5
RSAオプション
ElGamal
RFC 1991 (廃止)
PGP 2.6 2.7
RSA
RFC 3156 MIME Security with OpenPGP
RFC 9580
1. はじめに
この文書は、OpenPGPが暗号化、復号化、署名、および鍵管理機能を提供するために使用するメッセージ交換パケット形式に関する情報を提供します。これはRFC 4880(「OpenPGPメッセージ形式」)の改訂版であり、これはRFC 2440の改訂版であり、それ自体はRFC 1991(「PGPメッセージ交換形式」)に代わるものです。 この文書は、RFC 4880(OpenPGP)、RFC 5581(OpenPGPにおけるCamellia)、およびRFC 6637(OpenPGPにおける楕円曲線)を廃止するものです。執筆時点では、この文書には未解決の検証済みエラッタがすべて組み込まれており、それらは付録Cに記載されています。 これらの以前の仕様を既に実装しているソフトウェアは、変更点について付録Bを確認することをお勧めします。
1.1. 用語
本文書中のキーワード「MUST(しなければならない)」、「MUST NOT(してはならない)」、「REQUIRED(必須)」、「SHALL(するべき)」、「SHALL NOT(すべきでない)」、「SHOULD(すべきでない)」、「RECOMMENDED(推奨される)」、「NOT RECOMMENDED(推奨されない)」、「MAY(してもよい)」、および「OPTIONAL(任意)」は、ここで示すようにすべて大文字で表記されている場合に限り、BCP 14 RFC 2119 RFC 8174 の規定に従って解釈されます。 本文書中の名前空間割り当てを説明するために使用されるキーワード「Private Use(私的使用)」、「Specification Required(仕様必須)」、「RFC Required(RFC必須)」は、RFC8126 の規定に従って解釈されます。 本文書で使用されている一部の用語は、OpenPGP仕様の以前のバージョンから改良されています。詳細については、付録B.1を参照してください。
2. 一般的な機能
OpenPGPは、公開鍵暗号および/または対称鍵暗号とデジタル署名を用いることで、メッセージおよびデータファイルの機密性と整合性を確保します。OpenPGPは、暗号化および/または署名されたメッセージのエンコードと転送のためのフォーマットを提供します。さらに、OpenPGPは鍵と証明書のエンコードと転送機能も提供しますが、鍵の保存と管理については本文書の範囲外です。
2.1. 暗号化による機密性
OpenPGPは、対称鍵暗号と(オプションで)公開鍵暗号を組み合わせることで機密性を確保します。公開鍵を使用する場合、まずオブジェクトは対称鍵暗号アルゴリズムを用いて暗号化されます。各対称鍵は、単一のオブジェクトに対して一度だけ使用されます。オブジェクトごとに、新しい「セッション鍵」が乱数として生成されます(「セッション」と呼ばれることもあります)。セッション鍵は一度だけ使用されるため、メッセージに紐付けられ、メッセージと共に送信されます。鍵を保護するため、受信側の公開鍵で暗号化されます。シーケンスは以下のとおりです。
1. 送信者がメッセージを作成します。
2. 送信側のOpenPGP実装は、このメッセージ用のランダムなセッション鍵を生成します。
3. セッション鍵は、各受信者の公開鍵を使用して暗号化されます。
これらの「暗号化されたセッション鍵」がメッセージの先頭となります。
4. 送信側のOpenPGP実装は、必要に応じてメッセージを圧縮し、セッション鍵から導出されたメッセージ鍵を使用して暗号化します。暗号化されたメッセージが、OpenPGPメッセージの残りの部分を構成します。
5. 受信側のOpenPGP実装は、受信者の秘密鍵を使用してセッション鍵を復号します。
6. 受信側のOpenPGP実装は、セッション鍵から導出されたメッセージ鍵を使用してメッセージを復号します。メッセージが圧縮されている場合は、解凍されます。
対称鍵暗号化を使用する場合、上記と同様のプロセスが使用されますが、セッション鍵は共有秘密から導出された対称アルゴリズムを使用して暗号化されます。
デジタル署名と機密保持サービスの両方を、同じメッセージに適用することができます。まず、メッセージに対して署名が生成され、メッセージに添付されます。次に、メッセージと署名は、セッション鍵から導出された対称メッセージ鍵を使用して暗号化されます。最後に、セッション鍵は公開鍵暗号を使用して暗号化され、暗号化されたブロックの先頭に付加されます。
2.2. デジタル署名による認証
デジタル署名は、暗号学的ハッシュ関数と署名可能な公開鍵アルゴリズムを使用します。処理手順は以下のとおりです。
送信者がメッセージを作成します。
送信側の実装は、メッセージのハッシュダイジェストを生成します。
送信側の実装は、送信者の秘密鍵を用いてハッシュダイジェストから署名を生成します。
署名はメッセージに添付されるか、メッセージとともに送信されます。
受信側の実装は、メッセージのコピーとメッセージ署名を取得します。
受信側の実装は、受信したメッセージの新しいハッシュダイジェストを生成し、メッセージの署名を用いて検証します。検証が成功すれば、メッセージは真正であると認められます。
2.3. 圧縮
OpenPGPの実装は、データの圧縮をサポートする場合があります。既存のOpenPGPメッセージの多くは圧縮されています。圧縮をサポートしたくない制約付き実装に取り組んでいる実装者などは、少なくとも解凍機能を実装することを検討すべきでしょう。
2.4. Base64への変換
OpenPGPにおける暗号化メッセージ、署名、鍵、証明書の基本的な表現形式は、任意のオクテットのストリームです。一部のシステムでは、7ビットの印刷可能なテキストで構成されるブロックのみの使用が許可されています。生のバイナリデータを安全に転送できないチャネルを介してOpenPGPの生のバイナリオクテットを転送するために、これらのバイナリオクテットの印刷可能なエンコードが定義されています。生の8ビットバイナリオクテットストリームは、「ASCII Armor」と呼ばれる形式でBase64エンコードを使用して、印刷可能なASCII文字のストリームに変換できます(セクション6を参照)。
実装はBase64変換をサポートすべきです。
2.5. 署名のみのアプリケーション
OpenPGPは暗号化と署名の両方を使用するアプリケーション向けに設計されていますが、署名のみの実装を必要とするユースケースも数多く存在します。この仕様では暗号化と署名の両方が要求されていますが、暗号化サポートを省略しているという点のみで非準拠となるサブセット実装が存在することは妥当です。
3. データ要素のフォーマット
このセクションでは、OpenPGPで使用されるデータ要素について説明します。
3.1. スカラー数
スカラー数は符号なしであり、常にビッグエンディアン形式で格納されます。解釈対象のk番目のオクテットを$ n[k] で表すと、2オクテットのスカラーの値は$ ((n[0] << 8) + n[1]) となります。4オクテットのスカラーの値は$ ((n[0] << 24) + (n[1] << 16) + (n[2] << 8) + n[3]) となります。
3.2. 多倍長整数
多倍長整数(MPI)は、暗号計算などで使用されるような大きな整数を格納するために使用される符号なし整数です。
MPIは2つの部分から構成されます。1つ目は、MPIの長さをビット単位で表した2オクテットのスカラー値、2つ目は、実際の整数値を含むオクテット列です。
これらのオクテット列はビッグエンディアン形式の数値を形成します。ビッグエンディアン形式の数値に適切な長さを接頭辞として付加することで、MPIに変換できます。
例:
(角括弧で囲まれたオクテット列の数値はすべて16進数です。)
オクテット列 [00 00] は、値0のMPIを形成します。
オクテット列 [00 01 01] は、値1のMPIを形成します。
オクテット列 [00 09 01 FF] は、値511のMPIを形成します。
追加ルール:
MPIのサイズは、((MPI.length + 7) / 8) + 2オクテットです。
MPIの長さフィールドは、最上位の非ゼロビットから始まる長さを表します。したがって、MPI 00 02 01 は正しくありません。正しくは 00 01 01 です。バージョン6の鍵、署名、または公開鍵暗号化セッションキー(PKESK)パケット内のMPIを解析する場合、実装はエンコードされた長さが最上位の非ゼロビットから始まる長さと一致するかどうかを確認する必要があります。一致しない場合は、パケットを不正な形式として拒否します。 MPIの未使用ビットはゼロでなければなりません。
3.2.1. MPIを使用したその他のデータのエンコード
場合によっては、MPIは楕円曲線(EC)点(セクション11.2参照)や既知の固定長のオクテット列(セクション11.3参照)などの非整数データのエンコードに使用されることに注意してください。ワイヤ表現は同じです。最初の非ゼロビットから数えたビット長の2オクテットに続き、先頭のゼロオクテットを取り除いた上で値を表現できる最小のオクテットの系列が続きます。
3.3. キーIDとフィンガープリント
キーIDは、キーを識別する8オクテットのスカラー値です。実装においては、キーIDが一意であると仮定すべきではありません。フィンガープリントはキーIDよりも一意である可能性が高いです。キーのフィンガープリントとキーIDは、キーのバージョンによって異なる方法で計算されます。
5.5.4項では、キーIDとフィンガープリントの生成方法について説明します。
3.4. テキスト
3.5. 時刻フィールド
時刻フィールドは、1970年1月1日午前0時(UTC)からの経過秒数を表す符号なし4オクテットの数値です。
3.6. キーリング
キーリングは、ファイルまたはデータベースに格納された1つ以上のキーの集合です。通常、キーリングは単に鍵の連番リストですが、適切なデータベースであれば何でも構いません。キーリングやその他のデータベースの詳細については、本仕様の範囲外とします。
3.7. 文字列から鍵への変換(S2K)指定子
文字列から鍵への変換(S2K)指定子は、パスフレーズ文字列を対称鍵暗号化/復号鍵に変換するために使用されます。S2K変換を必要とするパスフレーズは、現在、秘密鍵の秘密部分の暗号化と、対称暗号化されたメッセージの2つの場面で使用されています。
3.7.1. S2K指定子タイプ
現在、S2K指定子には4つのタイプがあり、いくつかの予約値も存在します。
table:OpenPGP 文字列から型 (S2K: String-to-Key) Types Registry
ID S2K Type S2K Field Size (Octets) Generate? 参照
0 Simple S2K 2 No Section 3.7.1.1
1 ソルト付き S2K 10 Only when string is high entropy Section 3.7.1.2
2 予約値 - No
3 Iterated and Salted S2K 11 Yes Section 3.7.1.3
4 Argon2 20 Yes Section 3.7.1.4
100-110 プライベートまたは実験的使用 - 必要に応じて
S2K指定子タイプについては、以下のサブセクションで説明します。「生成しますか?」列に「はい」がない場合、S2Kエントリは下位互換モードでの読み取り専用であり、新しい出力の生成には使用しないでください。
3.7.1.1. シンプルS2K
シンプルS2Kは、文字列を直接ハッシュ化してキーデータを生成します。このハッシュ化は、以下に示すように行われます。
code:simple S2K
Octet 0: 0x00
Octet 1: hash algorithm
Simple S2Kはパスフレーズをハッシュ化してセッションキーを生成します。この処理方法は、セッションキーのサイズ(使用する暗号方式によって決まります)とハッシュアルゴリズムの出力サイズによって異なります。ハッシュサイズがセッションキーサイズよりも大きい場合、ハッシュの最上位(左端)オクテットがキーとして使用されます。
ハッシュサイズがキーサイズよりも小さい場合、必要なキーデータを生成するのに十分な数のハッシュコンテキストインスタンスが作成されます。これらのインスタンスには、0、1、2、…個のゼロがプリロードされます(つまり、最初のインスタンスにはプリロードなし、2番目のインスタンスには1個のゼロ、3番目のインスタンスには2個のゼロがプリロードされ、以下同様です)。
データがハッシュ化されると、各ハッシュコンテキストに独立して渡されます。コンテキストはそれぞれ異なる方法で初期化されているため、それぞれ異なるハッシュ出力が生成されます。パスフレーズがハッシュ化されると、複数のハッシュから得られた出力データが、最初のハッシュを左端として連結され、鍵データが生成されます。右側の余分なオクテットは破棄されます。
3.7.1.2. ソルト付きS2K
ソルト付きS2Kでは、S2K指定子に「ソルト」値(任意のデータ)が含まれています。このソルト値は、パスフレーズ文字列とともにハッシュ化され、辞書攻撃を防ぐのに役立ちます。
code:salted S2K
Octet 0: 0x01
Octet 1: hash algorithm
Octets 2-9: 8-octet salt value
ソルト付きS2Kは、シンプルなS2Kとほぼ同じですが、ハッシュ関数への入力が、S2K指定子からの8オクテットのソルトとパスフレーズで構成される点が異なります。
3.7.1.3. 反復ソルト付きS2K
反復ソルト付きS2Kは、ソルトとオクテット数の両方を含みます。ソルトはパスフレーズと組み合わされ、その結果の値が繰り返しハッシュ化されます。これにより、攻撃者が辞書攻撃を試みるために行う作業量がさらに増加します。
code:iterated and salted S2K
Octet 0: 0x03
Octet 1: hash algorithm
Octets 2-9: 8-octet salt value
Octet 10: count; a 1-octet coded value
カウントは、以下の式を用いて1オクテットの数値に符号化されます。
code:a
count = ((Int32)16 + (c & 15)) << ((c >> 4) + EXPBIAS);
上記の式はC99に記載されており、「Int32」は32ビット整数の型、変数「c」は符号化されたカウント(オクテット10)を表します。 反復型ソルトS2Kは、パスフレーズとソルトデータを複数回ハッシュ化します。ハッシュ化するオクテットの総数は、S2K指定子の符号化されたカウントで指定されます。なお、結果として得られるカウント値は、ハッシュ化されるオクテット数を示すオクテットカウントであり、反復回数ではありません。
最初に、必要なキーデータのオクテット数に応じて、他のS2Kアルゴリズムと同様に、1つ以上のハッシュコンテキストが設定されます。その後、ソルト、続いてパスフレーズデータが、オクテットカウントで指定されたオクテット数がハッシュ化されるまで、各ハッシュコンテキストへの入力として繰り返し処理されます。入力はオクテット数に合わせて切り詰められますが、オクテット数がソルトとパスフレーズの初期サイズより小さい場合は切り詰められません。つまり、オクテット数に関わらず、各ハッシュコンテキストには、ソルトとパスフレーズの完全なコピーが少なくとも1つ入力として渡されます。ハッシュ処理が完了すると、ハッシュダイジェストからキーデータが生成されます。これは、他のS2Kアルゴリズムの場合と同様です。
3.7.1.4. Argon2
このS2K方式では、RFC 9106で規定されているArgon2を使用してパスフレーズをハッシュ化します。これによりメモリの堅牢性が確保され、パスフレーズを総当たり攻撃からさらに保護します。 code:Argon2
Octet 0: 0x04
Octets 1-16: 16-octet salt value
Octet 17: 1-octet number of passes t
Octet 18: 1-octet degree of parallelism p
Octet 19: 1-octet encoded_m, specifying the exponent of
the memory size
saltはパスフレーズごとに一意である必要(SHOULD)があります。
パス数 t と並列度 p はゼロ以外でなければなりません(MUST)。
メモリサイズ m は $ 2^{encoded\_m} キロバイト (KiB) の RAM です。エンコードされたメモリサイズは 3+ceil(log2(p)) から 31 までの値でなければならず(MUST)、デコードされたメモリサイズ m は 8*p から $ 2^{31} までの値になります。メモリのハードネスサイズはオクテットではなく KiB 単位で指定されることに注意してください。
Argon2 は、パスフレーズを P、saltを S、上記で説明した t、p、m の値、必要なキーサイズをタグ長 T、バージョン v を 0x13、タイプを Argon2id として呼び出されます。
t、p、m の推奨値については、RFC 9106 のセクション 4 を参照してください。特定のアプリケーションにおける推奨値mが2のべき乗でない場合、結果として得られる性能が許容範囲内であれば、次の2のべき乗に切り上げることを推奨します。そうでない場合は、切り捨ててください(ただし、mは少なくとも8*pでなければなりません)。 例として、最初の推奨オプション(t=1、p=4、m=$ 2^{21} )の場合、完全なS2K指定子は次のようになります。
code:a
04 XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
XX 01 04 15
ここで、XXはランダムなオクテットのソルトを表します。
3.7.2. S2Kの使用
シンプルS2Kおよびソルト付きS2K指定子は、ユーザーが提供するような低エントロピー文字列と併用した場合、総当たり攻撃で解読される可能性があります。さらに、シンプルS2Kを使用すると、鍵と初期化ベクトル(IV)の再利用につながる可能性があります(セクション5.3を参照)。したがって、S2K指定子を生成する際には、実装はシンプルS2Kを使用してはなりません。また、実装は、入力文字列が高エントロピーであることを知っている場合(例えば、既知の信頼できる乱数源を使用して文字列を生成した場合)を除き、ソルト付きS2Kを生成すべきではありません。
実装はArgon2を使用することを推奨します。Argon2が利用できない場合は、オクテット数が多く、強力なパスフレーズを使用するように注意すれば、反復S2Kおよびソルト付きS2Kを使用しても構いません。ただし、この方法はArgon2とは異なり、メモリ耐性を提供しません。
3.7.2.1. 秘密鍵暗号化
秘密鍵パケット(5.5.3項参照)において、公開鍵データに続く最初のオクテットは、秘密鍵データがパスフレーズで保護されているかどうか、またどのように保護されているかを示します。この最初のオクテットは「S2K使用オクテット」と呼ばれます。
S2K使用オクテットがゼロの場合、秘密鍵データは保護されていません。ゼロ以外の場合、パスフレーズを使用して秘密鍵を解読する方法が記述されています。
RFC 2440以前の実装では、S2K使用オクテットに共通暗号アルゴリズムID(9.3項参照)を格納することで、保護された鍵を示していました。この場合、パスフレーズを指定された暗号アルゴリズムの鍵に変換するために、常にMD5ハッシュ関数が使用されていました。 後の実装では、S2K使用オクテットに特殊値253(AEAD)、254(CFB)、または255(MalleableCFB)のいずれかを格納することで、保護された秘密鍵を示します。S2K使用オクテットの直後には、パスフレーズを秘密情報を解読できる対称鍵に変換する方法、および使用される暗号化の種類に関連するその他のパラメータを記述する一連のフィールドが続きます。
ワイヤフォーマットのフィールドは、囲んでいるOpenPGPパケットのバージョンによっても異なります。以下の表は、S2K使用オクテットでインデックス付けされており、セクション5.5.3で説明されている詳細をまとめたものです。
以下の表では、check(x)は「2オクテットチェックサム」を意味し、これはx mod 65536のすべてのオクテットの合計です。infoおよびpacketprefixパラメータについては、セクション5.5.3で詳しく説明されています。「Generate?」列ヘッダーは「Gen?」に短縮されていることに注意してください。ここ。