GPG で始める暗号・署名ライフ

PGP (Pretty Good Privacy) の実装のひとつである GPG (GNU Privacy Guard) を使用して鍵を生成する方法をゼロから紹介します。

また、ファイルを暗号化・署名してやりとりする方法や、 Git のコミットに署名をつける方法、エンジニアフレンドリーなパスワードマネージャー Pass によるパスワード管理の方法なども紹介します。

メールでパスワードつき zip を送りたくない (送らせたくない) 人、クラウド型のパスワードマネージャーを信用できない人、自分の機密データは自分で守りたい人には多分おすすめの記事です。

PGP ・ GPG とは

PGP (Pretty Good Privacy) は、公開鍵暗号方式で暗号化と署名ができるソフトウェアです。フィル・ジマーマンが開発し、その後 PGP の規格が OpenPGP として標準化されました。現代で PGP とか OpenPGP と言ったら公開鍵暗号方式の規格のひとつだと思えば良いです。

OpenPGP の実装のひとつが GNU の GPG (GNU Privacy Guard) です。 PGP で暗号化や署名を行うなら大体 GPG を使うことになります。本記事では GPG を使用して鍵の生成、鍵を使用して暗号化・署名する方法を解説します。

公開鍵暗号方式とは

そもそも公開鍵暗号方式ってなんだよって人のために簡単に解説します。

昔、暗号と言えば共通鍵暗号方式を指していました。これは、暗号化と復号化に共通の鍵を使う方式です。例えば、パスワードつき zip やパスワードつき Office ドキュメントは、パスワードを共通鍵とした共通鍵暗号と言えるでしょう。

共通鍵暗号方式は処理が早いという利点はあるのですが、共通鍵を他人と安全に共有するのが難しいという欠点があります (鍵配送問題) 。共通鍵は第三者に漏洩してはいけません。メールにて

後で zip ファイルのパスワードを送ります。

なんてものは、メールを盗み見られたらアウトです。 SMTP サーバーを構築したことある人なら分かるはずです。メールのセキュリティーなんてそんなもんですよ。

共通鍵暗号方式の問題を解消したのが公開鍵暗号方式です。公開鍵暗号方式は、「公開鍵」と「秘密鍵」の 2 つを用いた暗号方式です。共通鍵暗号方式に比べ処理が少し遅いですが、安全性は抜群です。

秘密の情報を送信する人は、受信する人の公開鍵を使って情報を暗号化します。暗号化した情報をそのままメールなどで送信します。第三者がこれを傍受しても、鍵の非対称性によって解読ができません。秘密の情報を受信した人は、自身の秘密鍵を使って情報を復号することができます。復号のための鍵を配送する必要がありません。

自分の公開鍵を使って情報を暗号化すれば、自分しか復号できなくなります。パスワードの管理など自身の機密情報の暗号化に使えます。

公開鍵はその名の通り、公開する鍵です。インターネットなどで全世界にばら撒いても何の問題もありません。むしろばら撒いてください。筆者も 公開鍵を公開 しています。みんながあなたの公開鍵を使って情報を暗号化することで、あなたに安全にデータを送ることができるようになります。ただし、公開した公開鍵が信用ならなかったり、改竄される可能性もあるので、普段からメールのフッタに「私の鍵 (の指紋) はこれです」と書いておいたり、 Keybase に SNS アカウントと公開鍵を紐付けておくと信頼性が高まります。詳しくは後述。

秘密鍵はその名の通り、秘密にする鍵です。絶対に漏洩してはいけません。上司、友人、恋人、家族はもちろん、捜査当局であっても秘密鍵を渡してはいけません。

公開鍵と秘密鍵は必ずセットで使ったり使われたりします。このセットを「鍵ペア」と言います。公開鍵と秘密鍵は非対称性があり、公開鍵を秘密鍵として使ったり、秘密鍵を公開鍵として使うことはできません。

また、公開鍵暗号の応用として、デジタル署名を行うことができます。あるデータに対して公開鍵で処理を行うと、データを暗号化することができますが、公開鍵ではなく自身の秘密鍵で処理を行うと、「データが私によって署名されましたよ」ということが証明できるようになります。署名データを公開鍵で検証することで、署名が正しいものであることを証明します。

GPG のインストール

Windows

Gpg4win からインストーラをダウンロードします。ダウンロードしたらすぐ実行せず、インストーラを右クリックしてプロパティを開いて、インストーラについているデジタル署名が問題無いか確認してからインストールします。ちなみに、この署名は X.509 によるもので、 PGP による署名ではありません。

インストーラが何者かに改竄されていた場合、秘密鍵が漏洩したりする可能性があるので、署名の確認を行っておくと安心です。

macOS

$ brew install gnupg pinentry-mac

Linux

大抵は既に入っています。入っていなくても、パッケージマネージャで gnupg と pinentry (pinentry-cursespinentry-tty など環境によって異なります) をインストールすれば GPG が使えるようになるはずです。

インストールの確認

gpg コマンドを叩いて、動作するかどうかを確認します。

$ gpg
gpg: ディレクトリ'$HOME/.gnupg'が作成されました
gpg: keybox'$HOME/.gnupg/pubring.kbx'が作成されました
gpg: *警告*: コマンドが指定されていません。なにを意味しているのか当ててみます ...
gpg: 開始します。メッセージを打ってください ...

ホームディレクトリに .gnupg ディレクトリが作られます。ここに GPG のデータが格納されます。 Control+C で GPG を終了します。

鍵の生成

GPG を使って自分の鍵を生成します。

鍵には「主鍵」と「副鍵」の 2 種類あります。主鍵の 1 つの下に複数の副鍵がぶら下がっているイメージです。普段は副鍵を使用してファイルの暗号化や署名を行います。副鍵の秘密鍵が漏洩したら主鍵を使用して副鍵を失効させるといった使い方をします。

主鍵の生成

まず主鍵から生成します。鍵のセキュリティーに超神経質な人は、 OS クリーンインストール直後でネットワークから完全に切り離された状態のマシンで実行しましょう。

gpg --full-gen-key コマンドでインタラクティブに主鍵を生成します。 --expert オプションをつけるとすべての選択肢が表示されるようになります。

$ gpg --full-gen-key --expert
gpg (GnuPG) x.x.xx; Copyright (C) 2020 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.

ご希望の鍵の種類を選択してください:
   (1) RSA と RSA (デフォルト)
   (2) DSA と Elgamal
   (3) DSA (署名のみ)
   (4) RSA (署名のみ)
   (7) DSA (機能をあなた自身で設定)
   (8) RSA (機能をあなた自身で設定)
   (9) ECC と ECC
  (10) ECC (署名のみ)
  (11) ECC (機能をあなた自身で設定)
  (13) 既存の鍵
  (14) カードに存在する鍵
あなたの選択は?

あなたの選択は? と聞かれるので、数字を入力して選択します。 (1) RSA と RSA (デフォルト) のように 2 つ表示されているものは、主鍵と副鍵を同時に生成する選択肢です。今は主鍵だけを生成するので、これらの選択肢は選ばないようにします。

基本的に RSA か ECC を選択すれば良いと思います。 RSA は巨大な合成数の素因数分解が困難なことを利用したアルゴリズムで、恐らく最も使われているアルゴリズムです。互換性も高いので迷ったら RSA を選びましょう。

最近では ECC もよく使われます。 ECC は楕円曲線の離散対数問題の困難性を利用した新しいアルゴリズムで、鍵のサイズが RSA より小さくパフォーマンスに優れています。

今回は ECC を選択したいと思います。 (11) ECC (機能をあなた自身で設定) を選択するので 11 と入力します。 RSA を選択する場合は 8 を選択します。

あなたの選択は? 11

鍵ECDSA/EdDSAに認められた操作: Sign Certify Authenticate
現在の認められた操作: Sign Certify

   (S) 署名機能を反転する
   (A) 認証機能を反転する
   (Q) 完了

あなたの選択は?

ECC の主鍵には、鍵に対する署名 (Certify) に加えてファイルに対する署名 (Sign) と認証 (Authenticate) の機能を追加することができますが、鍵に対する署名だけで十分なので他の機能は無効にします。他の機能は副鍵にやらせましょう。 現在の認められた操作: Sign Certify となっているので、 Sign を無効にするため s を入力します。 Certify のみになったら q を入力して完了します。

鍵ECDSA/EdDSAに認められた操作: Sign Certify Authenticate
現在の認められた操作: Sign Certify

   (S) 署名機能を反転する
   (A) 認証機能を反転する
   (Q) 完了

あなたの選択は? s

鍵ECDSA/EdDSAに認められた操作: Sign Certify Authenticate
現在の認められた操作: Certify

   (S) 署名機能を反転する
   (A) 認証機能を反転する
   (Q) 完了

あなたの選択は? q

機能を選択した後、 ECC の場合は楕円曲線の種類を選びます。 (1) Curve 25519 を選択します。 RSA の場合は鍵の長さを聞かれます。 1024 - 4096 bits の間で選択可能で、デフォルトでは 3072 bits ですが通常は最長の 4096 bits を入力します。長い方が安全です。

ご希望の楕円曲線を選択してください:
   (1) Curve 25519
   (3) NIST P-256
   (4) NIST P-384
   (5) NIST P-521
   (6) Brainpool P-256
   (7) Brainpool P-384
   (8) Brainpool P-512
   (9) secp256k1
あなたの選択は? 1

アルゴリズムを設定した後、鍵の有効期限を設定します。ここでは無期限を選択しますので 0 を入力します。入力の確認があるので、 y を入力します。

鍵の有効期限を指定してください。
         0 = 鍵は無期限
      <n>  = 鍵は n 日間で期限切れ
      <n>w = 鍵は n 週間で期限切れ
      <n>m = 鍵は n か月間で期限切れ
      <n>y = 鍵は n 年間で期限切れ
鍵の有効期間は? (0) 0
鍵は無期限です
これで正しいですか? (y/N) y

ユーザー ID を設定します。名前とメールアドレスとコメントで構成されるもので、これらの情報は公開することになります。本当は本名や実際のメールアドレスを設定するのが望ましいですが、他人から見て自分だと分かるなら架空の名前でも良いです。メールアドレスは、常にメールを受信できるようなメールアドレスを指定しましょう。

名前は 5 文字以上で、アルファベットで書きます。コメントは空欄で良いです。

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

本名: John Doe
電子メール・アドレス: john@example.com
コメント:
次のユーザIDを選択しました:
    "John Doe <john@example.com>"

名前(N)、コメント(C)、電子メール(E)の変更、またはOK(O)か終了(Q)? o

最後に、鍵にパスフレーズを設定します。鍵に対するマスターパスのようなもので、秘密鍵が漏洩した場合の最後の砦となるものです。パス「ワード」ではなくパス「フレーズ」ですので、大文字小文字記号すべてを含んだ十分長いもの設定することを強くお勧めします。すでに他の Web サービスなどで使用したことがあるものを使い回さないように。パスフレーズは今後ちょこちょこ入力することになりますので、覚えられるものを設定し、忘れないようにしましょう。

たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。
新しい鍵を保護するために、
パスフレーズを入力してください。
パスフレーズ:
繰り返し:

これで、主鍵の公開鍵と秘密鍵の生成は完了です。同時に、主鍵を失効させる失効証明書も生成されます。

gpg: $HOME/.gnupg/trustdb.gpg: 信用データベースができました
gpg: 鍵F6C6DFE63D6F96E3を究極的に信用するよう記録しました
gpg: ディレクトリ'$HOME/.gnupg/openpgp-revocs.d'が作成されました
gpg: 失効証明書を '$HOME/.gnupg/openpgp-revocs.d/AED43BEDC290985B95DEBC22F6C6DFE63D6F96E3.rev' に保管しました。
公開鍵と秘密鍵を作成し、署名しました。

pub   ed25519 yyyy-MM-DD [C]
      AED43BEDC290985B95DEBC22F6C6DFE63D6F96E3
uid                      John Doe <john@example.com>

保管されている公開鍵は以下のコマンドで確認することができます。

$ gpg -k
​$HOME/.gnupg/pubring.kbx
------------------------
pub   ed25519 yyyy-MM-DD [C]
      AED43BEDC290985B95DEBC22F6C6DFE63D6F96E3
uid           [  究極  ] John Doe <john@example.com>

副鍵の生成

主鍵を生成したら、副鍵を生成します。副鍵はいくつでも作ることができます。副鍵はそれぞれ独立しているので、どのような順番で作成しても構いません。

まずは、暗号化用の副鍵を作成します。 gpg --edit-key コマンドでインタラクティブに鍵を編集します。鍵の指定は、 16 進の鍵 ID か指紋、ユーザー ID の一部分を入力すれば GPG は勝手に選んでくれます。今回は john@example.com のようにメールアドレスを全部入れるよう記述します。一意に定まっていれば john のみでも大丈夫です。

$ gpg --edit-key --expert john@example.com
gpg (GnuPG) x.x.xx; Copyright (C) 2020 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  ed25519/F6C6DFE63D6F96E3
     作成: yyyy-MM-DD  有効期限: 無期限       利用法: C
     信用: 究極        有効性: 究極
[  究極  ] (1). John Doe <john@example.com>

gpg>

help と入力すると、コマンドの一覧が出ます。今回は副鍵を追加するので addkey と入力します。

gpg> addkey
ご希望の鍵の種類を選択してください:
   (3) DSA (署名のみ)
   (4) RSA (署名のみ)
   (5) Elgamal (暗号化のみ)
   (6) RSA (暗号化のみ)
   (7) DSA (機能をあなた自身で設定)
   (8) RSA (機能をあなた自身で設定)
  (10) ECC (署名のみ)
  (11) ECC (機能をあなた自身で設定)
  (12) ECC (暗号化のみ)
  (13) 既存の鍵
  (14) カードに存在する鍵
あなたの選択は?

暗号化用の副鍵のアルゴリズムを指定します。今回は (12) ECC (暗号化のみ) を指定します。主鍵とアルゴリズムが異なっていても構いません。楕円曲線は (1) Curve 25519 を指定します。

あなたの選択は? 12
ご希望の楕円曲線を選択してください:
   (1) Curve 25519
   (3) NIST P-256
   (4) NIST P-384
   (5) NIST P-521
   (6) Brainpool P-256
   (7) Brainpool P-384
   (8) Brainpool P-512
   (9) secp256k1
あなたの選択は? 1

有効期限は無期限を設定しました。あとは先程設定したパスフレーズを入れれば暗号化用の副鍵が生成されます。

鍵の有効期限を指定してください。
         0 = 鍵は無期限
      <n>  = 鍵は n 日間で期限切れ
      <n>w = 鍵は n 週間で期限切れ
      <n>m = 鍵は n か月間で期限切れ
      <n>y = 鍵は n 年間で期限切れ
鍵の有効期間は? (0) 0
鍵は無期限です
これで正しいですか? (y/N) y
本当に作成しますか? (y/N) y
OpenPGPの秘密鍵のロックを解除するためにパスフレーズを入力してください:
"John Doe <john@example.com>"
256ビットEDDSA鍵, ID F6C6DFE63D6F96E3,
作成日付 yyyy-MM-DD.

パスフレーズ:
たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。

sec  ed25519/F6C6DFE63D6F96E3
     作成: yyyy-MM-DD  有効期限: 無期限       利用法: C
     信用: 究極        有効性: 究極
ssb  cv25519/16BA3755596CADFC
     作成: yyyy-MM-DD  有効期限: 無期限       利用法: E
[  究極  ] (1). John Doe <john@example.com>

gpg>

暗号化用の副鍵を追加しました。この時点で、主鍵によって副鍵が署名されています。次はファイル署名用の副鍵を生成します。最初に (10) ECC (署名のみ) を選択する以外は全く同じ手順です。

gpg> addkey
ご希望の鍵の種類を選択してください:
   (3) DSA (署名のみ)
   (4) RSA (署名のみ)
   (5) Elgamal (暗号化のみ)
   (6) RSA (暗号化のみ)
   (7) DSA (機能をあなた自身で設定)
   (8) RSA (機能をあなた自身で設定)
  (10) ECC (署名のみ)
  (11) ECC (機能をあなた自身で設定)
  (12) ECC (暗号化のみ)
  (13) 既存の鍵
  (14) カードに存在する鍵
あなたの選択は? 10
ご希望の楕円曲線を選択してください:
   (1) Curve 25519
   (3) NIST P-256
   (4) NIST P-384
   (5) NIST P-521
   (6) Brainpool P-256
   (7) Brainpool P-384
   (8) Brainpool P-512
   (9) secp256k1
あなたの選択は? 1
鍵の有効期限を指定してください。
         0 = 鍵は無期限
      <n>  = 鍵は n 日間で期限切れ
      <n>w = 鍵は n 週間で期限切れ
      <n>m = 鍵は n か月間で期限切れ
      <n>y = 鍵は n 年間で期限切れ
鍵の有効期間は? (0) 0
鍵は無期限です
これで正しいですか? (y/N) y
本当に作成しますか? (y/N) y
OpenPGPの秘密鍵のロックを解除するためにパスフレーズを入力してください:
"John Doe <john@example.com>"
256ビットEDDSA鍵, ID F6C6DFE63D6F96E3,
作成日付 yyyy-MM-DD.

パスフレーズ:
たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。

sec  ed25519/F6C6DFE63D6F96E3
     作成: yyyy-MM-DD  有効期限: 無期限       利用法: C
     信用: 究極        有効性: 究極
ssb  cv25519/16BA3755596CADFC
     作成: yyyy-MM-DD  有効期限: 無期限       利用法: E
ssb  ed25519/2DABDC562EA88B2E
     作成: yyyy-MM-DD  有効期限: 無期限       利用法: S
[  究極  ] (1). John Doe <john@example.com>

gpg>

これで、暗号化用の副鍵とファイル署名用の副鍵を作成できました。しかし、鍵の変更はまだディスクに書き込まれていないため、 save と入力して変更を保存する必要があります。

gpg> save

副鍵が保存され gpg が終了しました。 gpg -k (gpg --list-keys) コマンドで公開鍵を確認してみましょう。

$ gpg -k
​$HOME/.gnupg/pubring.kbx
------------------------
pub   ed25519 yyyy-MM-DD [C]
      AED43BEDC290985B95DEBC22F6C6DFE63D6F96E3
uid           [  究極  ] John Doe <john@example.com>
sub   cv25519 yyyy-MM-DD [E]
sub   ed25519 yyyy-MM-DD [S]

pub は主鍵の公開鍵、 sub は副鍵の公開鍵を表します。 [C] は鍵に対する署名 (Certify) 、 [E] は暗号化 (Encrypt) 、 [S] はファイルに対する署名 (Sign) の機能があることを表します。

認証 (Authenticate) の副鍵もあります。これは GPG の鍵を SSH の鍵として使うことができるようになる鍵です。今回は作りませんでした。

主鍵の秘密鍵の削除

gpg -K (gpg --list-secret-keys) コマンドで秘密鍵を確認することができます。

$ gpg -K
​$HOME/.gnupg/pubring.kbx
------------------------
sec   ed25519 yyyy-MM-DD [C]
      AED43BEDC290985B95DEBC22F6C6DFE63D6F96E3
uid           [  究極  ] John Doe <john@example.com>
ssb   cv25519 yyyy-MM-DD [E]
ssb   ed25519 yyyy-MM-DD [S]

sec は主鍵の秘密鍵、 ssb は副鍵の秘密鍵を表します。

主鍵の秘密鍵があると、主鍵自身の失効や副鍵の作成・失効、有効期限の変更など鍵のあらゆる管理ができます。副鍵の生成に関しては前節で完了しました。主鍵の秘密鍵を常に持っていると、漏洩し悪用された場合にヤバいので、どこか別の場所に保管してマシンからは削除してしまいましょう。

主鍵と副鍵の秘密鍵の保管

まずは主鍵と副鍵の秘密鍵をファイルへエクスポートします。 gpg --export-secret-key を実行します。 -a (--armor) オプションをつけると、 ASCII テキスト形式で出力します。オプションなしだとバイナリ形式となります。

$ gpg --export-secret-key -a john@example.com > secret-key.asc
OpenPGPの秘密鍵をエクスポートするためにパスフレーズを入力してください:
"John Doe <john@example.com>"
256ビットEDDSA鍵, ID F6C6DFE63D6F96E3,
作成日付 yyyy-MM-DD.

パスフレーズ:

secret-key.asc に主鍵と副鍵の秘密鍵がエクスポートされました。これを適当なオフラインストレージに保管するか、紙に印刷します。印刷する場合はファイルの中身を QR コード化しておくと復元に便利です。いざという時は主鍵の秘密鍵が必要になるので、セキュアかつ大切に保管しましょう。

秘密鍵を確実に保管したら、 secret-key.asc は削除します。このファイルには秘密鍵 (機密情報) が入っているので、 rm コマンドではなく shred コマンドで削除します。

$ shred -u secret-key.asc

主鍵の秘密鍵を削除

GPG に保管されている主鍵の秘密鍵を削除します。 gpg --delete-secret-key コマンドで主鍵の秘密鍵を削除します。

「選択した OpenPGP 秘密鍵を本当に永久に削除しますか?」 と聞かれたら削除します。「選択した OpenPGP 副鍵を本当に永久に削除しますか?」 と聞かれたらキャンセルします。すると、主鍵の秘密鍵のみ削除できます (もう少し良いやり方があるかも) 。 pinentry によっては、 GUI でダイアログボックスが出現するかもしれません。

# gpg --delete-secret-key john@example.com
gpg (GnuPG) x.x.xx; Copyright (C) 2020 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  ed25519/F6C6DFE63D6F96E3 yyyy-MM-DD John Doe <john@example.com>

この鍵を鍵リングから削除しますか? (y/N) y
これは秘密鍵です! 本当に削除しますか? (y/N) y
選択したOpenPGP秘密鍵を本当に永久に削除しますか? (y/N)
"John Doe <john@example.com>"
256ビットEDDSA鍵, ID F6C6DFE63D6F96E3,
作成日付 yyyy-MM-DD.
?
  OK
  Cancel
[oc]? o
選択したOpenPGP副鍵を本当に永久に削除しますか? (y/N)
"John Doe <john@example.com>"
256ビットECDH鍵, ID 16BA3755596CADFC,
作成日付 yyyy-MM-DD (主鍵ID F6C6DFE63D6F96E3).
?
  OK
  Cancel
[oc]? c
gpg: 秘密副鍵:の削除に失敗しました: 操作がキャンセルされました
gpg: john@example.com: delete key failed: 操作がキャンセルされました

もう一度、 gpg -K (gpg --list-secret-keys) コマンドで秘密鍵を確認してみましょう。

$ gpg -K
​$HOME/.gnupg/pubring.kbx
------------------------
sec#  ed25519 yyyy-MM-DD [C]
      AED43BEDC290985B95DEBC22F6C6DFE63D6F96E3
uid           [  究極  ] John Doe <john@example.com>
ssb   cv25519 yyyy-MM-DD [E]
ssb   ed25519 yyyy-MM-DD [S]

sec の隣に # がついています。これは秘密鍵が存在しないことを示しています。

主鍵の失効証明書の削除

主鍵の秘密鍵は保管したので、失効証明書を持っている必要はありません。失効証明書は、主鍵の秘密鍵とパスフレーズがあれば後から生成できます。主鍵の秘密鍵を紛失しそうだったり、パスフレーズを忘れそうで心配な人は失効証明書も印刷するなどして保管しておくと良いと思います。

失効証明書が漏洩してイタズラされたら自分の鍵が使い物にならなくなりますので、マシンから削除してしまいましょう。 $HOME/.gnupg/openpgp-revocs.d/ ディレクトリ内に失効証明書が保存されているので、 shred コマンドで削除します。

$ cd ~/.gnupg/openpgp-revocs.d/
$ shred -u AED43BEDC290985B95DEBC22F6C6DFE63D6F96E3.rev

鍵のセットアップは以上で終了です。お疲れ様でした。

ファイルの暗号化

ここからは GPG の実際の使い方について解説します。まずはファイルの暗号化から。

自分だけが復号できる暗号

まずは、暗号化したいデータ data.txt を用意します。テキストでもバイナリでも何でも良いですし、ファイル名も何でも良いです。

$ echo supersecret > data.txt

GPG で暗号化する場合、ファイルを受け取る人の公開鍵を使用して暗号化します。今回は「自分だけが復号できる暗号」なので、ファイルを受け取る人は自分自身です。よって、自分の公開鍵を使って暗号化します。

gpg -e コマンドでファイルを暗号化します。 -e (--encrypt) オプションはファイルの暗号化を表しています。 -r (--recipient) オプションはファイルを受け取る人の指定です。自分自身のユーザー ID を指定しています。

$ gpg -e -r john@example.com data.txt

すると、同じディレクトリに data.txt.gpg が出力されます。バイナリ形式です。 ASCII 形式で出力したいなら、 -a (--armor) オプションをつけます。その場合、 data.txt.asc として出力されます。

$ ls
data.txt  data.txt.gpg

これで暗号化は完了です。元のファイル data.txt は消します。機密データなら shred コマンドで。

$ rm data.txt

暗号化したデータ data.txt.gpg を復号してみましょう。 GPG で復号する場合、ファイルを受け取る人の秘密鍵を使用して復号します。

秘密鍵を持っているなら、 gpg コマンドにファイル名を渡すことで自動的に復号してくれます。パスフレーズの入力を求められることがあるので、自分の鍵のパスフレーズを入力します。

$ gpg data.txt.gpg
gpg: *警告*: コマンドが指定されていません。なにを意味しているのか当ててみます ...
OpenPGPの秘密鍵のロックを解除するためにパスフレーズを入力してください:
"John Doe <john@example.com>"
256ビットECDH鍵, ID 16BA3755596CADFC,
作成日付 yyyy-MM-DD (主鍵ID F6C6DFE63D6F96E3).

パスフレーズ:
gpg: 256-ビットECDH鍵, ID 16BA3755596CADFC, 日付yyyy-MM-DDに暗号化されました
      "John Doe <john@example.com>"

同じディレクトリに data.txt が出力されます。このファイルの中身が復号されたファイルになります。

$ cat data.txt
supersecret

ファイルを暗号化して他人に送る

GPG で暗号化する場合、ファイルを受け取る人の公開鍵を使用して暗号化します。今回はファイルを受け取るのは他人なので、他人の公開鍵を使って暗号化することになります。

まずは、暗号を受け取る人の公開鍵を自分のマシンにインポートする必要があります。今回は、筆者宛に秘密のメッセージを送ることを想定し、 筆者の公開鍵 をインポートしてみようと思います (公開鍵の公開方法は後述) 。以下のコマンドでインポートできます。

$ gpg --fetch-keys https://github.com/livewing.gpg
gpg: 鍵を'https://github.com/livewing.gpg'から要求
gpg: 鍵EFD57D2CC060FC28: 公開鍵"livewing.net <devあlivewing.net>"をインポートしました
gpg: 処理数の合計: 1
gpg:               インポート: 1

これで公開鍵をインポートできました。あとは、 gpg -e コマンドで暗号化するだけです。

$ gpg -e -r livewing.net data.txt
gpg: 449041683480BFBD: この鍵が本当に本人のものである、という兆候が、ありません

sub  cv25519/449041683480BFBD 2021-01-24 livewing.net <devあlivewing.net>
 主鍵フィンガープリント: 4427 7A6E 10C7 C0A1 3483  05F6 EFD5 7D2C C060 FC28
      副鍵フィンガープリント: 5E8C BEBF E3C2 562B 5B38  9F5C 4490 4168 3480 BFBD

この鍵は、このユーザIDをなのる本人のものかどうか確信でき
ません。今から行うことを*本当に*理解していない場合には、
次の質問にはnoと答えてください。

それでもこの鍵を使いますか? (y/N) y

ファイルを暗号化することができました。出力された data.txt.gpg をメールなどで通信相手に送信します。メールで送るなら -a オプションをつけて ASCII 形式にした方が手軽に送れていいかもしれません。

データを受信した人は、受信した人自身の秘密鍵を使って復号します。他人の公開鍵を使って暗号化した場合、暗号化したデータは暗号化した人でも復号することができません。今回の場合、この暗号化されたデータを復号できるのは筆者のみということになります。

ファイルを暗号化する際、 GPG が筆者の公開鍵をめっちゃ怪しんでいます。インポートされた公開鍵が本当に本物かどうかがわからないからです。もし偽物の公開鍵を使って暗号化した場合、中間者攻撃によって第三者に暗号がバレる可能性があります。

鍵の指紋を確認するなどして、インポートした公開鍵が本物であると信用できるなら、信用度を設定することで警告メッセージを非表示にできます。 gpg --edit-key で筆者の公開鍵を指定し、 trust コマンドで信用度を設定します。

$ gpg --edit-key livewing.net
gpg (GnuPG) x.x.xx; Copyright (C) 2020 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.


pub  ed25519/EFD57D2CC060FC28
     作成: 2021-01-24  有効期限: 無期限       利用法: C
     信用: 不明の     有効性: 不明の
sub  ed25519/B767D2D60808F027
     作成: 2021-01-24  有効期限: 無期限       利用法: A
sub  cv25519/449041683480BFBD
     作成: 2021-01-24  有効期限: 無期限       利用法: E
sub  ed25519/0120DBCFCEB11C9C
     作成: 2021-01-24  有効期限: 無期限       利用法: S
[  不明  ] (1). livewing.net <devあlivewing.net>

gpg> trust
pub  ed25519/EFD57D2CC060FC28
     作成: 2021-01-24  有効期限: 無期限       利用法: C
     信用: 不明の     有効性: 不明の
sub  ed25519/B767D2D60808F027
     作成: 2021-01-24  有効期限: 無期限       利用法: A
sub  cv25519/449041683480BFBD
     作成: 2021-01-24  有効期限: 無期限       利用法: E
sub  ed25519/0120DBCFCEB11C9C
     作成: 2021-01-24  有効期限: 無期限       利用法: S
[  不明  ] (1). livewing.net <devあlivewing.net>

他のユーザの鍵を正しく検証するために、このユーザの信用度を決めてください
(パスポートを見せてもらったり、他から得たフィンガープリントを検査したり、などなど)

  1 = 知らない、または何とも言えない
  2 = 信用し ない
  3 = まぁまぁ信用する
  4 = 充分に信用する
  5 = 究極的に信用する
  m = メーン・メニューに戻る

あなたの決定は? 5
本当にこの鍵を究極的に信用しますか? (y/N) y

pub  ed25519/EFD57D2CC060FC28
     作成: 2021-01-24  有効期限: 無期限       利用法: C
     信用: 究極        有効性: 不明の
sub  ed25519/B767D2D60808F027
     作成: 2021-01-24  有効期限: 無期限       利用法: A
sub  cv25519/449041683480BFBD
     作成: 2021-01-24  有効期限: 無期限       利用法: E
sub  ed25519/0120DBCFCEB11C9C
     作成: 2021-01-24  有効期限: 無期限       利用法: S
[  不明  ] (1). livewing.net <devあlivewing.net>
プログラムを再起動するまで、表示された鍵の有効性は正しくないかもしれない、
ということを念頭においてください。

gpg> quit

信用度は以下の 5 段階から選択します。 5 = 究極的に信用する の場合のみ、ファイル暗号化時に警告が出なくなります。色々な手段で公開鍵の信用を必ず確認し、適切な信用度を設定するよう心がけましょう。

  1 = 知らない、または何とも言えない
  2 = 信用し ない
  3 = まぁまぁ信用する
  4 = 充分に信用する
  5 = 究極的に信用する

他人の公開鍵に署名することで信用する (lsign コマンド) という方法もありますが、主鍵の秘密鍵が必要になりますので、今回は trust コマンドによる信用度の設定を紹介しました。

複数の人が復号できる暗号

GPG で暗号化する際、 -r オプションを複数つけることで複数人が復号できるよう暗号化することができます。

$ gpg -e -r john@example.com -r livewing.net data.txt

単一のファイル data.txt.gpg が出力されます。この場合、自分と筆者が復号できるということになります。

ファイルへの署名

ファイルへの署名について解説します。ファイルに署名をつけることで、ファイルの差出人が自分であることと、ファイルが改竄されていないことを証明することができます。暗号化はしません。

署名の付加

GPG でファイルに署名する場合、自分の秘密鍵を使用して署名します。

まずは、署名対象のファイル data.txt を用意します。テキストでもバイナリでも何でも良いですし、ファイル名も何でも良いです。

$ echo myfile > data.txt

gpg -s (gpg --sign) コマンドでファイルに署名します。

$ gpg -s data.txt
OpenPGPの秘密鍵のロックを解除するためにパスフレーズを入力してください:
"John Doe <john@example.com>"
256ビットEDDSA鍵, ID 2DABDC562EA88B2E,
作成日付 yyyy-MM-DD (主鍵ID F6C6DFE63D6F96E3).

パスフレーズ:

data.txt に署名をつけました。 data.txt.gpg が出力されています。このファイルは、元の data.txt の内容と署名がひとつになったバイナリファイルです。 -a オプションを指定すると、 ASCII 形式で出力されます。

-s オプションの代わりに --clear-sign オプションを指定すると、元の data.txt の内容がそのまま記載されるようになります。署名は ASCII 形式になります。

$ gpg --clear-sign data.txt
$ cat data.txt.asc
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

myfile
-----BEGIN PGP SIGNATURE-----

iHUEARYIAB0WIQT7mhuXcDyCvlBUJvYtq9xWLqiLLgUCYLuhdQAKCRAtq9xWLqiL
LlmtAP4iwRAZmnuxFtB5Y+vYP6UFeyvCEm5w1mTUmPcAip/CUAD+NmbNQUnZrIEn
5yVuhCfe6hxUzMA+o94tyBmAcWnv8As=
=LdXT
-----END PGP SIGNATURE-----

-s オプションの代わりに -b (--detach-sign) オプションを指定すると、署名の部分だけ出力することができます。

$ gpg -b data.txt

署名の部分だけ data.txt.sig に出力されます。

いずれかの方法で署名を作成して、ファイルと署名を公開します。

署名の検証

署名をした人の公開鍵と署名データを使用して、ファイルの差出人や内容が改竄されていないことを検証することができます。

署名した人の公開鍵はインポートしておく必要があります。

gpg コマンドに署名のファイル名を渡せば、自動的に検証してくれます。

$ gpg data.txt.sig
gpg: *警告*: コマンドが指定されていません。なにを意味しているのか当ててみます ...
gpg: 署名されたデータが'data.txt'にあると想定します
gpg: yyyy年MM月DD日 HH時mm分ss秒 UTCに施された署名
gpg:                EDDSA鍵FB9A1B97703C82BE505426F62DABDC562EA88B2Eを使用
gpg: "John Doe <john@example.com>"からの正しい署名 [究極]

正しい署名 と表示されているので、ファイルの改竄などが起こっていないことを確認できました。

署名対象のファイルと署名が一緒のファイルになっている (-s--clear-sign オプションで署名されている) 場合、署名の検証と同時にファイルの分離も行います。

Arch Linux などでは、パッケージ管理システムに PGP 署名の検証機能がついています。これにより、パッケージの改竄やすり替えができなくなっています。

署名と暗号化

署名と暗号化は同時に行うことができます。やり方は単純で、 gpg コマンドに -e オプションと -s オプションなどを組み合わせるだけです。

$ gpg -e -s -r livewing.net data.txt

これで、筆者宛に暗号化すると同時に、自分が差出人であることを署名しています。データを受け取って復号と署名の検証を行うときは、いつも通り gpg コマンドに渡すだけで復号と検証を行ってくれます (お互いに公開鍵を交換している必要があります) 。

公開鍵の公開

公開鍵の公開方法を紹介します。筆者宛の暗号化が行えたのは、筆者が公開鍵を公開していたからです。公開鍵を正しく公開することで、あなた宛に暗号化できるようになったり、あなたの署名の検証が行えるようになります。

公開鍵のエクスポート

まずは、自分の公開鍵を ASCII テキスト形式で出力します。 gpg --export コマンドで簡単にできます。 -a オプションを忘れずに。 ユーザー ID を指定しないと、インポートしてある別の公開鍵もすべて一緒に出力されてしまいますので注意。

$ gpg --export -a john@example.com
-----BEGIN PGP PUBLIC KEY BLOCK-----

zQZRLYfw1OLWXjLOONUnEj8ONDqNbTVvHnm/OArtsULIPTDwFZ57ZBTzkV1/STcr
jUsmZQ60T0cinT4tET9yVQkdo2uhDTI4LJ1joTHhL29gCbvDOOZJPNN4SvRRegD7
7pXDzShI3ejv9fos5w1iyhZSNzP7V9DPTjRSPjxVOjVTSDbWPNfPOOLPNjRPUtRP
S4NNPtxD9fos5w1iyhBaztQ+AhKj5448sC5QouRRnIyMMgS9SJXNRxc7rnhDs80d
w/4ONZn5pz22oK/6ABvK9ecKI/u+BeOr4IulF13b5TzkK+0AhQtRLYgPlEVXXjLO
ONTKIDRSNDRUDOAimP5bJvl1VlNS8inhlWY3Z6/v5LR4UYVCzZOsNUVBNjRVO4u4
OOtJPNNtSvRRegD77pXDzShI3ejv9fos5w1iyhZSNzP7DfxPTjjNPtxD9fos5w1i
yhZ36DQ+CukJn8LCdTVKIIM8ESZDbZeGax5G4rV4At2XKe/nuHpN/wBvrKnnPcua
iIoJV7de+Sq0DQ0NFlRptqIPmhX0CYLAhQZRLYgQUuLWXjLOONUnEj8ONDqNn0Y6
NFVCJyPddsxq8jUHLzEVHt7pDMVWxthPYA3VtThV7jDLSttNVOLuOX7HB+3PxWuo
yq68VioT3+L9o5owODWth0ZrNufPNVRWRCoT3+L9o5owqvNRTELVNO0JVDG7zuhK
pQlPiyOHWiLgd9kJYdvYYtHPLYgQUtNXPENgd9kJYdvYYg/VNC0GPQKS3klpTeiO
BJrDeGOq2UMrc7jazSrIaJCC5yL2GjQ/s5kMGQTD0cbyrGdbcfr5/rt1/1q1UnG0
cr40UBJwSDHy0DQ/LY6aJOrWAEQOKsF9rQMZU+65hR9CGFkD73cY0lU7f8DONWxo
MC4JJyUvOWdi41/EkQRm1w+RFhcH+R+vj/AY58RR
=FeRD
-----END PGP PUBLIC KEY BLOCK-----

これをばら撒きます。

指紋の確認

公開鍵が本物であるかどうかを目で見て検証する際、上記のような公開鍵を全文字検査するのは現実的ではありません。そこで、鍵のハッシュ値をとることで、簡単に鍵が本物であるかを検証することができるようになります。鍵のハッシュ値のことを指紋と言います。指紋と言えばほとんどの場合、主鍵の指紋のことを指します。

鍵の指紋は gpg --fingerprint で確認することができます。

$ gpg --fingerprint john@example.com
pub   ed25519 yyyy-MM-DD [C]
      AED4 3BED C290 985B 95DE  BC22 F6C6 DFE6 3D6F 96E3
uid           [  究極  ] John Doe <john@example.com>
sub   cv25519 yyyy-MM-DD [E]
sub   ed25519 yyyy-MM-DD [S]

この鍵の指紋は AED4 3BED C290 985B 95DE BC22 F6C6 DFE6 3D6F 96E3 となります。これも公開鍵と一緒にばら撒きます。

Web サイトで公開

自分の Web サイトを持っているなら、 筆者の Web サイト のように公開するのが良いです。指紋も載せておきましょう。筆者のページは Next.jsOpenPGP.js を使用して自動生成しています。もちろん静的な HTML でも大丈夫です。改竄を防ぐため、 TLS を必ず有効にし、サーバーのセキュリティーにも十分配慮します。

ユーザー ID を公開する時、ユーザー ID に含まれるメールアドレスの扱いに注意しましょう。インターネットではスパムメールを送るためのメールアドレスクローラが動いています。つまりメールアドレスをベタ書きするとスパムメールが飛んでくることになります。ユーザー ID の部分だけ画像で配信するとか、 Flexbox と order CSS プロパティを組み合わせて DOM 上の文字の順番がランダムになるようにするなどの対策が必要です。

いくつかの企業・法人でも、 Web サイトにて PGP 公開鍵を公開しています。ソフトウェアの脆弱性情報の報告などに使用できるようにしています。公開鍵を公開する際、参考にしてみてください。

GitHub で公開

このブログを読んでいるような人ならこの方法が一番お気楽だと思います。アカウントに 2 要素認証を設定し、ちゃんと contribute している実績がある人なら公開鍵の信頼性も十分なものになるでしょう。

公開鍵の登録は簡単で、 Settings → SSH and GPG keys → New GPG key と進み、 -----BEGIN PGP PUBLIC KEY BLOCK----- から始まる公開鍵を貼り付けて Add GPG key を押せば完了です。公開鍵は https://github.com/ユーザー名.gpg を GET すると取得できます。「公開鍵くれ」って言われたらこの URL と指紋を教えれば OK です。

GitHub に登録した公開鍵は、 Git コミットの署名の検証にも活用できます。コミット一覧に緑色の Verified バッジを並べることができるようになります。コミットへの署名は後述。

Keybase で公開

Keybase は、 PC やスマートフォンなどのデバイス、 PGP 公開鍵、 Twitter や GitHub などのソーシャルアカウントを紐づけて公開するサービスです。紐づけることで、公開鍵の信頼性が高まります。また、 Keybase ユーザー同士で簡単に暗号を送りあったり、暗号化されたストレージや Git リポジトリを利用することができるようになります。ちなみに Keybase は 2020 年に Zoom Video Communications に買収されました。

Keybase を インストール することで、コマンドラインツールを使用することができます。 Arch Linux の場合は、以下のコマンドでインストールできます。

# pacman -S keybase

コマンドラインツールを使用して、 Keybase アカウントの作成、デバイスの認証、公開鍵の登録、ソーシャルアカウントの認証を行うことができます。まずはアカウントを作成します。

$ keybase signup
$ keybase passphrase set

アカウントはブラウザでも作成できます。ブラウザでアカウントを作成したら keybase login でログインします。

アカウントを作成しログインしたら、公開鍵をアップロードします。

$ keybase pgp select

アップロードされるのは公開鍵のみですが、本人確認のため鍵のパスフレーズの入力が要求されます。

あとは、ソーシャルアカウントなどを認証します。基本的に、ブラウザで設定方法を確認し、コマンドラインツールで設定を行います。

Twitter では公開ツイートの投稿、 GitHub では Gist の投稿が要求されます。これらは定期的に確認されるため、ツイートして認証後にツイ消ししたり鍵を掛けるなどすると、認証が無効になります。

$ keybase prove twitter xxxxxxxx
$ keybase prove github xxxxxxxx

このほか、 DNS の TXT レコードや HTTP サーバのファイル配信によってドメインを認証することもできます。

鍵サーバで公開

昔から、 SKS (Synchronizing Key Server) に公開鍵を公開するのが事実上の標準になっていました。複数の SKS サーバ同士で公開鍵を同期しています。鍵のインポートや更新が簡単になったり、鍵への署名の際に便利であるためよく使われてきました。しかし、鍵の所有者であっても公開鍵をサーバから削除できなかったり、ユーザー ID の部分一致検索が可能でスパムメールの温床となる可能性があったり、 証明書の汚染攻撃を受ける などしてかなりアレな状態になっているので、 SKS への公開はしなくても良いと思います。

最近は新しい鍵サーバ keys.openpgp.org が立ち上がりました。従来の SKS ネットワークとは別の鍵サーバになっています。 Rust で実装されており (すばらしい) 、メール認証によって公開鍵の管理が行えるようになっています。鍵の検索はメールアドレス・鍵 ID ・指紋いずれかの完全一致のみ可能になっており、メールアドレスが部分一致で引っかかることがありません。このサーバは、 Mozilla Thunderbird の拡張である Enigmail のデフォルトの鍵サーバにもなっています。

keys.openpgp.org に公開鍵を登録するには、以下のコマンドを実行し、メールアドレスの検証を行います。

$ gpg --export john@example.com | curl -T - https://keys.openpgp.org/

指紋をメールのフッタに載せる

普段から、メールのフッタに自分の鍵の指紋を載せておくと良いでしょう。

--
John Doe

Email: john@example.com
Web: https://example.com/john
Address: 1-1 Chiyoda, Chiyoda-ku 100-0001 Tokyo
PGP Fingerprint: AED4 3BED C290 985B 95DE  BC22 F6C6 DFE6 3D6F 96E3

複数のコンピュータで同じ鍵を使う

GPG では自分の公開鍵と秘密鍵をエクスポートして、別のコンピュータでインポートして使うことが可能です。複数台のコンピュータを所持している場合、ファイルの復号や署名の作成に便利です。ただし、同じ鍵を複数台のコンピュータで使い回しているので、秘密鍵の漏洩リスクが増えることに注意してください。

鍵のエクスポート

すでに紹介していますが、鍵のエクスポート方法をおさらいしておきます。まずは公開鍵のエクスポートから。

$ gpg --export -a john@example.com

これで標準出力に公開鍵が ASCII テキスト形式で出力されます。必要に応じてリダイレクトを使用してファイルに保存します。

$ gpg --export -a john@example.com > public-key.asc

次は秘密鍵のエクスポート。パスフレーズの入力が要求されます。

$ gpg --export-secret-key -a john@example.com

これで標準出力に秘密鍵が ASCII テキスト形式で出力されます。必要に応じてリダイレクトを使用してファイルに保存します。

$ gpg --export-secret-key -a john@example.com > secret-key.asc

保存した鍵は、他のコンピュータにコピーします。秘密鍵については絶対に他人に漏洩しない方法でコピーしましょう。 USB ストレージを使用するのが良いと思います。間違ってもネットワークを通して秘密鍵を送信してはいけません。

鍵のコピーが終わったら、エクスポートした秘密鍵は shred コマンドでしっかり削除しましょう。

$ shred -u secret-key.asc

鍵のインポート

鍵のインポートは --import オプションで簡単に行うことができます。秘密鍵のインポート時にはパスフレーズの入力が要求されます。

$ gpg --import public-key.asc
$ gpg --import secret-key.asc

鍵のインポートが終わったら、秘密鍵が記載されたファイルを shred コマンドでしっかり削除しましょう。

$ shred -u secret-key.asc

自分で作成した鍵は絶対に信用できるので、信用度を設定します。

$ gpg --edit-key john@example.com
gpg> trust

  1 = 知らない、または何とも言えない
  2 = 信用し ない
  3 = まぁまぁ信用する
  4 = 充分に信用する
  5 = 究極的に信用する
  m = メーン・メニューに戻る

あなたの決定は? 5
本当にこの鍵を究極的に信用しますか? (y/N) y
gpg> quit

これで、複数台のコンピュータで鍵を利用することができるようになりました。秘密鍵の漏洩のリスクに十分ご注意ください。

パスフレーズの変更

パスフレーズは後から変更することが可能です。同じ秘密鍵でも、コンピュータ毎に別々のパスフレーズを設定することができます。 --passwd オプションでパスフレーズの変更が可能です。

$ gpg --passwd john@example.com

Git コミットへの署名

コミットに署名をするには、 git commit コマンドに -S (大文字) オプションを追加します。署名用の鍵は、 Git に設定したユーザー名やメールアドレスから自動的に選択されます。

$ git commit -S

すべてのコミットにデフォルトで署名するには、設定を変更します。

$ git config --global commit.gpgsign true

これで、 -S オプションを指定しなくても署名できます。いつも通りコミットするだけです。

$ git commit

コミットの署名を検証するには、 git log--show-signature オプションを追加します。インポートしてある公開鍵と署名を自動的に検証します。

$ git log --show-signature
commit xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
gpg: EEE  M/DD HH:mm:ss yyyy JSTに施された署名
gpg:                EDDSA鍵FB9A1B97703C82BE505426F62DABDC562EA88B2Eを使用
gpg:                発行者"john@example.com"
gpg: "John Doe <john@example.com>"からの正しい署名 [究極]
Author: John Doe <john@example.com>
Date:   EEE MMM dd HH:mm:ss yyyy +0900

    First commit

GitHub で GPG 公開鍵を設定している場合、署名が正しいことが検証された場合は GitHub 上でコミットに Verified バッジがつくようになります。

パスワード管理

Pass という名前 (ググラビリティ低め) のパスワードマネージャがあります。パスワードの暗号化を GPG 、パスワードの同期を Git で行うシェルスクリプトです。 PC ではもちろん、 Android や iOS 端末でも利用することができます。パスワードを復号できるのは秘密鍵を持っている自分だけです。

インターネットサービスで使用するパスワードを保存するのはもちろん、パスワードの生成や、プラグインの追加によって TOTP (Time-Based One-Time Password) の認証コードの生成を行うことができます (多要素認証としてどうなのって感じはしますが)

インストール

ほとんどのパッケージマネージャーで pass をインストールすれば使用できるようになります。

pass --help でコマンドのヘルプを見ることができます。

パスワードストアの初期化

以下のコマンドで、パスワードを格納するディレクトリを作成します。

$ pass init john@example.com

john@example.com の部分に鍵を識別するための文字列を指定します。ユーザー ID のメールアドレスでも良いですし、鍵 ID や鍵の指紋でも良いです。

これで $HOME/.password-store/ ディレクトリが作成され、 $HOME/.password-store/.gpg-id に鍵の識別子が書き込まれます。

次に、パスワードストアの Git リポジトリを初期化します。 pass git コマンドで $HOME/.password-store/ ディレクトリに対する Git 操作を行うことができます。

$ pass git init

これで Git リポジトリが初期化され、現在のパスワードストアの状態が自動的にコミットされます。また、今後のパスワードストアへの操作が自動的にコミットされます。コミットを整理したいなら pass git rebase -i などで操作しましょう。

パスワードストアの構造

$HOME/.password-store/ の中に暗号化されたパスワードが保存されるわけですが、そのディレクトリ構造はユーザーが自由に構成できます。

基本的に、 Web サービスのドメイン名のディレクトリを作成し、その中にユーザー名やメールアドレスをファイル名としたパスワードファイルを作成することになります。以下のように構成するのがよくあるパターンでしょうか。

$ pass
Password Store  ($HOME/.password-store/)
├── github.com
│   └── johnexamplecom
├── soundcloud.com
│   └── john@example.com
:

既存のパスワードの追加

既存のパスワードをパスワードストアに追加してみましょう。 pass insert コマンドでパスワードを追加できます。今回は GitHub アカウント johnexamplecom のパスワードを追加しています (github.com/johnexamplecom) 。

$ pass insert github.com/johnexamplecom
mkdir: ディレクトリ '$HOME/.password-store/github.com' を作成しました
Enter password for github.com/johnexamplecom:
Retype password for github.com/johnexamplecom:

これで、 $HOME/.password-store/github.com/johnexamplecom.gpg に暗号化されたパスワードが保存されました。 pass もしくは pass ls コマンドでパスワード一覧が tree で表示されます。

$ pass
Password Store
└── github.com
    └── johnexamplecom

新しいパスワードの生成

アカウント登録する際、パスワードを自動生成することができます。 pass generate コマンドでパスワードを生成し、パスワードストアに追加できます。今回は SoundCloud アカウント john@example.com のパスワードを生成し追加しています (soundcloud.com/john@example.com) 。

$ pass generate soundcloud.com/john@example.com
mkdir: ディレクトリ '$HOME/.password-store/soundcloud.com' を作成しました
The generated password for soundcloud.com/john@example.com is:
2|1J3Gx.*#{$[~+aQ$qk~)[R.

デフォルトでは、大文字小文字アルファベット・数字・記号すべてを含む 25 文字のパスワードを生成します。コマンドラインオプションで、パスワードの長さや記号の有無などを設定できます。

保存したパスワードの取得

pass コマンドにパスワード名を渡すと、パスワードを標準出力へ出力します。 GPG 鍵のパスフレーズの入力を要求されます。

$ pass soundcloud.com/john@example.com
OpenPGPの秘密鍵のロックを解除するためにパスフレーズを入力してください:
"John Doe <john@example.com>"
256ビットECDH鍵, ID 16BA3755596CADFC,
作成日付 yyyy-MM-DD (主鍵ID F6C6DFE63D6F96E3).

パスフレーズ:
2|1J3Gx.*#{$[~+aQ$qk~)[R.

パスワードを OS のクリップボードにコピーするには、 -c オプションを使用します。コピーされたパスワードは 45 秒後にクリップボードから削除されます。

$ pass -c soundcloud.com/john@example.com

保存したパスワードの編集

pass edit でパスワードをテキストエディタで編集できます。 GPG で一旦復号したファイルをテキストエディタで編集し、再度暗号化します。

$ pass edit soundcloud.com/john@example.com

パスワードはシンプルに 1 行目に記載されているだけなので、自由に編集してください。

2 行目以降は自由記述欄です。基本的に 1 行 1 項目です。アカウント登録の際に入力させられる、 UX がアレな 秘密の質問の答えをメモるといった使い方ができます。

SuperSecretPassword
Secret Question 1: What is your favorite food? Sushi
Recovery Codes: XXX XXX XXX XXX

また、パスワードファイル自体の操作は pass rm pass mv pass cp で削除・移動・コピーを行うことができます。 pass コマンド経由の操作は自動的にコミットされるので、元に戻すことも簡単です。

パスワードストアの同期

pass git remote add でリモートリポジトリを設定して pass git push すれば OK です。 GitHub などにプライベートリポジトリを作成しておくと良いと思います。

$ pass git remote add origin git@github.com:johnexamplecom/.password-store.git
$ pass git push -u origin main

別の PC でパスワードストアを使用開始する場合は git clone すれば OK です。

$ git clone git@github.com:johnexamplecom/.password-store.git $HOME/.password-store

パスワードストアを更新する場合はいつも通りの Git コマンド操作を行えば良いです。 pass git fetch して pass git merge しましょう。 Git が使える人なら特に迷うことは無いはずです。

TOTP の利用

Pass 用の拡張 pass-otp を別途インストールすると、時刻同期型ワンタイムパスワード (TOTP: Time-Based One-Time Password) の認証コードを生成できるようになります。

pass-otp をインストールしたら、 pass otp コマンドが使用できるようになります。

Web アカウントにワンタイムパスワードを設定する際、 QR コードが表示されると思います。この QR コードの内容は otpauth://totp/ で始まる URI になっています。この URI をそのままパスワードストアに保存することになります。

スマートフォンで QR コードを読み取るか、 zbar を使用して QR コードの画像をデコードして URI を取得します。

URI を取得できたら、 pass otp append で既存のパスワードに TOTP トークンを追加します。パスワードを新規で作成する場合は pass otp insert コマンドで行います。

$ pass otp append github.com/john
Enter otpauth:// URI for github.com/john:
Retype otpauth:// URI for github.com/john:

すると、パスワードファイルが更新されます。 pass コマンドで中身を見てみましょう。

$ pass github.com/john
SuperSecretPassword
otpauth://totp/totp-secret?secret=XXXXXXXXXXXXXXXX&issuer=totp-secret

URI がそのまま追記されただけです。

認証コードを取得するには、 pass otp コマンドを実行します。 TOTP の URI と現在時刻から認証コードが生成されます。

$ pass otp github.com/john
123456

pass otp -c でクリップボードにコピーできます。

$ pass otp -c github.com/john

パスワードと TOTP の認証コード生成元の URI が共存することになるので、もしもの時のセキュリティーが気になる人は普通に Google Authenticator とかを使う方が良いかもしれません。というか多要素認証の意味としては別々のデバイスである方が良いです。

スマートフォンでの利用

Android 端末では Password Store が、 iOS 端末では Pass for iOS が利用できます。どちらもオープンソースです。他のアプリケーションや Web サイトでのパスワード自動入力に対応しています。 TOTP にも対応しています。アプリケーション内でパスワードストアの Git リモートリポジトリと PGP 鍵を設定すれば、パスワードを利用・編集できます。

こんなときは

副鍵の秘密鍵が漏洩した

主鍵の秘密鍵とパスフレーズさえ漏洩していなければなんとかなります。

主鍵の秘密鍵を使用して、既存の副鍵の失効を行い、新しく副鍵を生成します。失効した副鍵を削除する必要はありません。パスフレーズの変更も行っておきます。

鍵を変更したら、必ず新しい公開鍵を公開します。新しい公開鍵の公開で、既存の副鍵の失効と新しい副鍵の追加を表明することができます。主鍵の指紋は変わらないので、鍵の信用が傷つくことはありません。主鍵の秘密鍵を使い終わったら、オフラインで保管しシステムからは削除しておきましょう。

パスワードストアなど自分用に暗号化しているファイルを持っている場合は、鍵のパスフレーズが解析されてしまう前に、新しい暗号化用の副鍵で暗号化し直しておきましょう。 Git で管理している場合は古いパスワードがコミットされているので、これを抹消して git push --force します。

主鍵の秘密鍵が漏洩した

主鍵の秘密鍵が漏洩した場合は主鍵の失効を行います。副鍵も使えなくなります。主鍵の漏洩はそれくらいヤバいことです。また新しく主鍵から作り直して 1 からスタートすることになります。当然、鍵の信用もリセットされることになります。

主鍵の失効処理をした場合も、公開鍵を公開する必要があります。「もうこの鍵は一切合切使えないよ」と表明し、第三者による鍵の悪用を防止しなければなりません。

パスフレーズを忘れた

OS のキーチェーンにパスフレーズが保管されているかもしれません。 macOS ならキーチェーンアクセスで探してみましょう。

パスフレーズを本当に忘れる即ち秘密鍵が使用できなくなるということなので、予め生成された主鍵の失効証明書で主鍵を失効させ、公開鍵を公開します。暗号化していたファイルは復号できないため、すべて失われます。

当局に「秘密鍵を渡せ」と言われた

捜査当局に「この暗号を復号するからお前の秘密鍵を渡せ」と言われることがあるかもしれません。そのような場合でも絶対に秘密鍵を渡してはいけません。秘密鍵とパスフレーズを渡すと捜査に関係のない暗号まで身ぐるみ剥がされますよ。特定のファイルだけ相手に復号させる方法があります。

まず、捜査対象の暗号化されたファイルを一旦自分で復号します。この時、 --show-session-key オプションを指定します。

$ gpg --show-session-key data.gpg
OpenPGPの秘密鍵のロックを解除するためにパスフレーズを入力してください:
"John Doe <john@example.com>"
256ビットECDH鍵, ID 16BA3755596CADFC,
作成日付 yyyy-MM-DD (主鍵ID F6C6DFE63D6F96E3).

パスフレーズ:
gpg: 256-ビットECDH鍵, ID 16BA3755596CADFC, 日付yyyy-MM-DDに暗号化されました
      "John Doe <john@example.com>"
gpg: session key: '9:FD7B39B65473AA62230B1EBBE37E7F72516A441325DAFED3E3AA3F5A9CC45D24'

復号されると同時に session key: '9:FD7B...5D24' と表示されたと思います。これはセッション鍵というもので、これを使えば秘密鍵やパスフレーズなしで復号できます。セッション鍵はファイル毎に固有なので、特定のファイルだけを相手に復号させることができるようになります。

当局には秘密鍵の代わりにこのセッション鍵 9:FD7B...5D24 を渡しましょう。セッション鍵も機密情報なのでセキュアな方法でやりとりする必要があります。相手は --override-session-key オプションで復号できます。秘密鍵やパスフレーズは必要ありません。

$ gpg --override-session-key '9:FD7B39B65473AA62230B1EBBE37E7F72516A441325DAFED3E3AA3F5A9CC45D24' data.gpg
gpg: *警告*: コマンドが指定されていません。なにを意味しているのか当ててみます ...
gpg: ECDH鍵, ID 16BA3755596CADFCで暗号化されました

そもそもファイルの復号は、秘密鍵を使用してセッション鍵を取り出し、セッション鍵を使用してファイルを復号するといった手順で行います。中間のセッション鍵を取り出して共有することで、誰でもそのファイルを復号できるようになります。

おわり

GPG の使い方と応用例を紹介しました。鍵の扱いについての解説はこれでも大分省略しているので、各自でドキュメントなどを読むことを強くお勧めします。皆様の QOL が上がれば幸いです。