deslarnetのtech blog

慌てず、急いで、正確にな

PGP鍵の作成とYubiKeyでの運用

電子メール技術の問題点と現状

電子メールはネットワークでの通信が信頼されていた頃からある規格で、それ自体に盗聴やなりすましを防ぐ手段は含まれていません。このため、最近のソーシャルネットワークなどのサービスを利用する場合に比べて、さらに暗号化やデジタル署名が重要な場合があります。
https://mitome.in/email/

電子メールは、封筒に入った手紙と違って、いわば裸のはがきの状態で様々なサーバを経由して届けられる。さすがにそれでは困るので、通信経路を暗号化して盗聴できなくするのが一般的である。ほとんどのメールプロバイダはTLSをサポートしているためメッセージは暗号化されているが、エンドツーエンドで暗号化されていないため、プロバイダであるGmail、Outlook.comなどはこれらのメッセージを読むことが可能である。また、なりすましを防ぐことができない。例えばProton Mailユーザ同士ならば、PGPを使用して、特に意識することなくエンドツーエンドで暗号化されたメールを送受信でき、なりすましを防ぐことも可能である。エンドツーエンドの暗号化を可能とする技術にS/MIMEとPGPがあるが、残念ながらいずれもほとんど普及していない。大方のGmailやOutlook.comなどの利用者は、こうした大企業にメールの中身を覗き見られ、第三者に情報が渡される可能性が否定できない。

PGP, OpenPGP, and GnuPG (GPG)

OpenPGPは、公開鍵暗号方式によるデータの認証や暗号化のための非独占的なフォーマットであり、オリジナルのプロプライエタリ製品であるPGP (Pretty Good Privacy) ソフトウェアをベースにしている。OpenPGPのフォーマットと使用方法は、多くのIETF RFCとドラフトで規定されているため、これらの標準はどの企業でも、誰にライセンス料を支払うことなく実装することができる。GNU Privacy Guard (GnuPG, GPG) は、RFC4880で定義されたOpenPGP標準の完全でフリーな実装である。

Yubikeyの利点

公開鍵暗号方式は、巨大な数の素因数分解の困難性や、楕円曲線上の離散対数問題の困難性に基づく暗号方式である。「公開鍵」と「秘密鍵」という鍵ペアを利用する。ざっくり言うと、暗号化と復号に同じ鍵を用いる共通鍵と異なり「公開鍵で暗号化すると、ペアの秘密鍵でしか復号できない」という特徴がある。公開鍵は文字通り公開することができるが、秘密鍵はインターネット上でのあなたの唯一の存在証明であり、決して漏洩してはならない。YubiKeyはOpenPGPに対応しており、秘密鍵を書き込むことができる。一度書き込むと二度と秘密鍵を読み出すことはできなくなるため、他のデバイスに秘密鍵を保存するよりも安全に秘密鍵を持ち運ぶことができる。秘密鍵はYubiKey内で生成する方法もあるが、前述の通り二度と取り出せなくなるため、信頼できるPCで作成して書き込む方法が推奨されている。

GnuPGの導入

https://www.gnupg.org/index.html
WindowsならGpg4win, MacならGnuPGとpinentry-macをインストールする。Mailvelope等を使用する場合 "browser integration" にチェックを入れておくとよい。

作成する鍵の仕様

役割 種類
主鍵 Sign, Certify ECC NIST P-521
副鍵1 Encryption ECC NIST P-521
副鍵2 Sign, Authenticate ECC NIST P-521

鍵の種類は安全性に大きく関わるため、適切に選択する必要がある。CRYPTRECの暗号運用ガイドラインなどが参考になる。ここでは楕円曲線暗号かつNISTで鍵長の長いものを選択した。
主鍵は副鍵の生成・失効以外では使用しない。バックアップを取ったらPCから抹消して、エアギャップ保管が望ましい。

鍵の生成

主鍵の生成

$ gpg --expert --full-gen-key
gpg (GnuPG) 2.4.0; Copyright (C) 2021 g10 Code GmbH
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 (署名と暗号化) *デフォルト
  (10) ECC (署名のみ)
  (11) ECC (機能をあなた自身で設定)
  (13) 既存の鍵
  (14) カードに存在する鍵
あなたの選択は? 11

このECC鍵にありうる操作: Sign Certify Authenticate
現在の認められた操作: Sign Certify

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

あなたの選択は? Q
ご希望の楕円曲線を選択してください:
   (1) Curve 25519 *デフォルト
   (2) Curve 448
   (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
あなたの選択は? 5 
鍵の有効期限を指定してください。
         0 = 鍵は無期限
      <n>  = 鍵は n 日間で期限切れ
      <n>w = 鍵は n 週間で期限切れ
      <n>m = 鍵は n か月間で期限切れ
      <n>y = 鍵は n 年間で期限切れ
鍵の有効期間は? (0)0
鍵は無期限です
これで正しいですか? (y/N) y

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

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

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

# 鍵のパスフレーズを入力する

gpg: 鍵E9ACC474DF792868を究極的に信用するよう記録しました # 鍵ID(フィンガープリントの末尾8バイト)
gpg: ディレクトリ'/Users/taro/.gnupg/openpgp-revocs.d'が作成されました
gpg: 失効証明書を '/Users/taro/.gnupg/openpgp-revocs.d/E69AA264E45477C6E7784A2CE9ACC474DF792868.rev' に保管しました。
公開鍵と秘密鍵を作成し、署名しました。

pub   nistp521 2023-02-27 [SC]
      E69AA264E45477C6E7784A2CE9ACC474DF792868 # フィンガープリント
uid                      Taro Crypt <ctaro@example.com>

副鍵1, 副鍵2の生成

$ gpg --expert --edit-key E9ACC474DF792868 # 先ほどの鍵ID
gpg (GnuPG) 2.4.0; Copyright (C) 2021 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
Secret key is available.

sec  nistp521/E9ACC474DF792868
     created: 2023-02-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
[ultimate] (1). Taro Crypt <ctaro@example.com>

gpg> addkey
Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
  (14) Existing key from card
Your selection? 12
Please select which elliptic curve you want:
   (1) Curve 25519 *default*
   (2) Curve 448
   (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
Your selection? 5
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) 0
Key does not expire at all
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.

sec  nistp521/E9ACC474DF792868
     created: 2023-02-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  nistp521/97A48F3A2D3030F0
     created: 2023-02-27  expires: never       usage: E
[ultimate] (1). Taro Crypt <ctaro@example.com>

gpg> addkey
Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (12) ECC (encrypt only)
  (13) Existing key
  (14) Existing key from card
Your selection? 11

Possible actions for this ECC key: Sign Authenticate
Current allowed actions: Sign

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? A

Possible actions for this ECC key: Sign Authenticate
Current allowed actions: Sign Authenticate

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? Q
Please select which elliptic curve you want:
   (1) Curve 25519 *default*
   (2) Curve 448
   (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
Your selection? 5
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) 0
Key does not expire at all
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.

sec  nistp521/E9ACC474DF792868
     created: 2023-02-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  nistp521/97A48F3A2D3030F0
     created: 2023-02-27  expires: never       usage: E
ssb  nistp521/D1B0D4E117E6374D
     created: 2023-02-27  expires: never       usage: SA
[ultimate] (1). Taro Crypt <ctaro@example.com>

gpg> save

鍵のエクスポート

主鍵と副鍵の秘密鍵

$ gpg -a -o mastersub.key --export-secret-keys E9ACC474DF792868

副鍵の秘密鍵

$ gpg -a -o sub.key --export-secret-subkeys E9ACC474DF792868

公開鍵

$ gpg -a -o public.asc --export E9ACC474DF792868

失効証明書の作成

$ gpg -o revoke.asc --gen-revoke E9ACC474DF792868

エクスポートしたら、必ず安全な場所に保存すること。

全秘密鍵の削除と副鍵秘密鍵のインポート

全ての秘密鍵を削除

$ gpg --delete-secret-keys E9ACC474DF792868
gpg (GnuPG) 2.4.0; Copyright (C) 2021 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


sec  nistp521/E9ACC474DF792868 2023-02-27 Taro Crypt <ctaro@example.com>

この鍵を鍵リングから削除しますか? (y/N) y
これは秘密鍵です! 本当に削除しますか? (y/N) y

副鍵のみインポート

$ gpg --import sub.key
gpg: key E9ACC474DF792868: "Taro Crypt <ctaro@example.com>" not changed
gpg: To migrate 'secring.gpg', with each smartcard, run: gpg --card-status
gpg: key E9ACC474DF792868: secret key imported
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

Yubikeyの設定

KDFの有効化

$ gpg --card-edit

Reader ...........: Yubico YubiKey OTP FIDO CCID
Application ID ...: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: XXXXXXX
Name of cardholder: [未設定]
Language prefs ...: [未設定]
Salutation .......:
URL of public key : [未設定]
Login data .......: [未設定]
Signature PIN ....: 強制なし
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

gpg/card> admin
管理者コマンドが許可されています

gpg/card> kdf-setup
gpg/card> list

Reader ...........: Yubico YubiKey OTP FIDO CCID
Application ID ...: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: XXXXXXX
Name of cardholder: [未設定]
Language prefs ...: [未設定]
Salutation .......:
URL of public key : [未設定]
Login data .......: [未設定]
Signature PIN ....: 強制なし
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: on
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

PIN(初期値123456), Admin PIN(初期値12345678)の変更

gpg/card> passwd
gpg: OpenPGPカードno. XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXを検出

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

あなたの選択は? 1

副鍵のYubiKeyへの転送

$ gpg --edit-key $KEYID
gpg (GnuPG) 2.4.0; Copyright (C) 2021 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret subkeys are available.

pub  nistp521/E9ACC474DF792868
     created: 2023-02-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  nistp521/97A48F3A2D3030F0
     created: 2023-02-27  expires: never       usage: E
ssb  nistp521/D1B0D4E117E6374D
     created: 2023-02-27  expires: never       usage: SA
[ultimate] (1). Taro Crypt <ctaro@example.com>

gpg> key 1 # まず暗号化鍵を選択

pub  nistp521/E9ACC474DF792868
     created: 2023-02-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb* nistp521/97A48F3A2D3030F0
     created: 2023-02-27  expires: never       usage: E
ssb  nistp521/D1B0D4E117E6374D
     created: 2023-02-27  expires: never       usage: SA
[ultimate] (1). Taro Crypt <ctaro@example.com>

gpg> keytocard
Please select where to store the key:
   (2) Encryption key
Your selection? 2

同様に他の鍵も転送する。転送が終わったら、saveで抜けると副鍵がPCから削除される。

MailvelopeでのYubiKey PGP鍵の使用

Mailvelopeはブラウザの拡張機能で、GmailやOutlook.comなどでOpenPGPを使って暗号化されたメールを送受信できるようになる。PCにインストールされたGnuPGと連携できる。連携方法はこちら

まとめ

PGP鍵を作成し、YubiKeyに書き込んで使用できるようになった。
Mailvelopeを使用したメールの暗号化、署名ができるようになった。