Open3

OpenPGPを調べる

murakmiimurakmii

OpenPGPを勉強したくなったので、調べたことをまとめる。

murakmiimurakmii

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に正しく準拠していることがわかる。

murakmiimurakmii

パケットの種類

主要なパケットには以下のものがある。

公開鍵パケット(タグ: 6)

公開鍵を保持するバケット。以下の一連のデータを連結して構成される。

  1. フォーマットのバージョン1バイト。バージョン4(0x04)が推奨
  2. 公開鍵作成日時を表すUnixタイムスタンプ4バイト
  3. 公開鍵のアルゴリズムを示す1バイト(一覧)。0x01ならRSA (Encrypt or Sign)

これ以降のデータは「3.」のアルゴリズム次第になる。0x01RSA (Encrypt or Sign)の場合、

  1. RSA公開鍵のモジュラスを示す多倍長整数
  2. RSA公開鍵の公開指数を示す多倍長整数

となる。多倍長整数をどのようにエンコードするかも仕様で決まっており、

  1. 多倍長整数のビット数表す2バイト整数
  2. 「1.」で示されるビット長の、多倍長整数(1バイト境界に足りない分のビットはゼロ埋め)

となっている。
GnuPGで公開鍵パケットをダンプするとキーIDが表示されるが、キーIDはパケットにエンコードされているわけではない。以下のデータを結合したバイト列のSHA-1ハッシュを計算し、その下位8バイトがキーIDとして使われる。

  1. 固定の1バイト 0x99
  2. 公開鍵パケットのパケットボディ長を表す2バイト整数
  3. 公開鍵パケットのパケットボディ

ユーザーIDパケット(タグ: 13)

パケットボディにUTF-8でエンコードされたユーザーIDを持つパケット。