Skip to content

Instantly share code, notes, and snippets.

@Commod0re
Last active November 16, 2017 21:07
Show Gist options
  • Save Commod0re/801256701bc71f0251de2b708365e61c to your computer and use it in GitHub Desktop.
Save Commod0re/801256701bc71f0251de2b708365e61c to your computer and use it in GitHub Desktop.
inspect PGP packets in PGPy 0.4.x
#!/usr/bin/env python
# this is a hackish way to inspect the packets in a PGP object with PGPy 0.4.x
# in the future listing packets directly and determining what fields are useful should be part of the API
# this example prints a few packet types in close to the same format as gpg --list-packets
import sys
from pgpy.types import Armorable
from pgpy.packet import Packet
from pgpy.constants import PacketTag
def pgp_packets(text):
unarmored = Armorable.ascii_unarmor(text)
data = unarmored['body']
while data:
pkt = Packet(data)
yield pkt
if __name__ == '__main__':
for fn in sys.argv[1:]:
with open(fn) as f:
text = f.read()
offset = 0
for packet in pgp_packets(text):
# if you want to just print the repr for the packet class:
# print(packet)
# otherwise, details can be gathered and printed by inspecting packet
# packet header details (these are common to all packet types)
hdr = {}
hdr['off'] = offset
hdr['ctb'] = packet.header.__bytes__()[0],
hdr['tag'] = packet.header.tag,
hdr['hlen'] = len(packet.header)
hdr['plen'] = len(packet) - hdr['hlen']
hdr['lfmt'] = "new-ctb" if packet.header._lenfmt else ""
print("# off={off:} ctb={ctb:02x} tag={tag:} hlen={hlen:} plen={plen:} {lfmt:}".format_map(hdr))
# increment offset for the next packet
offset += hdr['plen'] + hdr['hlen']
# interpreting individual packets depends on each packet, here are a couple to get you started
# check pgpy/packet/packets.py for the relevant properties in order to add more, or inspect them with dir() or tab completion in ipython
if packet.header.tag in {PacketTag.PublicKey, PacketTag.PublicSubKey}:
# private key packets have these fields, plus a few more
print(":public {} packet:".format("sub key" if packet.header.tag == PacketTag.PublicSubKey else "key"))
ver = packet.header.version
algo = packet.pkalg
created = packet.created
# "expires" depends on signatures that follow and this example script isn't smart enough for that currently
print(" version {ver:}, algo {algo:}, created {created:}".format(ver=ver, algo=algo, created=created))
for i, field in enumerate(packet.keymaterial.__pubfields__):
print(" pkey[{}]: [{} bits]".format(i, getattr(packet.keymaterial, field).bit_length()))
print(" keyid: {}".format(packet.fingerprint.keyid))
if packet.header.tag == PacketTag.UserID:
# as we work on the packet API this pre-formatting step should become unnecessary
uid = packet.name
if packet.comment:
uid = '{} ({})'.format(uid, uid.comment)
if packet.email:
uid = '{} <{}>'.format(uid, uid.email)
print(':user ID packet: "{}"'.format(uid))
if packet.header.tag == PacketTag.UserAttribute:
print(":attribute packet: [{} image of size {}]".format(packet.image.iencoding.name, len(packet.image.image)))
# TODO: add more packet types here
@Commod0re
Copy link
Author

Commod0re commented Jun 12, 2017

For a key that is already loaded:

for packet in pgp_packets(str(key)):
    ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment