gpgpdump - OpenPGP packet visualizer

no extension

余暇でちまちま作っていたが,とりあえず使えるようになったので。

OpenPGP パケットの内容を視覚化する gpgpdump の 0.1.0 をリリースした。 名前でピンとくる人もいるだろうが,山本和彦さんの pgpdump の翻案である。 特徴は以下のとおり。

たとえば

$ cat sig -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iF4EARMIAAYFAlTDCN8ACgkQMfv9qV+7+hg2HwEA6h2iFFuCBv3VrsSf2BREQaT1 T1ZprZqwRPOjiLJg9AwA/ArTwCPz7c2vmxlv7sRlRLUI6CdsOqhuO1KfYXrq7idI =ZOTN -----END PGP SIGNATURE-----

という OpenPGP 署名データがあるとする。 これを pgpdump で表示すると

$ pgpdump sig Old: Signature Packet(tag 2)(94 bytes) Ver 4 - new Sig type - Signature of a canonical text document(0x01). Pub alg - Reserved for ECDSA(pub 19) Hash alg - SHA256(hash 8) Hashed Sub: signature creation time(sub 2)(4 bytes) Time - Sat Jan 24 11:52:15 東京 (標準時) 2015 Sub: issuer key ID(sub 16)(8 bytes) Key ID - 0x31FBFDA95FBBFA18 Hash left 2 bytes - 36 1f Unknown signature(pub 19)

となる。 一方, gpgpdump の場合は

$ gpgpdump sig [[Packet]] name = "Packet" value = "Signature Packet (tag 2)" note = "94 bytes" [[Packet.Item]] name = "Version" value = "4" dump = "04" note = "new" [[Packet.Item]] name = "Signiture Type" value = "Signature of a canonical text document (0x01)" [[Packet.Item]] name = "Public-key Algorithm" value = "ECDSA public key algorithm (pub 19)" [[Packet.Item]] name = "Hash Algorithm" value = "SHA256 (hash 8)" [[Packet.Item]] name = "Hashed Subpacket" [[Packet.Item.Item]] name = "Signature Creation Time (sub 2)" value = "2015-01-24T11:52:15+09:00" dump = "54 c3 08 df" [[Packet.Item]] name = "Unhashed Subpacket" [[Packet.Item.Item]] name = "Issuer (sub 16)" value = "0x31FBFDA95FBBFA18" [[Packet.Item]] name = "Hash left 2 bytes" dump = "36 1f" [[Packet.Item]] name = "Multi-precision integer" dump = "..." note = "ECDSA r (256 bits)" [[Packet.Item]] name = "Multi-precision integer" dump = "..." note = "ECDSA s (252 bits)"

という感じで同等の内容を TOML フォーマットで出力する。 また -j オプションを付けると

$ gpgpdump -j sig { "Packet": [ { "name": "Packet", "value": "Signature Packet (tag 2)", "note": "94 bytes", "Item": [ { "name": "Version", "value": "4", "dump": "04", "note": "new" }, { "name": "Signiture Type", "value": "Signature of a canonical text document (0x01)" }, { "name": "Public-key Algorithm", "value": "ECDSA public key algorithm (pub 19)" }, { "name": "Hash Algorithm", "value": "SHA256 (hash 8)" }, { "name": "Hashed Subpacket", "Item": [ { "name": "Signature Creation Time (sub 2)", "value": "2015-01-24T11:52:15+09:00", "dump": "54 c3 08 df" } ] }, { "name": "Unhashed Subpacket", "Item": [ { "name": "Issuer (sub 16)", "value": "0x31FBFDA95FBBFA18" } ] }, { "name": "Hash left 2 bytes", "dump": "36 1f" }, { "name": "Multi-precision integer", "dump": "...", "note": "ECDSA r (256 bits)" }, { "name": "Multi-precision integer", "dump": "...", "note": "ECDSA s (252 bits)" } ] } ] }

という感じに JSON 形式で出力する。 だいぶ冗長な表現で申し訳ないが,解析結果を以下の struct で正規化している。

//Packets - OpenPGP packets
type Packets struct {
    Packet []*Item
}

//Item - item in Packets
type Item struct {
    Name  string  `toml:"name" json:"name"`
    Value string  `toml:"value,omitempty" json:"value,omitempty"`
    Dump  string  `toml:"dump,omitempty" json:"dump,omitempty"`
    Note  string  `toml:"note,omitempty" json:"note,omitempty"`
    Item  []*Item `toml:"Item,omitempty" json:"Item,omitempty"`
}

gpgpdumpGo 言語の勉強用に作成した。

golang.org/x/crypto/openpgp/packet というパッケージがあって,これを使えば簡単にできるだろうと思ったのが大間違いで,結局このパッケージで使えたのは OpaquePacketOpaqueSubpacket くらい。 実際のパケットの解析はゴリゴリとコードを書くはめになった。 いや,これだけでもだいぶ助かったけど。

とはいえ,まだまだ課題はあって

  • パケット解析部分のテストが未実装。つか,古いフォーマットのパケットのテストどうしよう
  • そもそもパケット解析部分は作りが悪くて,不正なパケットを食わせると簡単に panic が起きてしまうので全面的に書きなおす予定
  • Compressed Data Packet (Tag 8) が未実装。どうやって実現しようか悩み中
  • 実は ECC (RFC 6637) がよく分かってない。もしかしたら解釈を間違えているかもしれない
  • 最終的には pgpdump と同等な出力を目指す

といったあたりを,これからゆっくり手を入れていこうと考えている。

ブックマーク