OpenPGPを調べる
OpenPGPを勉強したくなったので、調べたことをまとめる。
RFCを読む
RFC4880として仕様がまとまっているのでそれを読む(もう少し新しいものがありそうだが、とりあえずこれを)
OpenPGPでデータを交換する際の最小単位をパケットという。
パケットはパケットヘッダーとパケットボディが結合されて構成される。
パケットヘッダーはさらに細分化でき、1バイトのパケットタグと1~5バイトのパケットボディ長から構成される。パケットタグがパケットの種類を示し、パケットボディの内容はその種別に応じて構成される。パケットヘッダーのビット単位のフォーマットはSection 4に記載されている。
基本的に、パケットは複数個結合して意味のある単位として交換される。
この際の、目的に応じたパケットの組み合わせはSection 11に記載がある。
例えば公開鍵を交換したいのであれば、最低限公開鍵パケットとユーザーIDパケットがなければならない。その他、必要なら署名に関するパケットも付与できる。
パケットは、そのままだとテキストとしては扱えず交換に難儀する場合がある。そのため、仕様ではパケットをテキストで表現するためのASCIIアーマーという形式も定義されている。恐らく、私たちがWeb上で目視するOpenPGP準拠のデータは、大抵の場合これによってエンコードされているはずである。例えばPGP公開鍵について|国税庁法人番号公表サイトでもASCIIアーマーでエンコードされた公開鍵を見ることができる。
ASCIIアーマーの仕様はSection 6.2に記載されており、おおよそBEGIN PGP PUBLIC KEY BLOCK
のようなアーマーヘッダーラインと、それに対応するアーマーテールでパケットのBase64表現を囲む形になる。アーマーヘッダーラインも目的に応じて文字列が規定されている。
ASCIIアーマー形式ならWeb上で人による交換が容易になるが、エンコードされているパケットの詳細が一目で分かるかと言われれば、Base64でエンコードされているためそうでもない。もしパケットが気になるなら、GnuPGを使ってASCIIアーマー形式がエンコードしているパケットをダンプすることができる。
先ほどの国税庁法人番号公表サイトで公開されている公開鍵をnta.asc
で保存し、gpg --list-packets nta.asc
とすればパケットをダンプできる。
$ gpg --list-packets nta.asc
# off=0 ctb=99 tag=6 hlen=3 plen=269
:public key packet:
version 4, algo 1, created 1431311175, expires 0
pkey[0]: [2048 bits]
pkey[1]: [17 bits]
keyid: 4BCD87A24D615230
# off=272 ctb=b4 tag=13 hlen=2 plen=36
:user ID packet: "National Tax Agency Corporate Number"
# off=310 ctb=89 tag=2 hlen=3 plen=312
:signature packet: algo 1, keyid 4BCD87A24D615230
version 4, created 1431311175, md5len 0, sigclass 0x13
digest algo 2, begin of digest b0 64
hashed subpkt 2 len 4 (sig created 2015-05-11)
hashed subpkt 27 len 1 (key flags: 03)
hashed subpkt 11 len 5 (pref-sym-algos: 9 8 7 3 2)
hashed subpkt 21 len 5 (pref-hash-algos: 8 2 9 10 11)
hashed subpkt 22 len 3 (pref-zip-algos: 2 3 1)
hashed subpkt 30 len 1 (features: 01)
hashed subpkt 23 len 1 (keyserver preferences: 80)
subpkt 16 len 8 (issuer key ID 4BCD87A24D615230)
data: [2048 bits]
# off=...
から始まる行が、パケットヘッダーの情報を示す(はず)。ここを見れば、パケットヘッダー中のパケットタグが示す種別(tag
)やパケットボディ長(plen
)が分かる。
ちなみに、tag=13
は公開鍵パケット、tag=2
はユーザーIDパケットと仕様で定義されているので、国税庁法人番号公表サイトで公開されているこのASCIIアーマー形式の公開鍵は、Section 11に正しく準拠していることがわかる。
パケットの種類
主要なパケットには以下のものがある。
公開鍵パケット(タグ: 6)
公開鍵を保持するバケット。以下の一連のデータを連結して構成される。
- フォーマットのバージョン1バイト。バージョン4(
0x04
)が推奨 - 公開鍵作成日時を表すUnixタイムスタンプ4バイト
- 公開鍵のアルゴリズムを示す1バイト(一覧)。
0x01
ならRSA (Encrypt or Sign)
これ以降のデータは「3.」のアルゴリズム次第になる。0x01
でRSA (Encrypt or Sign)
の場合、
- RSA公開鍵のモジュラスを示す多倍長整数
- RSA公開鍵の公開指数を示す多倍長整数
となる。多倍長整数をどのようにエンコードするかも仕様で決まっており、
- 多倍長整数のビット数表す2バイト整数
- 「1.」で示されるビット長の、多倍長整数(1バイト境界に足りない分のビットはゼロ埋め)
となっている。
GnuPGで公開鍵パケットをダンプするとキーIDが表示されるが、キーIDはパケットにエンコードされているわけではない。以下のデータを結合したバイト列のSHA-1ハッシュを計算し、その下位8バイトがキーIDとして使われる。
- 固定の1バイト
0x99
- 公開鍵パケットのパケットボディ長を表す2バイト整数
- 公開鍵パケットのパケットボディ
ユーザーIDパケット(タグ: 13)
パケットボディにUTF-8でエンコードされたユーザーIDを持つパケット。