【マサカリ希望】OpenPGPとかGnuPGってなんですか？

## 経緯

PGPなるもの、調べども調べども、わからざること増えにけり、智者の鉞を給ふべく、ここに書き記し候ふ。

**（現代語訳）**
今までなんとなくわかったふりして「 `gpg --gen-key` すれば良いんでしょ」と使ってきたPGP系の暗号技術だが、
[Yubikey 5C NFC](https://www.yubico.com/jp/product/yubikey-5c-nfc/)の購入を機に、ちゃんと理解してみたい。
とは言え、調べれば調べるほどわからないことが増えたので、今の理解をとりあえず書き記して、有識者にマサカリを投げてもらおう。

## What's Yubikey

![5CNFC-5Ci-keychain-2-1-450x450.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234167/e741d92f-19d5-ed7c-d113-08cf66195938.jpeg)

まずは契機となったYubikeyについて。
米国[Yubico](https:://www.yubico.com/)社が製造するハードウェア認証デバイスのシリーズ。
今回購入した[Yubikey 5C NFC](https://www.yubico.com/jp/product/yubikey-5c-nfc/)はUSB-CとNFCに対応したもので、
日本でもAmazonから6千円ぐらいで買える。
対応するプロトコルは、[WebAuthn](https://ja.wikipedia.org/wiki/WebAuthn)、[FIDO2](https://ja.wikipedia.org/wiki/FIDO_(%E8%AA%8D%E8%A8%BC%E6%8A%80%E8%A1%93))、[Smart card (PIV-compatible)](https://ja.wikipedia.org/wiki/FIPS_201)、[Yubico OTP](https://www.yubico.com/products/services-software/yubikey-otp/)、[OATH – HOTP](https://en.wikipedia.org/wiki/HMAC-based_One-time_Password_algorithm)、[Open PGP (RSA 4096bit)](https://ja.wikipedia.org/wiki/Pretty_Good_Privacy), Secure Static Password。

いろいろあって面食らったが、一個ずつ調べてみる。

まず、PIVってのが日本語でぜんぜん情報が出てこなかった。
それもそのはず、PIVは[FIPS 201](https://ja.wikipedia.org/wiki/FIPS_201)と言う米国連邦標準規格のなかの「連邦政府の職員及び請負業者のための個人識別情報の検証要件」のことだった。
一般的な日本人にとっては関係なさそうだが、PKCS#11準拠のライブラリを介してSSH対応の秘密鍵を保管できたりする。

FIDO2はFIDOアライアンスが策定したCTAP1（FIDO2じゃなかった頃にU2F（Universal 2 Factor）と呼ばれていた2段階認証）および、その発展形であるCTAP2とWebAuthnの組み合わせのことで、ざっくり言うとユーザからOSまでの間がCTAP、OSからブラウザまでの規格がWebAuthnらしい。
Yubico OTPはYubico独自規格（AES 128bit on Cloud & 44 chars OTP）で、OATH-HOTPが時刻または生成回数ベースのOTP、Secure Static Passwordがパスワードの内部メモリ保存または生成で、正直使い所がない。
ということで、残るはOpen PGPだ。
よし、Open PGPについてちゃんと調べよう。

そんなことを調べてる過程で、Yubikey 5C NFCは防水（ `water-resistant` だから生活防水程度かと思ったら、「[水深48mの塩水に2カ月漬けても大丈夫」](https://securitykey.yubion.com/yubikey_about.html)）てことも知った。へー。

## What's PGP

[Pretty Good Privacy](https://ja.wikipedia.org/wiki/Pretty_Good_Privacy#:~:text=Pretty%20Good%20Privacy%EF%BC%88%E3%83%97%E3%83%AA%E3%83%86%E3%82%A3%E3%83%BB%E3%82%B0%E3%83%83%E3%83%89,%E3%81%97%E3%81%9F%E6%9A%97%E5%8F%B7%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%A7%E3%81%82%E3%82%8B%E3%80%82)の略。
公開鍵暗号方式の種々のアルゴリズムを使って、ファイル等を暗号化/復号化するソフトウェア。
開発当時、暗号方式は米国で武器扱いのため輸出禁止されていたにもかかわらず「普及しないと意味がない！」とソースコード全文を書籍にして輸出した話が有名。
現在、PGPはシマンテックに買収されて商用有償ソフトウェアになってしまったが、同仕様を標準化してオープンにした[OpenPGP](https://www.openpgp.org/about/)と、そこからさらに派生した[GNU Privacy Guard](https://ja.wikipedia.org/wiki/GNU_Privacy_Guard)（通称、GnuPGまたはGPG）が普及。
GPGは最初、OpenPGPで特許係争中だったアルゴリズム（[IDEA](https://ja.wikipedia.org/wiki/International_Data_Encryption_Algorithm)など）をサポートしなかったが、Version 2.0.20ごろに特許が切れたので、限定的にサポート。
現在では楕円曲線暗号[^ECC]なども含めたOpenPGP 2.1系に完全準拠している。
OpenPGPなYubicoも、よくわからないまま鍵生成したらECCだった。

要するに、PGPとかOpenPGPとかGPGとか色々あってよくわかんねーなと思っても「**つまり、全部一緒でしょ**」って考えて良さそう。
今までは全部違うと思ってたので、混乱のタネが一つ減った感ある。
GnuPGの最新版は[2.2.24](https://gnupg.org)。およそ2ヶ月ごとにリリースされてて、頻繁にバグフィックスされてる、素晴らしい。

[^ECC]: Elliptic Curve Cryptography、略してECC。具体的な暗号方式ではなく、楕円曲線の特徴を利用した暗号方式の総称。大きな合成数の素因数分解が大変なのを利用したRSAに比べて、 $ y^2 = x^3 + ax + b $ と言う曲線を使って、より短い桁数でRSAと同じ強度の値を得られるのが利点。

### What's 公開鍵暗号

対義語は同じ鍵を使って暗号化と復号化をする「[共通鍵暗号](https://ja.wikipedia.org/wiki/%E5%85%B1%E9%80%9A%E9%8D%B5%E6%9A%97%E5%8F%B7)」。同じ鍵を使うから「対称暗号」とも。

PGPがサポートする公開鍵暗号は「非対称暗号」、つまり、暗号化する鍵（秘密鍵; `Secret Key` ）と復号化する鍵（公開鍵; `Public Key` ）が別。
詳しくは[公開鍵暗号 - Wikipedia](https://ja.wikipedia.org/wiki/%E5%85%AC%E9%96%8B%E9%8D%B5%E6%9A%97%E5%8F%B7)に譲るとして、他人と共有しても問題ない「公開鍵」と自分だけがしっかり管理する「秘密鍵」を使うことで、単純な暗号化だけでなく認証( **is NOT 認可** )できるのがポイント。
ところで、ECCは送信時に適当な乱数を使うので、鍵が同じでも暗号文が毎回変わるらしい。え。

GPGでは、さらに鍵を作るための鍵「主鍵（ `Primary Keys` 、または `Master Keys` ）」[^PK]と普段使いの「副鍵（ `Subordinate Keys` ）」の概念がある。
主鍵は鍵への署名（ `Certification` ）用の鍵で、副鍵に「これは正しい副鍵ですよ」と署名し、有効期間などを設定することができる。
副鍵はデータ署名（ `Signing` ）のほか、暗号（ `Encryption` ）/復号（ `Decryption` ）用と認証（ `Authentication` ）用を作ることができる。

[^PK]: 調べてる中で一番厄介だったのがこれ。日本語で調べてると「主鍵は秘密鍵」とか「主鍵をMaster Keyと呼ぶ」とか出てくるけど、どちらも嘘。主鍵にも公開鍵/秘密鍵のペアがあるので単数形の `Master Key` にはなり得ない。誤解の原因は、事実上「主鍵は基本的に副鍵の署名にしか使わないので、秘密鍵しか要らない」ことと、[公式のチュートリアル](https://www.gnupg.org/gph/en/manual/c235.html)でさえ主鍵秘密鍵を `Primary Key`　、 `Master Key` と混用して記載されているためと思われ。

#### 鍵への署名 (Certification)

`Certification` と `Signing` 、って何が違うんですかね。
どうやら、鍵に対して行うか、データに対して行うかの違いってことらしい。
つまり、主鍵でなら `Certification` 、副鍵でなら `Signing` ってことか。
（厳密には主鍵で `Signing` したり、副鍵で `Certification` することもできるけど、後述する理由によって危険 or 無意味。）

これからデータを署名したり、暗号化したり、いずれにせよ主鍵の秘密鍵だけは絶対に漏洩させたくないので日常的に使用したくない。
なので、最初に一回、主鍵の秘密鍵で副鍵ペアを署名して、以後は副鍵だけを使い、主鍵は大事なところに隠しておく。
（主鍵をYubikeyに保管したり、Yubikeyで直接作ることもできるらしいが、Yubikey落としたらアウトだし、Yubikey持ってない人もいるので、保管のベストプラクティスってどうなんですかね？）

#### データへの署名 (Signing)

![Digitally Signing for Data.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234167/7c52d487-6dda-8152-2617-6dedd2cbf03f.png)

今まで暗号化/復号化したことはあっても署名を実装する機会があまりなかったので、知った気で理解してなかったポイント、その1。
つまり、署名では、受け手の鍵束を全く使わない。だから、受け手がGPGを知らなくてもなんら問題ない。

#### 暗号 / 復号 (Encryption / Decryption)

![Encryption & Decryption.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234167/d9f9a99a-ee3f-2bf1-fb0e-f5c0259ae5bb.png)

暗号化は、相手の公開鍵を使って行う。
署名で勘違いしてたのは「暗号文を復号できるのは秘密鍵を持ってる本人だけだから、それもつまり署名じゃん」と暗号/復号と署名をごちゃごちゃに理解していたところ。
それを実現するには、世界中の人が公開鍵を使えてないと無理だし、正しく暗号化されているか確認できてなきゃ意味ないですよね。

公開鍵のやりとりと証明に使うのが[公開鍵基盤](https://ja.wikipedia.org/wiki/%E5%85%AC%E9%96%8B%E9%8D%B5%E5%9F%BA%E7%9B%A4)、通称PKI（Public Key Infrastructure）。
PKIの実装として最も普及しているのが[X.509](https://ja.wikipedia.org/wiki/X.509)。

X.509が発行する証明書の例。

```plaintext
Certificate:
   Data:
       Version: 1 (0x0)
       Serial Number: 7829 (0x1e95)
       Signature Algorithm: md5WithRSAEncryption
       Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc,
               OU=Certification Services Division,
               CN=Thawte Server CA/emailAddress=server-certs@thawte.com
       Validity
           Not Before: Jul  9 16:04:02 1998 GMT
           Not After : Jul  9 16:04:02 1999 GMT
       Subject: C=US, ST=Maryland, L=Pasadena, O=Brent Baccala,
                OU=FreeSoft, CN=www.freesoft.org/emailAddress=baccala@freesoft.org
       Subject Public Key Info:
           Public Key Algorithm: rsaEncryption
           RSA Public Key: (1024 bit)
               Modulus (1024 bit):
                   00:b4:31:98:0a:c4:bc:62:c1:88:aa:dc:b0:c8:bb:
                   33:35:19:d5:0c:64:b9:3d:41:b2:96:fc:f3:31:e1:
                   66:36:d0:8e:56:12:44:ba:75:eb:e8:1c:9c:5b:66:
                   70:33:52:14:c9:ec:4f:91:51:70:39:de:53:85:17:
                   16:94:6e:ee:f4:d5:6f:d5:ca:b3:47:5e:1b:0c:7b:
                   c5:cc:2b:6b:c1:90:c3:16:31:0d:bf:7a:c7:47:77:
                   8f:a0:21:c7:4c:d0:16:65:00:c1:0f:d7:b8:80:e3:
                   d2:75:6b:c1:ea:9e:5c:5c:ea:7d:c1:a1:10:bc:b8:
                   e8:35:1c:9e:27:52:7e:41:8f
               Exponent: 65537 (0x10001)
   Signature Algorithm: md5WithRSAEncryption
       93:5f:8f:5f:c5:af:bf:0a:ab:a5:6d:fb:24:5f:b6:59:5d:9d:
       92:2e:4a:1b:8b:ac:7d:99:17:5d:cd:19:f6:ad:ef:63:2f:92:
       ab:2f:4b:cf:0a:13:90:ee:2c:0e:43:03:be:f6:ea:8e:9c:67:
       d0:a2:40:03:f7:ef:6a:15:09:79:a9:46:ed:b7:16:1b:41:72:
       0d:19:aa:ad:dd:9a:df:ab:97:50:65:f5:5e:85:a6:ef:19:d1:
       5a:de:9d:ea:63:cd:cb:cc:6d:5d:01:85:b5:6d:c8:f3:d9:f7:
       8f:0e:fc:ba:1f:34:e9:96:6e:6c:cf:f2:ef:9b:bf:de:b5:22:
       68:9f
```

```markdown
- 証明書
  - バージョン
  - 通し番号
  - アルゴリズムID
  - 発行者
  - 有効期間
      - 開始
      - 満了
  - 主体者
  - 主体者の公開鍵情報
      - 公開鍵アルゴリズム
      - 主体者の公開鍵
  - 発行者の一意な識別子 (予備)
  - 主体者の一意な識別子 (予備)
  - 拡張 (予備)
- 証明書の署名アルゴリズム
- 証明書の署名
```

証明書に「主体者」とあっても、いくらでもなりすましができるので、「本当に本人の公開鍵か」を確かめる必要がある。
（主体者と発行者が同一なのが、いわゆるオレオレ証明書。）
本人確認のために存在するのが[Fingerprint](https://ja.wikipedia.org/wiki/%E6%8C%87%E7%B4%8B_(%E5%85%AC%E9%96%8B%E9%8D%B5%E6%9A%97%E5%8F%B7))と[認証局](https://ja.wikipedia.org/wiki/%E8%AA%8D%E8%A8%BC%E5%B1%80)（通称CA; Certification Authority）、そして、[Web of Trust](https://en.wikipedia.org/wiki/Web_of_trust)。

##### Fingerprint

その名の通り、指紋。マイクロソフトは頑なに拇印、Thumbprintと呼んでるらしいけど。
ざっくり言えば、公開鍵の送り手と受け手それぞれで証明書からハッシュ値を計算して突合して、合ってればOKでしょ作戦。

> 例えば、アリスがボブの公開鍵を検証したい場合、彼女は電話や直接会うなどの方法でボブと連絡をして、ボブの公開鍵の指紋を読み上げてもらうか、指紋が書かれた紙を渡してもらう。アリスはこの信頼できる指紋が入手した公開鍵のものと一致するかを確認することができる。このように、値を交換して比較することは、値が長い公開鍵ではなく短い指紋である場合には簡単なことである。

あれ、これってボブが声色を真似てた他人だったら破綻じゃない？

##### Certification Authority

公開鍵が正しいかは皆が信頼する第三者に担保してもらいましょう作戦。
公開鍵を登録するときに身元を確認したりお金を取ったりして証明書を発行することで、証明書の持ち主=公開鍵の正当な所有者とする。
SSL証明書が一番身近ですね。

…だけど、身元確認と有料化で正当性が担保できる理屈がいまいちわからん。
お金持ちとお金に弱い認証局があったら、総崩れなんじゃないの？
と思ったら、[Certification Transparency](https://certificate.transparency.dev)で、認証局の信用性を確かめたりしてるんですね。なるほど。

##### Web of Trust

「CAにはじまる中央集権的な証明って、なんか嫌じゃん？」って思ったんでしょうね、きっと。
PGPは「みんなに正しいと言われてる人は正しいに違いない」作戦、その名も「信用の輪」。
1by1な関係は前述のFingerprint等ですぐに検証できるんだから、それを繰り返していきましょう、
多くの人から信用され、また直接的に信用されていればいるほど（= グラフ構造で言うところの平均最短距離が短ければ短いほど）、より信用できるでしょう。

…え、ほんとか。
[スモールワールド・ネットワーク](https://ja.wikipedia.org/wiki/%E8%A4%87%E9%9B%91%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF)で「誰でも6次でつながる」って、しかも、ごく少数のハブ的な存在がいるだけで良いって書いてあったよね。
その理屈で行けば絶大な信用を得るのは難しくとも、それなりの信用を得るのは簡単なんじゃないの？

##### SPKI (Simple public key infrastructure)

調べていくと[簡易公開鍵基盤](https://ja.wikipedia.org/wiki/%E7%B0%A1%E6%98%93%E5%85%AC%E9%96%8B%E9%8D%B5%E5%9F%BA%E7%9B%A4)と言うものもあるらしい。
実際に使ってるのを見たことはない。
「人と鍵をセットにして信用するの無理じゃね」って思ったんでしょうね、知らんけど。
[RFC2692](https://tools.ietf.org/html/rfc2692)と[RFC2693](https://tools.ietf.org/html/rfc2693)を読んで、
めちゃくちゃ意訳すると「『相手がAさんであるか』（= 認証）わからなくても『あの人はBとCができる』（= 認可）とわかってれば良いじゃん、てか『BとCができる』ってことはAさんに違いないよ」、でしょうか。
大変興味深い、けど簡易じゃないし、深追いする気にならない。

##### In-band & Out-of-band

公開鍵暗号を介した通信、例えばHTTPSなどはプロトコルのレベルで自動的に公開鍵のやりとりがサポートされていて、これをインバンド方式と呼ぶ。
他にはS/MIMEやTLSがある。つまり、暗号化の仕組みを知らなくても使える方式。

他方、通信中に行わないものはアウトオブバンド、略してOOB。
いわゆるワンタイムパスワードやSMS認証は、認証そのものの通信の外でやりとりしているのでOOB。
あれ、だけどやっぱり暗号化の仕組みを知らなくても使えてる気がするな。

#### 認証 (Authentication)

署名と暗号化/復号化を調べてるうちに、「そりゃSSHのログインにも公開鍵暗号が使えますわ」と自然に理解。
というか、先の「暗号文を復号化できるのは秘密鍵を持ってる本人だけだから、それもつまり署名じゃん」の勘違いは、SSHからPGPの世界に入ったせいだ。

今は、なぜ「接続先のFingerprintを調べれば、接続先が本物か確かめられる」のか、一応わかる。
ただ、「サーバ構築入門」的な流れでよく見る「接続先で鍵ペア作る」行為、あれ、かなり危険ですね。まったく気づいてなかった。

## MacOSでGPGを使う

てことで、実際にMacOSでGPGを使っていきましょう。
千里の道は `brew install gpg` からはじまる。

具体的な各作業については割愛。もう疲れた。

## 所感

調べれば調べるほどわからないことが増えていきつつ、よく知らないままでもそれなりに使える暗号技術って、ひとえに先人の弛まぬ研鑽のおかげだなと実感。
自分で図を書いてやっと入り口に立ったぐらいの気持ち。
サイモン・シンの『暗号解読』をもう一回読み直したいし、Wikipediaで[暗号関係の書籍の一覧](https://ja.wikipedia.org/wiki/%E6%9A%97%E5%8F%B7%E9%96%A2%E4%BF%82%E3%81%AE%E6%9B%B8%E7%B1%8D%E3%81%AE%E4%B8%80%E8%A6%A7#%E6%AD%B4%E5%8F%B2%E3%83%BB%E8%87%AA%E5%8F%99%E4%BC%9D)なんて激アツなページも見つけてしまったのだが、
書籍も良いけど、誰かと雑に談しながら理解を深めていきたいなぁ。コロナ禍、早く終わらんかなぁ。

あと、結局のところ、主鍵束を作った時のパスフレーズ忘れると死ぬって問題があって、「パスフレーズを絶対忘れない方法…あ、俺の身体(虹彩、静脈、耳形、DNA等々)からパスフレーズ作りたい！」って思ったら、Yubicoの次期製品[Yubikey Bio](https://pages.yubico.com/yubikey-bio-updates.html)がそれを叶えてくれそう。
だけど、指紋だけっぽいなぁ。指紋は盗まれそうだなぁ。
NFCを掌にインストールしたいわ。

## 参考

- [dev.yubico - What is PGP?](https://developers.yubico.com/PGP/)
- [GitHub - drduh/YubiKey-Guide](https://github.com/drduh/YubiKey-Guide)
- [Encrypting vs. Signing with OpenPGP. What’s the Difference? - MDaemon Technologies Blog](https://blog.mdaemon.com/encrypting-vs-signing-with-openpgp-whats-the-difference)
- [図解 X.509 証明書 - Qiita](https://qiita.com/TakahikoKawasaki/items/4c35ac38c52978805c69)
- [生体認証 - Wikipedia](https://ja.wikipedia.org/wiki/%E7%94%9F%E4%BD%93%E8%AA%8D%E8%A8%BC)