GnuPGを使おう

GnuPGとは

平文(ひらぶん)を暗号文にすることを暗号化といいます。暗号文を平文に戻すことを復号といいます。

暗号化の鍵と復号の鍵とが同じ暗号を、共通鍵暗号または対称鍵暗号といいます。両方の鍵が異なる暗号で、暗号化の鍵から復号の鍵を導けないものを、公開鍵暗号といいます。公開鍵暗号なら、暗号化の鍵を公開しても、復号の鍵を持っている人にしか復号できないので、安心です。

GnuPG(グヌー・ピー・ジー、GNU Privacy Guard)は、オープンソースの暗号化ツールです。共通鍵暗号にも公開鍵暗号にも対応しています。Windows、Mac、Linuxなどで使えます。

その昔、PGP(Pretty Good Privacy)という有名な暗号化ツールがありました。これに基づいて OpenPGP という標準が作られます。GnuPGはこれを実装したものです。GnuPGのコマンド名は gpg で、PGPをもじって作られた名前であることがわかります。

GnuPGのインストール

GnuPG サイトの Download の GnuPG binary releases という表から、自分のOSに合ったものをダウンロードするのが基本です。

WindowsのWSLでUbuntuなどを使っている人は、その中のものを使うのが手っ取り早いでしょう。gpg と打ち込んでみて、GnuPGが起動したなら、Control-C で止めます。もし入っていないようなら、例えばUbuntuなら apt install gnupg と打ち込んでインストールします。

生のWindowsでは、Gpg4win が簡単そうです。Download ボタンをクリックすると、寄付するように求められますが、「$0」を選ぶと無料でダウンロードできます。ダウンロードしたインストーラを実行すると、GnuPG以外の関連ツールもインストールしようとしますので、ここではGnuPG以外のチェックを外してインストールします。デフォルトでは C:\Program Files (x86) 以下に Gpg4winGnuPG というフォルダが作られ、C:\Program Files (x86)\GnuPG\bin にパスが追加され、gpg コマンドが実行できるようになります。

Macなら Homebrew などのパッケージマネージャでインストールするのが楽でしょう。Homebrew なら brew install gnupg でできます。

gpg コマンドを試してみる

試しに gpg と打ち込むと、英語環境なら

gpg: WARNING: no command supplied.  Trying to guess what you mean ...
gpg: Go ahead and type your message ...

日本語環境なら

gpg: *警告*: コマンドが指定されていません。なにを意味しているのか当ててみます ...
gpg: 開始します。メッセージを打ってください ...

のような機械翻訳っぽい日本語メッセージが表示されますので、Control-C で止めます。

もし

gpg: WARNING: unsafe permissions on homedir '/home/okumura/.gnupg'

または

gpg: *警告*: homedir '/Users/okumura/.gnupg'の安全でない許可

のような警告が出たら、該当のディレクトリを他人に読めない設定にしてください(上の例なら chmod 700 /Users/okumura/.gnupg)。

なお、機械翻訳っぽい日本語メッセージが嫌なら、LANG=en_US.UTF-8 gpg のようにコマンドの頭に言語指定を付けてください。

共通鍵暗号(普通の暗号)

まずは、簡単な共通鍵方式で試してみましょう。デフォルトでは AES256 という強力な共通鍵暗号方式が使われます。

ターミナル(WindowsならコマンドプロンプトまたはPowerShell)を立ち上げて、暗号化したいファイル(以下では himitsu.txt とします)のあるディレクトリに移動し、次のように打ち込みます。

gpg -c himitsu.txt

すると、「Enter passphrase」または「パスフレーズを入力」のように聞かれますので,パスフレーズを2回入力します。パスフレーズはパスワードと同じ意味ですが、パスワードというと一つの単語を思い浮かべてしまうかもしれないので、単語をいくつか並べたフレーズでもいいという意味合いを込めて、ここではパスフレーズと呼んでいます。お遊びで暗号化するなら例えば hoge のような簡単な文字列をパスフレーズにしてもいいのですが、本格的に暗号化するなら、ランダムな文字列または単語をいくつか並べたフレーズを使い、忘れないように記録しておきましょう。

パスフレーズ2回の打ち込みがうまくいけば、同じディレクトリに himitsu.txt.gpg というファイルができます。これが暗号化されたファイルです。

うまくいっているか確認するために、元のファイル himitsu.txt を削除してから、himitsu.txt.gpg を復号(暗号化したものを平文に戻すこと)してみましょう。

gpg himitsu.txt.gpg

さきほどのパスフレーズを打ち込むと、元のファイルが復元されます。

なお、himitsu.txt.gpg はバイナリファイルです。テキスト(ASCII)ファイルにしたい場合は、

gpg -ca himitsu.txt

のようにします(オプションは -ca でも -ac でもかまいません)。できたファイル himitsu.txt.asc はテキスト(ASCII)ファイルですので、メール本文にコピペすることもできますが、ファイルサイズはバイナリファイルより大きくなります。

公開鍵暗号

まずは、自分の鍵ペア(秘密鍵・共通鍵)を生成しましょう。次のように打ち込みます。

gpg --gen-key

すると,例えば次のようにいろいろ聞いてきます。で書いた部分が入力例です。

gpg (GnuPG) 2.3.6; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

注意: 全機能の鍵生成には "gpg --full-generate-key" を使います。

GnuPGはあなたの鍵を識別するためにユーザIDを構成する必要があります。

本名: Haruhiko Okumura
電子メール・アドレス: okumura@okumuralab.org
次のユーザIDを選択しました:
    "Haruhiko Okumura <okumura@okumuralab.org>"

名前(N)、電子メール(E)の変更、またはOK(O)か終了(Q)? O
たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。

ここでパスフレーズの入力を促されます。Windowsでは画面に gpg: AllowSetForegroundWindow(....) failed: のようなエラーメッセージが表示されるようですが、無視してください。

たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。
gpg: C:\\Users\\okumu\\AppData\\Roaming\\gnupg\\trustdb.gpg: 信用データベースができました
gpg: ディレクトリ'C:\\Users\\okumu\\AppData\\Roaming\\gnupg\\openpgp-revocs.d'が作成されました
gpg: 失効証明書を 'C:\\Users\\okumu\\AppData\\Roaming\\gnupg\\openpgp-revocs.d\\D958C0F261D9A15EBAC7001D9F111BFA5D37D00A.rev' に保管しました。
公開鍵と秘密鍵を作成し、署名しました。

pub   ed25519 2022-06-29 [SC] [有効期限: 2024-06-28]
      6B993E71B219138FD0901308BDFF7C7348C6D481
uid                      Haruhiko Okumura <okumura@okumuralab.org>
sub   cv25519 2022-06-29 [E] [有効期限: 2024-06-28]

このように、Windowsでは C:\Users\自分の名前\AppData\Roaming\gnupg の下に、それ以外では ~/.gnupg の下に、信用データベース trustdb.gpg、鍵束 pubring.gpg、秘密鍵 private-keys-v1.d/*、失効証明書 openpgp-revocs.d/* が生成されます。

できたキーの一覧を見てみましょう。

gpg --list-keys

次のように画面に出ます。

gpg: 信用データベースの検査
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: 深さ: 0  有効性:   2  署名:   0  信用: 0-, 0q, 0n, 0m, 0f, 2u
gpg: 次回の信用データベース検査は、2024-06-27です
C:\Users\okumu\AppData\Roaming\gnupg\pubring.kbx
------------------------------------------------
pub   ed25519 2022-06-29 [SC] [有効期限: 2024-06-28]
      6B993E71B219138FD0901308BDFF7C7348C6D481
uid           [  究極  ] Haruhiko Okumura <okumura@okumuralab.org>
sub   cv25519 2022-06-29 [E] [有効期限: 2024-06-28]

このように、今は EdDSA (ed25519) / ECDH (cv25519) という方式の鍵が使われるようです。

ここまでのステップでしくじったなら、MacやLinuxでは ~/.gnupg 以下、Windowsでは C:\Users\自分の名前\AppData\Roaming\gnupg 以下を消せばやりなおせます。

自分の公開鍵を表示してみましょう。

gpg -a --export

複数のキーを登録しているなら、次のように、名前かメールアドレス、または公開鍵のフィンガープリント(fingerprint、電子指紋)と呼ばれる文字列(上の --list-keys の出力で pub の次の行に表示される長い文字列)を与えます。フィンガープリントは公開鍵を16進40桁、つまり160ビットに要約したものです。

gpg -a --export 6B993E71B219138FD0901308BDFF7C7348C6D481

すると,たとえば次のように画面(標準出力)に出ます。

-----BEGIN PGP PUBLIC KEY BLOCK-----

mDMEYrum+xYJKwYBBAHaRw8BAQdAOOosMJxpPRArdsgj0i4k+cEjpB+1aBvRdiGH
U+YKCOW0KUhhcnVoaWtvIE9rdW11cmEgPG9rdW11cmFAb2t1bXVyYWxhYi5vcmc+
iJkEExYKAEEWIQRrmT5xshkTj9CQEwi9/3xzSMbUgQUCYrum+wIbAwUJA8JnAAUL
CQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRC9/3xzSMbUgX4mAQCFLJhANxpB
xqJLgT2030MxDXNkrfBYKO89E7d9QNTYyAD8DwFaNKR/PJPMFniqutmqI3fXmqgG
cmd2x+Fyrukc7gq4OARiu6b7EgorBgEEAZdVAQUBAQdAJJdg7dOiA62DrLdJDIkE
3avENkBnGiTEwWXt3W+shjcDAQgHiH4EGBYKACYWIQRrmT5xshkTj9CQEwi9/3xz
SMbUgQUCYrum+wIbDAUJA8JnAAAKCRC9/3xzSMbUgX26AP0W90RO3gaaZXu4tCE7
j+pAXaMbIiNsnT66Z5WIXfaxVwD/dCfNFESpjjyI9/nMEB0SrSIk9sNjdHnwLdMS
SbYQJgU=
=/YnU
-----END PGP PUBLIC KEY BLOCK-----

この公開鍵は自分のサイトで公開しておくと便利です。例えば私の公開鍵は私のサイトで公開しています。さらに、MIT PGP Public Key Server などの公開鍵サーバにも登録しておくとよいかもしれません。

公開鍵を特定するためには、フィンガープリントがよく使われます。フィンガープリントは16進4桁ずつスペースで区切って

6B99 3E71 B219 138F D090 1308 BDFF 7C73 48C6 D481

のように表記するのが便利です。メールの署名に入れたり、名刺に印刷したりすることもあります。公開鍵を使ってメッセージを送るときは、その公開鍵が正しいことを、本人から名刺などで直接もらったフィンガープリントで確認すれば安心です。

複数の公開鍵を持っている場合は、デフォルトの鍵のフィンガープリントを ~/.gnupg/gpg.conf というファイルに

default-key 6B993E71B219138FD0901308BDFF7C7348C6D481

のように書き込んでおくと便利です。

公開鍵でメッセージをやりとりする

まず、メッセージを送りたい友人(たとえば奥村氏)の公開鍵をもらってきて、自分の「鍵束」(keyring)に登録します。

奥村氏の公開鍵(上のようなテキスト形式のもの)が okumura.asc というファイルに入っているとしましょう。

gpg --import okumura.asc

これで奥村氏の公開鍵が自分の鍵束に登録できました。gpg --list-keys で確認してください。

ファイル himitsu.txt を奥村氏 okumura@okumuralab.org だけに読めるように暗号化してみましょう。

gpg -ear okumura@okumuralab.org himitsu.txt

受取人が複数の場合は、次のように複数指定できます:

gpg -ear okumura@okumuralab.org -r okumura@edu.mie-u.ac.jp himitsu.txt

すると、himitsu.txt.asc というテキスト(ASCII)ファイルができますので,それを送ります。バイナリファイルのほうがよければ、オプションを -ear でなく -er にします。その場合、暗号ファイル名は himitsu.txt.gpg になります。

奥村氏は、受け取ったファイルを復号するには,単に次のように打ち込みます。

gpg himitsu.txt.asc

自分の秘密鍵のパスフレーズを入力すると、復号して、平文が標準出力(画面)に出力されます。

次のように -o オプションで出力ファイル名を指定することもできます。

gpg -o himitsu.txt himitsu.txt.asc

メールの署名を検証する

メールが本物か、改ざんされていないかを検証するために、PGP署名が付いていることがあります。例えば Apple の Apple Product Security メールにはこの公開鍵で検証できる署名が付いていますし、JPCERT からのメールはこの公開鍵で検証できる署名が付いています。

こういったメールを検証するには、あらかじめ公開鍵を gpg --import ファイル名 でインポートしておき、メッセージを Apple のメールなら(base64を展開した)UTF-8、JPCERT のメールなら ISO-2022-JP で保存し、gpg --verify ファイル名 で検証します。改行コードは CR LF を仮定しますが、テキストモードで署名された場合は LF でもかまわないようです。内容が正しければ

gpg: 火  5/17 08:00:14 2022 JSTに施された署名
gpg:                RSA鍵78F88B5B532B323C35F57CE8782F6A283D69AE18を使用
gpg: "Apple Product Security <product-security@apple.com>"からの正しい署名 [不明の]
gpg: *警告*: この鍵は信用できる署名で証明されていません!
gpg:       この署名が所有者のものかどうかの検証手段がありません。
 主鍵フィンガープリント: 78F8 8B5B 532B 323C 35F5  7CE8 782F 6A28 3D69 AE18

改ざんがされていれば

gpg: 火  5/17 08:00:14 2022 JSTに施された署名
gpg:                RSA鍵78F88B5B532B323C35F57CE8782F6A283D69AE18を使用
gpg: "Apple Product Security "からの*不正な*署名 [不明の]

のようなメッセージが出力されます。「この鍵は信用できる署名で証明されていません」という警告が出ますが、この場合はしかたがありません(ネットから得た公開鍵を信頼できるものとして自分で署名すれば警告が出なくなりますが、特に必要はないでしょう)。

メールに署名する

あらかじめメールの内容をテキストファイルとして作成します。例:

This is a test.

これはテストです。

文字コードはあらかじめ同意しておく必要があります(伝統的に日本語はISO-2022-JPにしていましたが、今後はUTF-8に統一されるでしょう)。行末は何でもかまいません。gpg --clearsign ファイル名 と打ち込みます。拡張子 .asc の付いたファイルが生成されます。例:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

This is a test.

これはテストです。
-----BEGIN PGP SIGNATURE-----

iHUEARYKAB0WIQRrmT5xshkTj9CQEwi9/3xzSMbUgQUCYskSVgAKCRC9/3xzSMbU
gWzeAP9uB4TG3bAzsgWziZM26I3UIeDERe8W1yHVRI8qxVLm/wD+KrfxGLaapzuf
QtK1YoMmR8B5KIF3D5jaiiFX63QRLwU=
=mWlV
-----END PGP SIGNATURE-----

これをメール本文にして送ります。