gpg (GNU Privacy Guard)の使い方

  • 17
    いいね
  • 0
    コメント

はじめに

軽いノリでgitコミットに署名しようとgpg (GNU Privacy Guard)について調べたところ、思いの外複雑で全体像を把握するのに苦労しました。

そこでgpgに頭を悩ませている人を一人でも多く救うべく、この記事を書きました。内容に誤りがありましたら、修正リクエストを送っていただけると幸いです。

gpgのバージョンについて

この記事を執筆している2016年9月18日の時点で、gpgには3種類のバージョンが存在し、それぞれ開発が続いています。

  • gpg modern (2.1.x)
  • gpg stable (2.0.x)
  • gpg classic (1.4.x)

gpg1.4はシングルバイナリであり、それ単体で動作します。一方gpg2.0以降は、暗号化にlibgcryptという外部のライブラリを使用しています。バージョンの違いは内部の設計の違いでしかありませんが、はじめてgpgを使うのであれば、gpg2.0以降の使用をお勧めします。

なお、この記事ではgpg 2.0.30を前提に説明を勧めます。

プライマリキーとサブキーについて

さて、gpgの使い方について説明を始める前に、まずはプライマリキーとサブキーについて説明します。すでにご存知という方は、このセクションを読み飛ばしてください。

プライマリキーとサブキーの関係

公開鍵暗号における鍵は、公開鍵と秘密鍵の組み合わせで構成されます。これら2つの鍵の組み合わせを鍵ペアと呼びます。そして、主となる鍵ペアをプライマリキーと呼び、プライマリキーに紐付いた鍵ペアをサブキーと呼びます。

プライマリキーの特徴

GnuPGにおけるプライマリキーは署名に使用されます。プライマリキーはサブキーを紐付けるための鍵ペアですから、その存在は極めて重要です。プライマリキーの秘密鍵さえ盗んでしまえば、所有者になりすまして署名することができますし、紐付けられているサブキーをすべて失効させて、新しいサブキーで置き換えることもできます。したがって、プライマリキーの秘密鍵は絶対に漏洩しないよう厳重に保管する必要があります。

サブキーの特徴

GnuPGにおけるサブキーは暗号化に使用されます。(署名にも使用できます。)サブキーはプライマリキーに対して自動的に紐付けられますが、サブキー同士は独立しています。そのため、新しいサブキーはいつでも追加できますし、不要になったサブキーは個別に失効できます。

そして、サブキーの失効が、プライマリキーの信用度に影響を与えることはありません。たとえば盗まれたのがサブキーの秘密鍵だけで、プライマリキーの秘密鍵が手元に残っていた場合、盗まれたサブキーを失効させて新しいサブキーで置き換えることができます。その際に自分のプライマリキーの信頼を構築し直す必要はありませんし、自分のプライマリキーを使って署名した他人のプライマリキーの信頼度が低下することもありません。

プライマリキーとサブキーの作成について

ここからgpgの使い方についての説明となります。まずは二者間でセキュアなコミュニケーションができるように、プライマリキーとサブキーを作成します。手順は次のとおりです。

  1. プライマリキーとサブキーを作成
  2. プライマリキーに対する失効証明書を作成
  3. 作成したプライマリキーとサブキーを確認

それではステップに沿って説明を進めます。

プライマリキーとサブキーを作成

プライマリキーとサブキーを作成するには、gpgに--gen-keyを指定します。さらに、--batchを指定することで設定ファイルを元に鍵ペアを自動で作成することができます。

以下に、Aliceがalice.confという設定ファイルを元にプライマリキーとサブキーを作成する場合の例を示します。

alice.conf

# "#"で始まる行はコメントです。
# %で始まる行は、gpgを制御するためのコマンドです。
# 設定ファイルはUTF-8で保存してください。 (詳細については、以下のドキュメントを参照)
# 
# Unattended GPG key generation - Using the GNU Privacy Guard
# https://www.gnupg.org/documentation/manuals/gnupg/Unattended-GPG-key-generation.html

# プライマリキーをRSA 496 bitとして設定
Key-Type: RSA
Key-Length: 4096

# サブキーをRSA 496 bitとして設定
Subkey-Type: RSA
Subkey-Length: 4096

# プライマリキー及びサブキーの有効期間を2年に設定 (有効期間は必ず設定してください。)
Expire-Date: 2y

# 名前とメールアドレスを設定
Name-Real: Alice
Name-Email: alice@example.com

# パスフレーズを設定 (大文字小文字・数字・記号を混ぜた安全なパスフレーズを指定してください)
Passphrase: ********

# 上記の内容で鍵ペアを作成
%commit
%echo 🍺 Successfully done

それでは、alice.confを使用して鍵ペアを作成する場合の例を示します。

# Aliceのマシンにて
$ gpg --gen-key --batch alice.conf
gpg: directory `/home/alice/.gnupg' created
gpg: new configuration file `/home/alice/.gnupg/gpg.conf' created
gpg: WARNING: options in `/home/alice/.gnupg/gpg.conf' are not yet active during this run
gpg: keyring `/home/alice/.gnupg/secring.gpg' created
gpg: keyring `/home/alice/.gnupg/pubring.gpg' created
gpg: /home/alice/.gnupg/trustdb.gpg: trustdb created
gpg: key C8A2005E marked as ultimately trusted
gpg: 🍺 Successfully done

以上で、プライマリキーとサブキーの作成は完了です。

プライマリキーに対する失効証明書を作成

プライマリキーとサブキーの作成が終わったら、直ちにプライマリキーに対する失効証明書を作成する必要があります。gpgに--gen-revokeを指定し、失効証明書を作成してください。

以下に、Aliceがrevoke.ascというファイル名で失効証明書を作成する場合の例を示します。最初に失効証明書を作成する理由を尋ねられますが、ここでは0番のNo reason specified (理由なし)を選択してください。また、説明についても空欄のママで問題ありません。

# Aliceのマシンにて
$ gpg --output revoke.asc --gen-revoke alice@example.com

sec  4096R/C8A2005E 2016-09-17 Alice <alice@example.com>

Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
  0 = No reason specified
  1 = Key has been compromised
  2 = Key is superseded
  3 = Key is no longer used
  Q = Cancel
(Probably you want to select 1 here)
Your decision? 0
Enter an optional description; end it with an empty line:
>
Reason for revocation: No reason specified
(No description given)
Is this okay? (y/N) y
You need a passphrase to unlock the secret key for
user: "Alice <alice@example.com>"
4096-bit RSA key, ID C8A2005E, created 2016-09-17

Enter passphrase:
ASCII armored output forced.
Revocation certificate created.

Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable.  But have some caution:  The print system of
your machine might store the data and make it available to others!

作成した失効証明書は紛失しないよう保管には十分注意してください。たとえば暗号化したUSBメモリに保存しておくと安全です。ただし、そのUSBメモリ自体を紛失しないように注意してください。

以上で、プライマリキーに対する失効証明書の作成は完了です。なお、失効証明書とは何か、いつ使うのかについては補足をご覧ください。

作成したプライマリキーとサブキーを確認

gpgに--list-keysまたは-kを指定すると保存されている公開鍵の一覧が表示されます。また、--list-secret-keysまたは-Kを指定すると保存されている秘密鍵の一覧が表示されます。

以下に、Aliceが作成したプライマリキーの公開鍵とサブキーの公開鍵の情報を確認する場合の例を示します。

# Aliceのマシンにて
$ gpg -k
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2018-09-17
/home/alice/.gnupg/pubring.gpg
-----------------------------
pub   4096R/C8A2005E 2016-09-17 [expires: 2018-09-17]
uid       [ultimate] Alice <alice@example.com>
sub   4096R/041C01EF 2016-09-17 [expires: 2018-09-17]

pubで始まる行がプライマリキーの公開鍵の情報、subで始まる行がサブキーの公開鍵の情報となります。続いて、プライマリキーの秘密鍵とサブキーの秘密鍵の情報を確認します。

# Aliceのマシンにて
$ gpg -K
/home/alice/.gnupg/secring.gpg
-----------------------------
sec   4096R/C8A2005E 2016-09-17 [expires: 2018-09-17]
uid                  Alice <alice@example.com>
ssb   4096R/041C01EF 2016-09-17

secで始まる行がプライマリキーの秘密鍵の情報、ssbで始まる行がサブキーの秘密鍵の情報となります。

以上が、プライマリキーとサブキーを作成する手順となります。

公開鍵の交換について

さて、プライマリキーとサブキーが作成できました。続いて、メッセージの署名および暗号化したメッセージの送受信ができるように公開鍵を通信相手と交換する手順を説明します。

公開鍵の交換方法は次のとおりです。

  1. 公開鍵ファイルをエクスポート
  2. 公開鍵ファイルを交換
  3. 公開鍵ファイルをインポート
  4. 公開鍵ファイルの改ざんの有無を検証
  5. 公開鍵を信頼
  6. 公開鍵の信用度を確認

それでは、AliceとBlakeがお互いの公開鍵を交換する場合を例に説明を進めます。

公開鍵ファイルをエクスポート

まずは、各々の公開鍵を--exportを指定してファイルに書き出します。

なお、冒頭で説明したとおり、サブキーはプライマリキーに紐付いています。プライマリキーの公開鍵をエクスポートして、次にサブキーの公開鍵をエクスポートして...と、個別に公開鍵をエクスポートする必要はありません。ユーザー名またはメールアドレスを指定するだけで、プライマリキーの公開鍵とサブキーの公開鍵をエクスポートできます。

# Aliceのマシンにて
$ gpg --output alice.gpg --export alice@example.com

# Blakeのマシンにて
$ gpg --output blake.gpg --export blake@example.com

以上で、Aliceはalice.gpgとして、Blakeはblake.gpgとして公開鍵ファイルをエクスポートできました。

公開鍵ファイルを交換

公開鍵は文字通り公開されていなければ暗号化も署名もできません。互いに通信したい相手の公開鍵が入手できれば問題ないので、GistやDropboxにアップロードするなどして、両者の間で公開鍵を交換してください。公開鍵を交換する手段はなんでも構いません。

それでは、AliceとBlakeの間でお互いの公開鍵が交換できたものとして、次のステップに進みます。

公開鍵ファイルをインポート

公開鍵か交換できたら、各々のマシンで受け取った公開鍵を取り込みます。gpgに--importを指定することで、公開鍵を取り込むことができます。

# Aliceのマシンにて
$ gpg --import blake.gpg
gpg: key 5B35859A: public key "Blake <blake@example.com>" imported
gpg: key 85051043: public key "Blake <blake@example.com>" imported
gpg: Total number processed: 2
gpg:               imported: 2  (RSA: 2)

# Blakeのマシンにて
$ gpg --import alice.gpg
gpg: key C8A2005E: public key "Alice <alice@example.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

以上で、公開鍵のインポートは完了です。

公開鍵ファイルの改ざんの有無を検証

最後に、受け取った公開鍵が改ざんされていないか、--fingerprintを比較して検証します。

以下に、AliceがBlakeから受け取った公開鍵の改ざんの有無を検証する場合の例を示します。

# Aliceのマシンにて
$ gpg --fingerprint blake@example.com
pub   4096R/85051043 2016-09-18 [expires: 2018-09-18]
      Key fingerprint = 1003 2D54 870B BB18 78C4  8F4B CE0E A33C 8505 1043
uid       [ unknown] Blake <blake@example.com>
sub   4096R/7726B5D5 2016-09-18 [expires: 2018-09-18]

# Blakeのマシンにて
$ gpg --fingerprint blake@example.com
pub   4096R/85051043 2016-09-18 [expires: 2018-09-18]
      Key fingerprint = 1003 2D54 870B BB18 78C4  8F4B CE0E A33C 8505 1043
uid                  Blake <blake@example.com>
sub   4096R/7726B5D5 2016-09-18 [expires: 2018-09-18]

たとえば、AliceがBlakeから受け取った公開鍵を検証する場合、「Blakeから受け取ったフィンガープリントは、1003 2D54 ...だったけど、合ってる?」とBlake本人に尋ねます。このとき、確実にBlake本人と通信できる手段を用いて質問をする必要があります。例えば、facebookのメッセンジャーやメール、電話などが利用できます。そして、フィンガープリントが一致していれば、つまり公開鍵ファイルに改ざんが無ければ、AliceがBlakeから受け取った公開鍵は確実にBlake本人が作成したものであると信用できます。同様の手順で、BlakeはAliceから受け取った公開鍵ファイルの改竄の有無を検証することができます。

以上で、公開鍵ファイルの改竄の有無の検証は完了です。

公開鍵を信頼

さて、受け取った公開鍵に改ざんが無いことを確認できたので、この公開鍵は信用することができます。gpgに公開鍵を信頼するよう伝えるには、--sign-keyを使います。
以下に、AliceがBlakeから受け取った公開鍵を信頼するように設定する場合の例を示します。

# Aliceのマシンにて
$ gpg --sign-key blake@example.com

pub  4096R/85051043  created: 2016-09-18  expires: 2018-09-18  usage: SCEA
                     trust: unknown       validity: unknown
sub  4096R/7726B5D5  created: 2016-09-18  expires: 2018-09-18  usage: SEA
[ unknown] (1). Blake <blake@example.com>


pub  4096R/85051043  created: 2016-09-18  expires: 2018-09-18  usage: SCEA
                     trust: unknown       validity: unknown
 Primary key fingerprint: 1003 2D54 870B BB18 78C4  8F4B CE0E A33C 8505 1043

     Blake <blake@example.com>

This key is due to expire on 2018-09-18.
Are you sure that you want to sign this key with your
key "Alice <alice@example.com>" (C8A2005E)

Really sign? (y/N) y
     ┌────────────────────────────────────────────────────────────────────────────────────┐
     │ Please enter the passphrase to unlock the secret key for the OpenPGP certificate:  │
     │ "Alice <alice@example.com>"                                                        │
     │ 4096-bit RSA key, ID C8A2005E,                                                     │
     │ created 2016-09-17.                                                                │

これで、AliceはBlakeから受け取った公開鍵を信頼して使用できるようになりました。同様の手順で、BlakeはAliceから受け取った公開鍵を信頼するように設定することができます。

以上で、公開鍵を信頼する設定は完了です。

公開鍵の信用度を確認

念のため、もう一度AliceがBlakeから受け取った公開鍵のフィンガープリントを確認します。

# Aliceのマシンにて
$ gpg --fingerprint blake@example.com
pub   4096R/85051043 2016-09-18 [expires: 2018-09-18]
      Key fingerprint = 1003 2D54 870B BB18 78C4  8F4B CE0E A33C 8505 1043
uid       [  full  ] Blake <blake@example.com>
sub   4096R/7726B5D5 2016-09-18 [expires: 2018-09-18]

AliceがBlakeの公開鍵を信頼する前はuidの行にunknownと表示されていましたが、今はfullと表示されています。これは、Blakeの公開鍵を信頼しているという状態を意味します。同様の手順でBlakeもAliceの公開鍵を確認することができます。

以上で、公開鍵の交換は完了です。

公開鍵サーバーを利用した公開鍵の交換について

さて、長々と手動で公開鍵を交換する方法を説明しましたが、実は公開鍵サーバーという便利なものがあります。公開鍵サーバーへ公開鍵を登録することで、公開鍵をエクスポートして交換してインポートするという一連の作業を省くことができます。GistやDropboxに公開鍵をアップロードする必要はなかったのです。

公開鍵サーバーを利用して公開鍵を交換する手順は、次のとおりです。

  1. 登録する公開鍵のIDを確認
  2. 公開鍵をサーバーへ登録
  3. 公開鍵サーバーから公開鍵を検索して取得

公開鍵サーバーとして広く利用されているのは、MITが運用しているpgp.mit.eduです。以下に、Aliceが自身の公開鍵をpgp.mit.eduへ登録し、Blakeがそこから公開鍵を取得する場合の例を示します。

登録する公開鍵のIDを確認

gpgで公開鍵をサーバーへ登録する際には、ユーザー名やメールアドレスではなく、公開鍵のIDを指定する必要があります。そこで、最初にgpgに--list-keysまたは-kを指定して公開鍵サーバーへ登録する公開鍵のIDを確認します。

以下に、Aliceが自身の公開鍵のIDを確認する場合の例を示します。

# Aliceのマシンにて
$ gpg -k alice@example.com
pub   4096R/C8A2005E 2016-09-17 [expires: 2018-09-17]
uid       [ultimate] Alice <alice@example.com>
sub   4096R/041C01EF 2016-09-17 [expires: 2018-09-17]

まず、pubから始まる行を探してください。4096R/C8A2005Eという部分の/より後ろの部分が公開鍵のIDとなります。ちなみに、/より前の部分は、公開鍵が4096 bitの鍵長で、暗号化アルゴリズムとしてRSAを利用していることを意味します。

以上で、公開鍵のIDが確認できました。

公開鍵をサーバーへ登録

Aliceの公開鍵のIDは、C8A2005Eです。それでは、--keyserverで公開鍵サーバーのアドレスを、--send-keysで公開鍵のIDを指定して公開鍵を登録します。

# Aliceのマシンにて
$ gpg --keyserver pgp.mit.edu --send-keys C8A2005E
gpg: sending key C8A2005E to hkp server pgp.mit.edu

なお、一度公開鍵サーバーに送信した公開鍵は、失効することはできても完全に削除することはできません。公開鍵を送信する際は有効期限が設定されていることを必ず確認してください。

以上で公開鍵サーバーへの登録は完了です。

公開鍵サーバーから公開鍵を検索して取得

公開鍵サーバーから公開鍵を検索して取得するには、gpgに--search-keysを指定します。検索クエリとしては、ユーザーの名前、メールアドレス、公開鍵のIDが指定できます。

さて、前のステップでAliceの公開鍵をサーバーへ送信する例を示しましたが、あくまで例であって実際には送信していません。そこで、検索クエリとしてAliceの代わりにHashimotoを指定した場合の例を以下に示します。ちなみに、なぜHashimotoで検索したかというと、ふいにHashicorpのMitchell Hashimoto氏の名前が思い浮かんだからです。つまり、深い意味はありません。

#Blakeのマシンにて
$ gpg --search-keys Hashimoto
gpg: searching for "Hashimoto" from hkp server keys.gnupg.net
(1) Ken Hashimoto <khashimoto@lastline.com>
      4096 bit RSA key 5D7D0502, created: 2016-06-22, expires: 2020-06-22
(2) Ricardo R Hashimoto (Viva o Palmeiras!) <ricardo@hashimoto.eng.br>
      1024 bit RSA key FACCC69A, created: 2015-05-07
(3) Jerry Hashimoto <jerry.hashimoto@gmail.com>
      4096 bit RSA key F7E33B17, created: 2015-01-05
...
(11)    Kouki Hashimoto <hashimotoku@nttdata.co.jp>
      2048 bit RSA key ECA521EE, created: 2014-07-21
Keys 1-11 of 231 for "Hashimoto".  Enter number(s), N)ext, or Q)uit >

この記事を執筆している2016年9月18日の時点では、上記のような結果が得られました。たとえば、Ken Hashimotoさんの公開鍵を入手したい場合は、1を入力します。すると、公開鍵がダウンロードされて自動的にインポートされます。

以上が、公開鍵をサーバーへ登録し、登録された公開鍵を検索して入手する手順となります。

メッセージの署名と暗号化について

さて、ようやくgpgで使用する公開鍵の準備ができました。次はメッセージに署名する方法とメッセージを暗号化する方法を説明します。なお、署名および暗号化の対象となるメッセージは、テキストファイルに限りません。バイナリを含め、どんなファイルでも署名および暗号化することができます。

それでは、AliceとBlakeの間で署名されたメッセージおよび暗号化されたメッセージをやり取りする場合を例に説明を進めます。

メッセージに署名を付加

メッセージに署名を付加したい場合は、--detach-signまたは-bを指定します。そして、署名が完了すると、*.sigというファイルが作成されます。たとえば、message.txtに署名するとmessage.txt.sigというファイルが作成されます。

以下に、Aliceがmessage.txtに署名する場合の例を示します。

# Aliceのマシンにて
$ echo "Hello, everyone!" > message.txt
$ gpg -b message.txt

You need a passphrase to unlock the secret key for
user: "Alice <alice@example.com>"
4096-bit RSA key, ID 041C01EF, created 2016-09-17 (main key ID C8A2005E)

以上で、メッセージに署名を付加することができました。

メッセージに付加された署名を検証

AliceはBlakeにmessage.txtとmessage.txt.sigを送ります。BlakeはAliceの公開鍵を利用することで、message.txt.sigはAliceが作成した署名であることを検証できます。署名を検証するには、gpgに*.sigを指定します。

以下に、BlakeがAliceの公開鍵を利用してmessage.txt.sigを検証する場合の例を示します。

# Blakeのマシンにて
$ cat message.txt
Hello, everyone!
$ gpg message.txt.sig
gpg: assuming signed data in `message.txt'
gpg: Signature made Thu Sep 15 09:23:20 2016 JST using RSA key ID 34A4470D
gpg: Good signature from "Alice <alice@example.com>"

以上で、メッセージに付加された署名を検証することができました。

特定の人だけが見ることができるようにメッセージを暗号化

特定の人だけが見ることができるようにメッセージを暗号化するには--encryptまたは-eを指定します。メッセージの受取人は--recipientまたは-rで指定します。そして、暗号化が完了すると、たとえばmessage.txtに対してmessage.txt.gpgというファイルが作成されます。なお、メッセージの暗号化は、受取人のサブキーの公開鍵を使って行うので、暗号化をする前にメッセージの送信者は受取人の公開鍵を入手しておく必要があります。

以下に、AliceがBlakeのサブキーの公開鍵を使用して、Blakeだけが見ることのできるメッセージを作成する場合の例を示します。

# Aliceのマシンにて
$ echo 'Hello, Blake!' > message.txt
$ gpg -e -r blake@example.com message.txt

以上で、特定の人だけが見ることができるメッセージの作成は完了です。

特定の人だけが見ることのできるメッセージを復号化

以下に、Blakeが、Aliceから受け取ったmessage.txt.gpgを自身の秘密鍵で復号化する場合の例を示します。

# Blakeのマシンにて
$ gpg message.txt.gpg

You need a passphrase to unlock the secret key for
user: "Blake <blake@example.com>"
4096-bit RSA key, ID 7726B5D5, created 2016-09-18 (main key ID 85051043)

$ cat message.txt
Hello, Blake!

Blakeは、無事にAliceからのメッセージを復号化できました。

以上が、メッセージに署名を付加する方法と、特定の人だけが見ることのできるメッセージの作成方法となります。

プライマリキーとサブキーの有効期間を延長する方法について

ここまでで、gpgの使い方は一通り把握できたのではないかと思います。次は、作成したプライマリキーとサブキーの有効期間を延長する方法について説明します。

さて、プライマリキーとサブキーの作成方法の説明では、Aliceが有効期間を2年に設定して、プライマリキーとサブキーを作成する場合の例を示しました。この記事を執筆しているのは2016年ですから、2年後の2018年には有効期限が切れます。それでは、Aliceが作成したプライマリキーとサブキーの有効期間を2018年から3年後の2019年に変更して、有効期間を1年延長する場合を例に説明を進めます。

gpgの対話モード

gpgには、鍵ペアを管理するための対話モードが備わっています。--editを指定することで、対話モードのシェルが起動します。

# Aliceのマシンにて
$ gpg --edit C8A2005E
gpg (GnuPG) 2.0.30; Copyright (C) 2015 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>

gpg>というプロンプトが表示されて、対話モードのシェルが起動しました。以降、このシェルでプライマリキーとサブキーの有効期間を変更する作業を行います。

gpgの対話モードについての注意事項

gpgの対話モードでは、プライマリキーの有効期間を延長しても、紐付けられたサブキーの有効期間が自動的に延長されることはありません。面倒ですが、プライマリキーとサブキーは個別に有効期間を変更する必要があります。

また、対話モードのシェルで行った作業は、保存しない限り反映されません。作業が完了したらsaveと入力して変更を保存してください。なお、変更を保存せずに終了する場合は、quitと入力します。

プライマリキーの有効期間を設定

まずはkey Nと入力して編集対象の鍵ペアを選択します。Nは鍵ペアの番号であり、0がプライマリキー、1が1つめのサブキー、2が2つめのサブキーという具合に番号が割り振られています。

それでは、key 0と入力してプライマリキーを選択してください。

# プライマリキーを選択
gpg> key 0

pub  4096R/C8A2005E  created: 2016-09-17  expires: 2018-09-17  usage: SCEA
                     trust: ultimate      validity: ultimate
sub  4096R/041C01EF  created: 2016-09-17  expires: 2018-09-17  usage: SEA
[ultimate] (1). Alice <alice@example.com>

続いて、expireと入力してプライマリキーの有効期間を変更します。

# プライマリキーの有効期間を3年に変更
gpg> expire
Changing expiration time for the primary key.
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 3y
Key expires at Fri Sep 20 20:06:13 2019 JST
Is this correct? (y/N) y

You need a passphrase to unlock the secret key for
user: "Alice <alice@example.com>"
4096-bit RSA key, ID C8A2005E, created 2016-09-17


pub  4096R/C8A2005E  created: 2016-09-17  expires: 2019-09-20  usage: SCEA
                     trust: ultimate      validity: ultimate
sub  4096R/041C01EF  created: 2016-09-17  expires: 2018-09-17  usage: SEA
[ultimate] (1). Alice <alice@example.com>

以上で、プライマリキーの有効期間が変更されました。

サブキーの有効期間を設定

次はサブキーを選択します。

# サブキーを選択
gpg> key 1

pub  4096R/C8A2005E  created: 2016-09-17  expires: 2019-09-20  usage: SCEA
                     trust: ultimate      validity: ultimate
sub* 4096R/041C01EF  created: 2016-09-17  expires: 2018-09-17  usage: SEA
[ultimate] (1). Alice <alice@example.com>

続いて、プライマリキーの有効期間を変更したときと同様に、expireと入力して有効期間を設定します。

# サブキーの有効期間を3年に設定
gpg> expire
Changing expiration time for a subkey.
...

以上で、サブキーの有効期間が変更されました。

設定した有効期間を確認して保存

念のため、プライマリキーとサブキーに設定した有効期間を確認します。listと入力することでプライマリキーとサブキーの一覧が表示されます。

# プライマリキーとサブキーの一覧を表示
gpg> list

pub  4096R/C8A2005E  created: 2016-09-17  expires: 2019-09-20  usage: SCEA
                     trust: ultimate      validity: ultimate
sub* 4096R/041C01EF  created: 2016-09-17  expires: 2019-09-20  usage: SEA
[ultimate] (1). Alice <alice@example.com>

プライマリキーとサブキーの有効期限が2019年に設定されていることを確認できました。最後に、saveと入力して変更を保存すれば完了です。

# プライマリキーとサブキーに対する変更を保存
gpg> save

以上が、プライマリキーとサブキーの有効期間を変更する手順となります。

更新したプライマリキーとサブキーを公開鍵サーバーに登録

プライマリキーとサブキーの更新が終わったら、公開鍵サーバーに登録しましょう。

以下に、Aliceが更新したプライマリキーとサブキーの公開鍵をpgp.mit.eduに登録する場合の例を示します。

# Aliceのマシンにて
$ gpg --keyserver pgp.mit.edu --send-keys C8A2005E

以上で、公開鍵サーバーに登録されているプライマリキーとサブキーの有効期間が更新されました。

プライマリキーの秘密鍵がラップトップPCごと盗まれた場合に備える

ここからはgpgをより安全に使うための方法を説明します。

gpgの使い方を学習したAliceとBlakeは、快適な暗号通信ライフをenjoyしていました。

ある日、AliceはラップトップPCを載せた車でスーパーへ買物に出かけました。買い物を終えて駐車場に戻ってきたAliceは青ざめました。割れた窓ガラス、そして助手席に置いてあったラップトップPCの姿はどこにも見あたりません。「あのラップトップPCには私のプライマリキーの秘密鍵が保存されているの!今頃私のプライマリキーの秘密鍵を盗んだクソ野郎が私になりすまして世界中に署名付きの恥ずかしいポエムをばらまいているに違いないわ...」

その後、新しいラップトップPCを購入したAliceは、失効証明書を使って盗まれたプライマリキーを失効させました。幸運なことに、車上荒らしはgpgの知識を持ち合わせていなかったため、盗まれたプライマリキーを失効させるまでの間に目立った被害は確認されませんでした。そして、AliceはBlakeと暗号化されたメッセージをやり取りするためにgpgのセットアップを一からやり直したのでした。

さて、プライマリキーの秘密鍵が盗まれた場合に備える、なにか良い方法はないのでしょうか。

署名用のサブキーを追加して安全性を高める

この記事の冒頭で、サブキーについて次のように説明したことを思い出してください。

GnuPGにおけるサブキーは暗号化に使用されます。(署名にも使用できます。)

そう、サブキーは暗号化だけではなく、署名にも使えるのです。

まずはプライマリキーとサブキーを作成します。その後、プライマリキーでそのサブキーに署名すれば、プライマリキーの信用を引き継いだ署名用のサブキーが作成できます。あとは、プライマリキーの秘密鍵をUSBメモリなどにバックアップした上で、~/.gnupgディレクトリに保存されたプライマリキーの秘密鍵を削除すれば完了です。すると、ラップトップPCにはサブキーしか保存されていない状態になります。これでラップトップPCが盗まれたとしてもプライマリキーを失効させる必要はなくなりました。バックアップしておいたプライマリキーの秘密鍵を使用して、また新しく署名用のサブキーを作成すれば良いのです。

以下に、Aliceが署名用のサブキーを追加する場合の例を示します。

署名用のサブキーを追加

署名用のサブキーを追加するには、--editでgpgの対話モードを起動します。その後addkeyと入力して署名用のサブキーを追加します。あとは、通常のプライマリキーとサブキーの作成と同様に、鍵の種類と鍵の長さ、そして有効期間を指定すればサブキーが追加されます。

以下に、Aliceが署名用のサブキーを追加する場合の例を示します。なお、鍵の種類はRSA 4096 bitで有効期間は2年に設定しています。

# Aliceのマシンにて
$ gpg --edit C8A2005E
...
gpg> addkey
Key is protected.

You need a passphrase to unlock the secret key for
user: "Alice <alice@example.com>"
4096-bit RSA key, ID C8A2005E, created 2016-09-17

Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
Your selection? 4
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 2y
Key expires at Fri Sep 21 18:02:25 2018 JST
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

pub  4096R/C8A2005E  created: 2016-09-17  expires: 2018-09-17  usage: SCEA
                     trust: ultimate      validity: ultimate
sub  4096R/041C01EF  created: 2016-09-17  expires: 2018-09-17  usage: SEA
sub  4096R/AA4708D1  created: 2016-09-21  expires: 2018-09-21  usage: S
[ultimate] (1). Alice <alice@example.com>
gpg> save

これで、署名用のサブキーが追加されました。念のため、gpgに--list-keysまたは-kを指定して、署名用のサブキーが追加されているか確認します。

# Aliceのマシンにて
$ gpg -k alice@example.com
pub   4096R/C8A2005E 2016-09-17 [expires: 2018-09-17]
uid       [ultimate] Alice <alice@example.com>
sub   4096R/041C01EF 2016-09-17 [expires: 2018-09-17]
sub   4096R/AA4708D1 2016-09-21 [expires: 2018-09-21]

以上で、署名用のサブキーの追加は完了です。

追加した署名用のサブキーを公開鍵サーバーに登録

署名用のサブキーが作成できたので、これを公開鍵サーバーに登録します。

以下に、Aliceが追加した署名用のサブキーを公開鍵サーバーに登録する場合の例を示します。

# Aliceのマシンにて
$ gpg --keyserver pgp.mit.edu --send-keys C8A2005E

以上で、追加した署名用のサブキーが公開鍵サーバーに登録されました。

~/.gnupgディレクトリのバックアップの作成

プライマリキーとサブキーは~/.gnupgディレクトリに保存されています。このディレクトリをコピーして、暗号化されたUSBメモリなどに保存してください。もちろん、そのUSBメモリ自体を紛失しないように注意してください。

以下に、Aliceが~/.gnupgディレクトリをgnupg_backup.tar.gzとして圧縮し、USBメモリがマウントされたパス/path/to/usb_flash_driveにコピーする場合の例を示します。

# Aliceのマシンにて
$ cd ~
$ tar -czvf gnupg_backup.tar.gz ./.gnupg
a ./.gnupg
a ./.gnupg/gpg.conf
a ./.gnupg/private-keys-v1.d
a ./.gnupg/pubring.gpg
a ./.gnupg/pubring.gpg~
a ./.gnupg/random_seed
a ./.gnupg/secring.gpg
a ./.gnupg/trustdb.gpg
$ cp ./gnupg_backup.tar.gz /path/to/usb_flash_drive

以上で、バックアップの作成は完了です。

プライマリキーの秘密鍵を削除

残念ながら、gpgにはプライマリキーの秘密鍵だけを削除する機能はありません。そこで、まずサブキーの秘密鍵を--export-secret-keysでエクスポートした後にすべての秘密鍵を削除し、サブキーの秘密鍵をインポートすることでプライマリキーの秘密鍵だけが削除された状態を作り出します。

以下に、Aliceがプライマリキーの秘密鍵を削除する場合の例を示します。まずは、サブキーの秘密鍵をsecret_subkeys.gpgとしてエクスポートします。
```

Aliceのマシンにて

$ gpg --output secret_subkeys.gpg --export-secret-subkeys C8A2005E
```

これで、サブキーの秘密鍵はsecret_subkeys.gpgにエクスポートされました。続いて、プライマリキーとサブキーの秘密鍵を削除します。

# Aliceのマシンにて
$ gpg --delete-secret-key C8A2005E
gpg (GnuPG) 2.0.30; Copyright (C) 2015 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.


sec  4096R/C8A2005E 2016-09-17 Alice <alice@example.com>

Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y

これで、Aliceのプライマリキーの秘密鍵が削除されました。gpgに--list-secret-keysまたは-Kを指定して、秘密鍵が削除されたことを確認してください。

# Aliceのマシンにて
$ gpg -K
$

無事にすべての秘密鍵が削除されると、このように何も表示されなくなります。続いて、secret_subkeys.gpgとして退避させたサブキーの秘密鍵を読み込みます。

# Aliceのマシンにて
$ gpg --import ./secret_subkeys.gpg
gpg: key C8A2005E: secret key imported
gpg: key C8A2005E: "Alice <alice@example.com>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

これで、プライマリキーの秘密鍵だけが削除された状態になりました。念のため、秘密鍵が読み込まれているか確認します。

# Aliceのマシンにて
$ gpg -K
/home/alice/.gnupg/secring.gpg
-----------------------------
sec#  4096R/C8A2005E 2016-09-17 [expires: 2018-09-17]
uid                  Alice <alice@example.com>
ssb   4096R/041C01EF 2016-09-17
ssb   4096R/AA4708D1 2016-09-21

保存されているのは、サブキーの秘密鍵だけであることが確認できました。

以上が、プライマリキーの秘密鍵を削除する手順となります。

プライマリキーの代わりにサブキーでメッセージに署名を付加する

さて、サブキーでプライマリキーと同様に署名ができる環境は整いました。署名を付加する方法は、サブキーもプライマリキーも同じです。

以下に、Aliceがmessage.txtに署名を付加する場合の例を示します。
```

Aliceのマシンにて

$ echo "Hi, I'm Alice." > message.txt
$ gpg -b message.txt

You need a passphrase to unlock the secret key for
user: "Alice alice@example.com"
4096-bit RSA key, ID AA4708D1, created 2016-09-21 (main key ID C8A2005E)
```

以上で、サブキーを使用してメッセージに署名を付加することができました。

プライマリキーの代わりにサブキーでメッセージに付加した署名を検証

署名に使用したのがサブキーであっても、検証の方法は変わりません。

以下に、BlakeがAliceから受け取ったmessage.txt.sigを検証する場合の例を示します。

# Blakeのマシンにて
$ gpg message.txt.sig
gpg: assuming signed data in `message.txt'
gpg: Signature made Wed Sep 21 20:36:38 2016 JST using RSA key ID AA4708D1
gpg: Good signature from "Alice <alice@example.com>"

無事に、メッセージに付加された署名がAliceのものであることを確認できました。

以上が、プライマリキーの代わりにサブキーでメッセージに署名を付加する方法となります。

補足

ここからは、本文中で扱わなかった項目について説明します。

失効証明書とは何か

失効証明書は、鍵ペアを使用することがなくなった、あるいは使用できなくなった場合に該当する鍵ペアに対して適用する印のようなものです。正しくプライマリキーを管理していれば、基本的に失効証明書が必要になることはありません。

しかし、プライマリキーの秘密鍵が保存されている~/.gnupgディレクトリを誤って削除してしまった、あるいは秘密鍵のパスフレーズを忘れるなどの理由により、プライマリキーの秘密鍵を使用できなくなることがあります。その場合、使えなくなったプライマリキーを失効させる必要が生じます。また、プライマリキーの秘密鍵とそのパスワードが漏洩した場合も同様にプライマリキーを失効させる必要が生じます。

プライマリキーを失効させる方法について

この記事の冒頭で説明したとおり、プライマリキーはサブキーを紐付けるための鍵ペアです。プライマリキーを失効させると今までに築いた信頼関係がすべて失われます。プライマリキーの秘密鍵の管理は厳重に行って、そもそも失効する必要が生じないようにしてください。プライマリキーを失効させる場合は、この注意事項を踏まえた上で慎重に行う必要があります。

プライマリキーを執行させるには、まず失効証明書を--importで読み込みます。その後、失効したプライマリキーを公開鍵サーバーに登録すれば、プライマリキーの失効は完了です。以下に、Aliceがrevoke.ascを使用してプライマリキーを失効させる場合の例を示します。

# Aliceのマシンにて
$ gpg --import revoke.asc

これで、Aliceのプライマリキーは執行しました。最後に、この更新を公開鍵サーバーに登録します。

# Aliceのマシンにて
$ gpg --keyserver pgp.mit.edu --send-keys C8A2005E

以上がプライマリキーを執行させる手順となります。

プライマリキーとサブキーに有効期間を指定する理由

失効証明書を紛失した場合に、失効させる手段が無くなるからです。

たとえば、プライマリキーとサブキーに有効期間として1年を指定したとします。この場合、仮に失効証明書を紛失したとしても1年経過すれば自動的に失効します。しかし、有効期間が指定されていなければ失効することはありません。プライマリキーを登録したサーバー上に残り続けます。

では、公開鍵サーバーの管理者に問い合わせてプライマリキーとサブキーを削除してもらうように依頼してはどうでしょうか? しかし、公開鍵サーバーは、他の公開鍵サーバーと連携しています。たとえば、pgp.mit.eduはkeys.gnupg.netと登録された公開鍵を共有しています。無数に存在する公開鍵サーバーの管理者全員に問い合わせて、登録済みの公開鍵を削除してもらうよう依頼することは現実的には不可能です。従って、有効期間を指定していないプライマリキーおよびサブキーの失効証明書を紛失した場合、永久に失効できなくなるのです。

プライマリキーとサブキーの作成直後に失効証明書を作成する理由

たとえば、--gen-keyでプライマリキーとサブキーを作成した後に、--gen-revokeで失効証明書を作成したとします。そして、数日後にプライマリキーの秘密鍵のパスワードを忘れてしまった場合を想定してください。

このとき、作成してある失効証明書を使えばプライマリキーを執行させることができます。しかし、失効証明書の作成を怠っていると、プライマリキーを失効させることはできません。当然ですが、失効証明書を作成する際にはプライマリキーの秘密鍵のパスワードが必要になるからです。したがって、プライマリキーとサブキーの作成直後であれば、確実にパスワードは覚えているわけですから、そのタイミングで失効証明書を作成しておく必要があるのです。

ところで、--gen-rebokeを実行すると、失効証明書を作成する理由が尋ねられます。選択肢は次のとおりでした。

  0 = No reason specified (理由は指定しない)
  1 = Key has been compromised (キーの信頼が失われたから)
  2 = Key is superseded (キーはより良いものに更新されるから)
  3 = Key is no longer used (もうキーは使われなくなるから)

キーの信頼が失われたというのは、秘密鍵が漏洩した場合を想定しています。キーをより良いものに更新するというのは、たとえば鍵の種類をRSA 2048 bitからRSA 4096 bitに更新することを想定しています。このように、上記の選択肢はすべて手元にプライマリキーの秘密鍵が残されていることを前提としている点に注意してください。したがって、やはりプライマリキーとサブキーの作成直後に失効証明書を作成する必要があるのです。

有効期間を過ぎた後のプライマリキーとサブキーの更新について

有効期間を過ぎた後でも、プライマリキーとサブキーの有効期間は更新できます。だからと言って、有効期限を過ぎた後に更新することを繰り返していては、いずれ周囲の人から信頼されなくなります。これは技術的な問題ではなく、その人が信頼できるか否かという社会的な問題ですからプライマリキーとサブキーの更新は余裕を持って行うように心がけるべきです。

プライマリキーとサブキーに設定された有効期間をすぎると何が起こるのか

プライマリキーとサブキーに設定された有効期間をすぎると何が起こるのでしょうか。

以下に、Blakeが作成したプライマリキーとサブキーの有効期限が切れた場合を例にして、何が起こるのかを示します。

メッセージに付加された署名の検証を試みた場合

AliceはBlakeからmessage.txtと、message.txt.sigを受け取りました。しかし、Aliceはメッセージを受け取ったことを忘れていて、気づいた頃にはすでにBlakeが署名に利用したプライマリキーに設定されている有効期間を過ぎていました。

以下に、AliceがBlakeから受け取った署名の検証を試みた場合の例を示します。

# Aliceのマシンにて
$ cat message.txt
Hi, everyone. I'm Blake.
$ gpg message.txt.sig
gpg: assuming signed data in 'message.txt'
gpg: Signature made Tue Sep 20 05:37:07 2016 JST using RSA key ID 85051043 
gpg: Good signature from "Blake <blake@example.com>" [expired]
gpg: Note: This key has expired!
Primary key fingerprint: 1003 2D54 870B BB18 78C4  8F4B CE0E A33C 8505 1043

このように、メッセージに付加された署名は有効期間を過ぎた後でも正しいものであることが検証できます。ただし、その署名を信頼するか否かは各自で判断することになります。プライマリキーの有効期間を延長せずに放置しているような人を信頼できるかというと、微妙なところです。

メッセージに署名の付加を試みた場合

有効期間を過ぎたプライマリキーを使用して、メッセージに署名を付加することはできません。

以下に、Blakeがメッセージに署名の付加を試みた場合の例を示します。

# Blakeのマシンにて
$ echo "I'm not lazy. Ha, ha!" > message.txt
$ gpg -b message.txt
gpg: skipped "blake@example.com": unusable secret key
gpg: signing failed: unusable secret key

このように、有効期間を過ぎたプライマリキーの秘密鍵を使ってメッセージに署名を付加することはできません。

特定の人だけが見ることができるようにメッセージの暗号化を試みた場合

有効期間を過ぎたサブキーを使用して、メッセージを暗号化することはできません。

以下に、Aliceが有効期限の切れたBlakeのサブキーの公開鍵を使用して、Blakeだけが見られるようにmessage.txtを暗号化しようと試みた場合の例を示します。

# Aliceのマシンにて
$ echo "Hi, Blake. Update your sub key." > message.txt
$ gpg -e -r blake@example.com message.txt
gpg: blake@example.com: skipped: Unusable public key
gpg: message.txt: encryption failed: Unusable public key

このように、有効期間を過ぎたサブキーの公開鍵を使用してメッセージを暗号化することはできません。

まとめ

最後に、gpgでプライマリキーとサブキーを作成する際の心得をまとめます。

  1. 有効期限を必ず設定
  2. 失効証明書を必ず作成
  3. プライマリキーの秘密鍵は絶対に漏洩させてはならない

以上です。Enjoy!

参考文献

  1. The GNU Privacy Handbook
  2. Subkeys - Debian Wiki
  3. How to change the expiration date of a GPG key | G-Loaded Journal
  4. openpgp - Lost PGP private key and want to remove it from keyserver.ubuntu.com - Ask Ubuntu
  5. Are GnuPG 1 and GnuPG 2 compatible with each other? - Super User
  6. How To Use GPG to Encrypt and Sign Messages on an Ubuntu 12.04 VPS | DigitalOcean
  7. Creating the perfect GPG keypair - Alex Cabal