PGPには沢山の暗号が登場します。 PGP内部ではこれらのアルゴリズムをどうやって使っているのでしょう。 このページではこういった疑問に, 数式などを使わずに, できるだけ易しく解説します。 タイトルはもちろん某書籍シリーズのパクリです! 例によって字ばっかりですみません。
PGPには色々な製品やバージョンがありますが, ここでは一括して 「PGP」 と呼ぶことにします。 ただし厳密なバージョンの違いを強調するために以下の表現を用いる場合があります。
末尾に参考文献を挙げておきます。 それらには, より詳しい情報があります。 是非参考にしてください。
よく 「PGP=公開鍵暗号」 のように言われますが, 実際にはPGPの暗号化処理はさまざまなアルゴリズムの組み合わせで成り立っています。 まずPGPでどのようなアルゴリズムを用いているか見てみましょう。
お互いに共通の 「鍵」 を持ち, その鍵を使ってメッセージの暗号化/復号化を行うもので, 最も古典的で現在もよく使われている方法です。 対称鍵暗号とか共通鍵暗号 (symmetric-key cipher) などと呼ばれることもあります。 通常は暗号化に使った鍵を使って暗号化の逆手順を行うことで復号化できます。 対称暗号は暗号化/復号化の処理が速いので各方面で重宝されますが, 鍵を共有するための 「安全な」 ネゴシエーションが要求されます。
後述しますが, PGPではメッセージの暗号に対称暗号を用いています。 PGPで使われている対称暗号アルゴリズムとしては IDEA, Triple-DES, CAST5, Blowfish, AES (Rijndael 128,192,256), Twofish があります。
1997年に, NIST (National Institute of Standards and Technoloty) はDESに代わる新たな暗号を一般から募集しました。 これが AES (Advanced Encription Standart) 構想です。 選考の結果 Rijndael が採択されました。 (FIPS-197)
1970年代に発明されたこの画期的なアイデアにより, 普通の人でも手軽に暗号を利用できるようになりました。 (それまでの対称暗号では,鍵の配布と管理に膨大なコストがかかるため, 政府や軍あるいは大企業以外では暗号は扱いかねるものでした) 公開鍵暗号は暗号化する鍵と復号化する鍵が別になっており, さらに暗号化する鍵 (公開鍵 (public key) と呼ばれています) が公開可能であることが特徴です。 このアルゴリズムの基本原理は, 落し戸関数 (trap door function) あるいは一方向関数 (one-way function) と呼ばれているもので, 離散対数や素因数分解などの数学的な特徴を逆手に取ったものです。
公開鍵暗号の最大の利点は, 鍵共有のためのネゴシエーションが不要なことです。 公開鍵暗号を用いれば全く未知の人から暗号化メッセージをもらうこともできます。 さらに公開鍵暗号は, 電子署名としての応用ができます。 暗号化/復号化の手順を逆にする (厳密にはちょっと違いますが) ことにより, メッセージの発信元が確かに 「本人」 の物であることを証明できます。 またメッセージの配信途中で改竄された場合でも 「改竄されている」 ことを検出できます。 (どのように改竄されたかまでは分かりません)
一方, 公開鍵暗号は 「非常に遅い」 アルゴリズムとしても有名です。 リアルタイム性が要求される場合やメッセージ量が非常に大きい場合には向きません。
PGPでは 「速い」 対称暗号と 「強力な」 公開鍵暗号を相補的に組み合わせています。 PGPで使われている公開鍵暗号アルゴリズムとしては RSA, ElGamal, DSA (電子署名専用) があります。
PGP 5.x では Diffie-Hellman (DH) と表記されていますが, これは厳密には (その改良版である) ElGamal が正しいです。 (Diffie-Hellman はリアルタイム通信での鍵交換のためのアルゴリズムなので, PGPのようなメッセージ暗号とはちょっと違う) また, PGP 5.x の DSS (Degital Signature Standard) 表記も厳密には DSA (Degital Signature Algorithm) とするべきです。 以前は DSS=DSA でしたが, 最近はDSSにRSAなどの他の署名アルゴリズムを使ってもいいことになっていて, いまや DSS≠DSA なのです。 (DSA は DSS のひとつですが, DSS の方式は DSA だけではないということです)
公開鍵暗号を応用してメッセージに電子署名を添える場合の問題点は,
です。 そこで, メッセージ本体を短い数値列に 「要約」 することが考えられました。 これがメッセージ要約と呼ばれるもので, そのためのアルゴリズムとして MD5, SHA-1, RIPE-MD/160 といった一方向ハッシュ関数 (one-way hash function) が用いられています。 ちなみに公開鍵の鍵指紋 (key-fingerprint) も, 公開鍵の上記アルゴリズム (大抵は MD5 か SHA-1) によるハッシュ値です。
この章以降の説明は, 主に OpenPGP を元にしています。 したがって, PGP 2.6.x や PGP 5.x では動作が異なる場合があります。 あらかじめご了承ください。 (分かっている部分については, その都度フォローします)
私たちが作成する鍵は対になっていて, 「鍵ペア」 (keypair) と呼ばれています。 ひとつは 「公開鍵」 (public key), もうひとつは秘密鍵 (secret key) です。 公開鍵は鍵ペアから抜き出して公開することができます。
公開鍵は1個の公開鍵パケット (public key packet) と0個以上の公開サブ鍵パケット (public subkey packet) で構成されています。 公開鍵パケットはトップレベル鍵とも呼ばれ, 主に署名検証に用います。 公開サブ鍵パケットは暗号化処理に用います。
ElGamal鍵および PGP 2.6.x 用のRSA鍵にはサブ鍵パケットがなく, 公開鍵パケットを署名検証および暗号化処理両方に用います。 また OpenPGP では 「署名専用アプリケーション」 を許容しているため, 署名検証専用の公開鍵も存在します。
更に公開鍵にはユーザIDパケット (1個以上) や鍵パケットへの署名パケット (0個以上) などが含まれます。
署名がひとつもない鍵は信用されません。 (よって使うことができません) PGPで普通に鍵を作成すると自身による署名パケットが必ず付加されます。
秘密鍵は1個の秘密鍵パケット (secret key packet) と0個以上の秘密サブ鍵パケット (secret subkey packet) で構成されています。 秘密鍵パケットはトップレベル鍵とも呼ばれ, 主に署名に用います。 秘密サブ鍵パケットは復号化処理に用います。 秘密 (サブ) 鍵パケットには公開 (サブ) 鍵パケットの情報も含まれています。
ElGamal鍵および PGP 2.6.x 用のRSA鍵にはサブ鍵パケットがなく, 秘密鍵パケットを署名および復号化処理両方に用います。 また OpenPGP では 「署名専用アプリケーション」 を許容しているため, 署名専用の鍵も存在します。
更に秘密鍵にはユーザIDパケット (1個以上) や鍵パケットへの署名パケット (0個以上) などが含まれます。
署名がひとつもない鍵は信用されません。 (よって使うことができません) PGPで普通に鍵を作成すると自身による署名パケットが必ず付加されます。
秘密 (サブ) 鍵パケットの秘密情報は対称暗号によって暗号化される場合があります。 (通常は暗号化されます) 暗号の鍵はパスフレーズから生成 (S2K: string-to-key) されます。 PGP 2.6.x ではパスフレーズのMD5ハッシュ値を鍵としてIDEAで暗号化します。 PGP 5.x 以降では, パスフレーズにソルト値を加えた上でハッシュします。 (ソルトS2K (Salted S2K)) またソルトS2Kを更に強化するために, ソルトS2Kを繰り返す場合もあります。 (累積ソルトS2K (Iterated and Salted S2K))
ソルトS2Kや累積ソルトS2Kを行うことによって, パスフレーズへの単純な 「辞書攻撃」 からある程度防衛できます。 ただし, S2Kに関する情報 (S2K識別子) 自体は暗号化されないため, 依然として 「解読されやすいパスフレーズ」 が危険であることに変わりありません。
PGP 5.x 以降で秘密鍵を暗号化する際, 対称暗号およびメッセージ要約の方式を選択する方法については後述します。
現在使われている鍵ペアの鍵パケットには Version 3 (V3) と Version 4 (V4) の2種類の形式があります。 (V3より前の形式は使ってはならないことになっています) PGP 2.6.x はV3のみサポートしています。 PGP 5.x 以降ではV4を使います。 V3はセキュリティ上の欠点 (OpenPGP 5.5.2章参照) があるため推奨されていません。 またRSA鍵以外の鍵を生成する場合にはV3を使うことができません。
PGPの暗号化/復号化処理は 対称暗号と公開鍵暗号を組み合わせた 「ハイブリッド暗号」(Hybrid cyphers) です。 暗号化処理を行う場合は, まずメッセージを対称暗号で暗号化し, その対称暗号の鍵情報を公開鍵で暗号化 (公開鍵暗号セッション鍵パケット (public-key encrypted session key packet)) して暗号化メッセージ (共通鍵暗号データパケット (symmetrically encrypted data packet)) に添付します。 復号化処理はその逆手順です。 受信メッセージから鍵情報とメッセージ情報を分離し, まず鍵情報を秘密鍵で復号化します。 そして復号化した鍵を使ってメッセージを復号化します。
メッセージの暗号に使われる鍵は 「セッション鍵」(session key) と呼ばれています。 セッション鍵は一度きりで使い捨てられる鍵で, 暗号化処理の度に擬似乱数から生成されます。 毎回異なる鍵を使うことによりクラッキングによるメッセージ解読をより困難なものにします。
PGPでは通常のメッセージの暗号化の他に対称暗号のみを使った暗号化/復号化を行うこともできます。 この場合の対称暗号の鍵は任意のパスフレーズをS2K処理した値を用います。 PGP 2.6.x ではパスフレーズのMD5ハッシュ値を鍵としてIDEAで暗号化します。 PGP 5.x 以降では, 通常ソルトS2Kや累積ソルトS2Kを用いてパスフレーズから鍵を生成します。 この場合, 暗号方式やS2K識別子は 「共通鍵暗号セッション鍵パケット」(symmetric-key encrypted session-key packet) に格納され,暗号化メッセージに添付されます。
対称暗号のみを使った暗号化は, パスフレーズについてあらかじめ合意しておく必要があります。 これは通常のPGPの暗号よりも弱いといえますが, コミュニティ内の使い捨ての情報のやりとりなら, この程度の暗号強度でも運用できる場合もあります。
PGP 2.6.x では対称暗号はIDEAのみでしたが, PGP 5.x 以降では複数のアルゴリズムから選択することができます。 これらのアルゴリズムはユーザが明示的に指定することもできますが, そうでない場合はどうやって決めているのでしょう。
実は鍵への署名パケット (V4のみ) には 「共通鍵暗号方式設定」(preferred symmetric algorithms) の情報が含まれていることがあります。 この中に使用すべき対称暗号方式が優先度の高い順に設定されています。 鍵への署名パケットに 「共通鍵暗号方式設定」 がない場合は, アプリケーションのデフォルトが使われます。 この情報は鍵ペア生成時および鍵ペア情報 (有効期限等) の変更時に, 使用してるアプリケーションのデフォルトにセットされます。
アプリケーションのデフォルトは, PGPの製品やバージョンごとに決まっています。 (「GNU Privacy Gard 講座」 の 「PGP、GnuPG各バージョンの標準アルゴリズムは?」 参照) ちなみに, 秘密鍵の暗号化と対称暗号のみを使ったメッセージの暗号でも (ユーザが明示しない限り) アプリケーションのデフォルトが使われます。
電子署名では, メッセージそのものを処理するのではなく, 被署名メッセージのハッシュ値に対し署名データを生成します。 メッセージの受信者は, 相手の公開鍵で署名データを復号し, 一方で元メッセージのハッシュ値を求めます。 復号して得られたハッシュ値と元メッセージのハッシュ値を比較することにより検証を行います。 PGPでは, メッセージ署名だけでなく, さまざまな場面 (鍵への署名もそのひとつです) で署名処理を行っています。
したがって, 電子署名がうまく運用できるかどうかは, メッセージ要約を行うハッシュ関数の性能にかかっています。
署名データを格納する署名パケットには Version 3 (V3) と Version 4 (V4) の2種類の形式があります。 PGP 2.6.x はV3のみサポートしています。 OpenPGP ではV4が推奨されています。 PGP 5.x は製品によって違うのですが, 最新のバージョン (PGP 7.x) 以外はV4に対応していないようです。 (ただし PGP 6.5.8ckt の最新版はV4に対応していました)
鍵への署名パケット (V4のみ) には 「ハッシュ方式の設定」(preferred hash algorithms) の情報が含まれていることがあります。 この中に使用すべきハッシュ関数が優先度の高い順に設定されています。 鍵への署名パケットに 「ハッシュ方式の設定」 がない場合は, アプリケーションのデフォルトが使われます。 この情報は鍵ペア生成時および鍵ペア情報 (有効期限等) の変更時に, 使用してるアプリケーションのデフォルト値にセットされます。
PGP 5.x 以降では, ほぼ SHA-1 がデフォルトになっているようです。 ただし, GnuPG の新しいバージョンでは RIPE-MD/160 がデフォルトになっているように見えます。 MD5はセキュリティ上の弱点が指摘されているので OpenPGP では推奨されていません。 (13章参照)
PGP 2.6.x ではハッシュ関数としてMD5を使います。
PGPでは暗号化の前または署名処理のあとにメッセージを圧縮する場合があります。 圧縮アルゴリズムには ZIP, ZLIB などがあります。
鍵への署名パケット (V4のみ) には 「圧縮方式の設定」(preferred compression algorithms) の情報が含まれていることがあります。 この中に使用すべき圧縮方式が優先度の高い順に設定されています。 鍵への署名パケットに 「圧縮方式の設定」 がない場合にはアプリケーションのデフォルトが使われます。 この情報は鍵ペア生成時および鍵ペア情報 (有効期限等) の変更時に, 使用してるアプリケーションのデフォルト値にセットされます。
GnuPG の一部のバージョンはZLIBを使っていたようですが, 最近はZIPになってるようです。