Carpe Diem

備忘録

GPGで主鍵と副鍵を作成する

背景

Yubikeyを新しくしたのでGPGの運用もYubikeyに寄せようと思ったのがきっかけです。

環境

  • GPG 2.2.32

前提知識

主鍵と副鍵

GPGには主鍵と副鍵の関係があります。またそれぞれ秘密鍵と公開鍵のペアになっています。

f:id:quoll00:20220216135426p:plain:w400

これは鍵が漏洩した際にローテーションしやすくするための仕組みです。
主鍵の秘密鍵は副鍵を生成したら基本的にPCなどのデバイスからは削除し、必要な時以外は紙やUSBなどでインターネットから隔離して管理しておくのが安全です。

鍵の種類

鍵には以下の4つの役割があります。

  • Certify(証明)
  • Sign(署名)
  • Authenticate(認証)
  • Encrypt(暗号化)

主鍵は自動的にCertifyが付きますが、それ以外は組み合わせは自由です。

Certify以外を全て副鍵で管理したケース

よく見る設計はこのパターンです。

f:id:quoll00:20220216135345p:plain:w400

今回はこちらのパターンで作成します。

Signを主鍵にも持たせたケース

gpgコマンドのデフォルト(?)だとこのケースです。
署名は漏洩した際になりすましが可能になってしまうため、秘密鍵=自分というくらい重要です。
なので主鍵と一緒に管理する人もいます。

f:id:quoll00:20220216135607p:plain:w160

同じ機能の鍵を複数持たせたケース

あまり見ませんが一応同じ機能を複数持たせることも可能です。
ただしgpgコマンドで設定する際はアルゴリズム自体は別にする必要がありました。

f:id:quoll00:20220216135654p:plain:w400

それぞれ副鍵を異なるSmartCardに持たせるという用途で使っている人はいました。

セキュリティ強度

セキュリティ強度については以前説明したことがあるので参考にしてください。

christina04.hatenablog.com

YubikeyはECCの場合以下をサポートしてます。secpNISTの曲線です。

  • secp256r1
  • secp256k1
  • secp384r1
  • secp521r1
  • brainpoolP256r1
  • brainpoolP384r1
  • brainpoolP512r1
  • curve25519
    • x25519 (decipher only)
    • ed25519 (sign / auth only)

ref: https://support.yubico.com/hc/en-us/articles/360016649139-YubiKey-5-2-3-Enhancements-to-OpenPGP-3-4-Support

作成

以下を参考に作っていきます。

github.com

ただこちらは秘密鍵が漏洩しないようガチガチの手順になっていますが、今回の手順は簡単のためその辺は省いています。

主鍵の作成

まずはCertifyの主鍵を作成します。

生成コマンド

gpg --expert --full-gen-keyで作成します。

$ gpg --expert --full-gen-key
gpg (GnuPG/MacGPG2) 2.2.32; 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.

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

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

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

あなたの選択は? S  # デフォルトだとSign&CertifyなのでCertifyのみに変更

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

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

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

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

本名: Junpei Tsuji  # 本名を入力
電子メール・アドレス: junpei.tsuji.ams@gmail.com  # 署名で利用するのでよく使うメールアドレスを入力
コメント:
次のユーザIDを選択しました:
    "Junpei Tsuji <junpei.tsuji.ams@gmail.com>"

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

# ここでこの鍵のパスフレーズの設定を求められます

gpg: 鍵27131B8D68CE0EE9を究極的に信用するよう記録しました
gpg: ディレクトリ'/Users/jun06t/.gnupg/openpgp-revocs.d'が作成されました
gpg: 失効証明書を '/Users/jun06t/.gnupg/openpgp-revocs.d/400397D054CBF0B4B0BD74AD27131B8D68CE0EE9.rev' に保管しました。
公開鍵と秘密鍵を作成し、署名しました。

pub   nistp521 2022-02-14 [C]
      400397D054CBF0B4B0BD74AD27131B8D68CE0EE9
uid                      Junpei Tsuji <junpei.tsuji.ams@gmail.com>

~ $

gpg: 鍵27131B8D68CE0EE9を究極的に信用するよう記録しました

に出力されている鍵IDは今後コマンドで頻繁に使うので、環境変数に設定しておきます。

$ export KEYID=27131B8D68CE0EE9

副鍵の作成

次に3つの副鍵をそれぞれ作ります。
期限は付けることが推奨されてますが、利便性とのトレードオフになります。
Yubikeyなどのハードウェアに移した場合は取り出せなくなるので個人的には無期限で良いかなと思います。

暗号化

~ $ gpg --expert --edit-key $KEYID
gpg (GnuPG/MacGPG2) 2.2.32; 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.

秘密鍵が利用できます。

sec  nistp521/27131B8D68CE0EE9
     作成: 2022-02-14  有効期限: 無期限      利用法: C
     信用: 究極        有効性: 究極
[  究極  ] (1). Junpei Tsuji <junpei.tsuji.ams@gmail.com>

gpg> addkey
ご希望の鍵の種類を選択してください:
   (3) DSA (署名のみ)
   (4) RSA (署名のみ)
   (5) Elgamal (暗号化のみ)
   (6) RSA (暗号化のみ)
   (7) DSA (機能をあなた自身で設定)
   (8) RSA (機能をあなた自身で設定)
  (10) ECC (署名のみ)
  (11) ECC (機能をあなた自身で設定)
  (12) ECC (暗号化のみ)
  (13) 既存の鍵
  (14) カードに存在する鍵
あなたの選択は? 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
あなたの選択は? 5
鍵の有効期限を指定してください。
         0 = 鍵は無期限
      <n>  = 鍵は n 日間で期限切れ
      <n>w = 鍵は n 週間で期限切れ
      <n>m = 鍵は n か月間で期限切れ
      <n>y = 鍵は n 年間で期限切れ
鍵の有効期間は? (0)0
鍵は無期限です
これで正しいですか? (y/N) y
本当に作成しますか? (y/N) y
たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。

# ここでこの鍵のパスフレーズの設定を求められます

sec  nistp521/27131B8D68CE0EE9
     作成: 2022-02-14  有効期限: 無期限      利用法: C
     信用: 究極        有効性: 究極
ssb  nistp521/11AD0FF2F4BFD05E
     作成: 2022-02-14  有効期限: 無期限      利用法: E
[  究極  ] (1). Junpei Tsuji <junpei.tsuji.ams@gmail.com>

gpg> q
変更を保存しますか? (y/N) y

署名

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
あなたの選択は? 5  # NIST
鍵の有効期限を指定してください。
         0 = 鍵は無期限
      <n>  = 鍵は n 日間で期限切れ
      <n>w = 鍵は n 週間で期限切れ
      <n>m = 鍵は n か月間で期限切れ
      <n>y = 鍵は n 年間で期限切れ
鍵の有効期間は? (0)0  # 無期限
鍵は無期限です
これで正しいですか? (y/N) y
本当に作成しますか? (y/N) y
たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。

# ここでこの鍵のパスフレーズの設定を求められます

sec  nistp521/27131B8D68CE0EE9
     作成: 2022-02-14  有効期限: 無期限      利用法: C
     信用: 究極        有効性: 究極
ssb  nistp521/11AD0FF2F4BFD05E
     作成: 2022-02-14  有効期限: 無期限      利用法: E
ssb  nistp521/3B0879ECC6A5E40E
     作成: 2022-02-14  有効期限: 無期限      利用法: S
[  究極  ] (1). Junpei Tsuji <junpei.tsuji.ams@gmail.com>

認証

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

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

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

あなたの選択は? S  # 署名機能をOFFに

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

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

あなたの選択は? A  # 認証機能をONに

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

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

あなたの選択は? Q
ご希望の楕円曲線を選択してください:
   (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
あなたの選択は? 5  # NISTの鍵
鍵の有効期限を指定してください。
         0 = 鍵は無期限
      <n>  = 鍵は n 日間で期限切れ
      <n>w = 鍵は n 週間で期限切れ
      <n>m = 鍵は n か月間で期限切れ
      <n>y = 鍵は n 年間で期限切れ
鍵の有効期間は? (0)0  # 無期限
鍵は無期限です
これで正しいですか? (y/N) y
本当に作成しますか? (y/N) y
たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。

# ここでこの鍵のパスフレーズの設定を求められます

sec  nistp521/27131B8D68CE0EE9
     作成: 2022-02-14  有効期限: 無期限      利用法: C
     信用: 究極        有効性: 究極
ssb  nistp521/11AD0FF2F4BFD05E
     作成: 2022-02-14  有効期限: 無期限      利用法: E
ssb  nistp521/3B0879ECC6A5E40E
     作成: 2022-02-14  有効期限: 無期限      利用法: S
ssb  nistp521/48920981EDF04394
     作成: 2022-02-15  有効期限: 無期限      利用法: A
[  究極  ] (1). Junpei Tsuji <junpei.tsuji.ams@gmail.com>

gpg> q
変更を保存しますか? (y/N) y

動作確認

鍵を生成したので署名や暗号化の動作確認をしてみます。
動作確認用のファイルを用意しておきます。

$ echo "gpg test" > test.txt

署名

$ gpg -u $KEYID -s test.txt

すると*.gpgのsuffixがついたfile.txt.gpgが生成されます。
署名には秘密鍵を用いています。

署名検証

$ gpg --verify test.txt.gpg
gpg: 水  2/16 22:31:26 2022 JSTに施された署名
gpg:                ECDSA鍵A4C4CE561C148B189D55252B3B0879ECC6A5E40Eを使用
gpg: "Junpei Tsuji <junpei.tsuji.ams@gmail.com>"からの正しい署名 [究極]

署名検証には公開鍵を用いています。
APT などのパッケージ管理ツールはこの仕組みでファイルが正しいかをチェックしています。

暗号化

$ gpg -e -r $KEYID file.txt

*.gpgのsuffixがついたfile.txt.gpgが生成されます。

暗号化には公開鍵を使ってます。なので第三者にGPG暗号化ファイルを渡す場合はその人のGPGの公開鍵をもらう必要があります。
公開鍵サーバに登録されている場合は

$ gpg -e -r <相手のメールアドレス> file.txt

で自動で公開鍵をダウンロードして暗号化できます。

復号

$ gpg -d test.txt.gpg
gpg: 521-ビットECDH鍵, ID 11AD0FF2F4BFD05E, 日付2022-02-14に暗号化されました
      "Junpei Tsuji <junpei.tsuji.ams@gmail.com>"
gpg test

復号では秘密鍵を用います。

主鍵の秘密鍵を削除

主鍵の秘密鍵をマシン上に残すのはリスクになるためバックアップをとって削除しておきます。

マシン上は以下の状態にする感じです。

f:id:quoll00:20220217063022p:plain:w400

エクスポート

各鍵をエクスポートします。

主鍵&副鍵全て

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

生成時に設定したパスフレーズの入力を求められます。

f:id:quoll00:20220301114458p:plain

副鍵のみ

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

生成時に設定したパスフレーズの入力を求められます。

f:id:quoll00:20220301114440p:plain

公開鍵のみ

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

失効証明書

失効証明書も主鍵がないと作れないので、あらかじめ作っておきます。

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

保存

エクスポートしたら暗号化してUSBに保存したり、QRコードに変換して紙に保存すると良いです。

削除し、副鍵のみインポート

バックアップが取れたら主鍵をマシンから削除します。

まずは全ての秘密鍵を削除し、

$ gpg --delete-secret-keys $KEYID
gpg (GnuPG/MacGPG2) 2.2.32; 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.


sec  nistp521/27131B8D68CE0EE9 2022-02-14 Junpei Tsuji <junpei.tsuji.ams@gmail.com>

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

先程エクスポートした副鍵をインポートします。

$ gpg --import sub.key
gpg: 鍵27131B8D68CE0EE9:"Junpei Tsuji <junpei.tsuji.ams@gmail.com>"変更なし
gpg: 'secring.gpg'の移行には、スマードカードそれぞれで、以下を実行してください: gpg --card-status
gpg: 鍵27131B8D68CE0EE9: 秘密鍵をインポートしました
gpg:           処理数の合計: 1
gpg:               変更なし: 1
gpg:       秘密鍵の読み込み: 1
gpg:     秘密鍵のインポート: 1

鍵一覧を表示すると、主鍵に#(使用不可)が付くようになっています。

$ gpg -K
--------------------------------
sec#  nistp521 2022-02-14 [C]
      400397D054CBF0B4B0BD74AD27131B8D68CE0EE9
uid           [  究極  ] Junpei Tsuji <junpei.tsuji.ams@gmail.com>
ssb   nistp521 2022-02-14 [E]
ssb   nistp521 2022-02-14 [S]
ssb   nistp521 2022-02-15 [A]

GitHubに登録

公開鍵はGitHubでCommitの署名に使うので登録しておきます。

christina04.hatenablog.com

署名の検証には副鍵の公開鍵を使いますが、副鍵は主鍵にバインドされてるので公開鍵は1つのファイルとして扱われます。

key management - One public key contains all subkeys? - Information Security Stack Exchange

まとめ

GPGの主鍵と副鍵を作成しました。
次回は副鍵をYubikeyに転送しようと思います。

参考