+ _packet_types = {
+ 0: 'reserved',
+ 1: 'public-key encrypted session key packet',
+ 2: 'signature packet',
+ 3: 'symmetric-key encrypted session key packet',
+ 4: 'one-pass signature packet',
+ 5: 'secret-key packet',
+ 6: 'public-key packet',
+ 7: 'secret-subkey packet',
+ 8: 'compressed data packet',
+ 9: 'symmetrically encrypted data packet',
+ 10: 'marker packet',
+ 11: 'literal data packet',
+ 12: 'trust packet',
+ 13: 'user id packet',
+ 14: 'public-subkey packet',
+ 17: 'user attribute packet',
+ 18: 'sym. encrypted and integrity protected data packet',
+ 19: 'modification detection code packet',
+ 60: 'private',
+ 61: 'private',
+ 62: 'private',
+ 63: 'private',
+ }
+
+ _public_key_algorithms = {
+ 1: 'rsa (encrypt or sign)',
+ 2: 'rsa encrypt-only',
+ 3: 'rsa sign-only',
+ 16: 'elgamal (encrypt-only)',
+ 17: 'dsa (digital signature algorithm)',
+ 18: 'reserved for elliptic curve',
+ 19: 'reserved for ecdsa',
+ 20: 'reserved (formerly elgamal encrypt or sign)',
+ 21: 'reserved for diffie-hellman',
+ 100: 'private',
+ 101: 'private',
+ 102: 'private',
+ 103: 'private',
+ 104: 'private',
+ 105: 'private',
+ 106: 'private',
+ 107: 'private',
+ 108: 'private',
+ 109: 'private',
+ 110: 'private',
+ }
+
+ _symmetric_key_algorithms = {
+ 0: 'plaintext or unencrypted data',
+ 1: 'idea',
+ 2: 'tripledes',
+ 3: 'cast5',
+ 4: 'blowfish',
+ 5: 'reserved',
+ 6: 'reserved',
+ 7: 'aes with 128-bit key',
+ 8: 'aes with 192-bit key',
+ 9: 'aes with 256-bit key',
+ 10: 'twofish',
+ 100: 'private',
+ 101: 'private',
+ 102: 'private',
+ 103: 'private',
+ 104: 'private',
+ 105: 'private',
+ 106: 'private',
+ 107: 'private',
+ 108: 'private',
+ 109: 'private',
+ 110: 'private',
+ }
+
+ _cipher_block_size = { # in bits
+ 'aes with 128-bit key': 128,
+ 'aes with 192-bit key': 128,
+ 'aes with 256-bit key': 128,
+ 'cast5': 64,
+ }
+
+ _crypto_module = {
+ 'aes with 128-bit key': _crypto_cipher_aes,
+ 'aes with 192-bit key': _crypto_cipher_aes,
+ 'aes with 256-bit key': _crypto_cipher_aes,
+ 'blowfish': _crypto_cipher_blowfish,
+ 'cast5': _crypto_cipher_cast,
+ 'tripledes': _crypto_cipher_des3,
+ }
+
+ _compression_algorithms = {
+ 0: 'uncompressed',
+ 1: 'zip',
+ 2: 'zlib',
+ 3: 'bzip2',
+ 100: 'private',
+ 101: 'private',
+ 102: 'private',
+ 103: 'private',
+ 104: 'private',
+ 105: 'private',
+ 106: 'private',
+ 107: 'private',
+ 108: 'private',
+ 109: 'private',
+ 110: 'private',
+ }
+
+ _hash_algorithms = {
+ 1: 'md5',
+ 2: 'sha-1',
+ 3: 'ripe-md/160',
+ 4: 'reserved',
+ 5: 'reserved',
+ 6: 'reserved',
+ 7: 'reserved',
+ 8: 'sha256',
+ 9: 'sha384',
+ 10: 'sha512',
+ 11: 'sha224',
+ 100: 'private',
+ 101: 'private',
+ 102: 'private',
+ 103: 'private',
+ 104: 'private',
+ 105: 'private',
+ 106: 'private',
+ 107: 'private',
+ 108: 'private',
+ 109: 'private',
+ 110: 'private',
+ }
+
+ _string_to_key_types = {
+ 0: 'simple',
+ 1: 'salted',
+ 2: 'reserved',
+ 3: 'iterated and salted',
+ 100: 'private',
+ 101: 'private',
+ 102: 'private',
+ 103: 'private',
+ 104: 'private',
+ 105: 'private',
+ 106: 'private',
+ 107: 'private',
+ 108: 'private',
+ 109: 'private',
+ 110: 'private',
+ }
+
+ _string_to_key_expbias = 6
+
+ _signature_types = {
+ 0x00: 'binary document',
+ 0x01: 'canonical text document',
+ 0x02: 'standalone',
+ 0x10: 'generic user id and public-key packet',
+ 0x11: 'persona user id and public-key packet',
+ 0x12: 'casual user id and public-key packet',
+ 0x13: 'postitive user id and public-key packet',
+ 0x18: 'subkey binding',
+ 0x19: 'primary key binding',
+ 0x1F: 'direct key',
+ 0x20: 'key revocation',
+ 0x28: 'subkey revocation',
+ 0x30: 'certification revocation',
+ 0x40: 'timestamp',
+ 0x50: 'third-party confirmation',
+ }
+
+ _signature_subpacket_types = {
+ 0: 'reserved',
+ 1: 'reserved',
+ 2: 'signature creation time',
+ 3: 'signature expiration time',
+ 4: 'exportable certification',
+ 5: 'trust signature',
+ 6: 'regular expression',
+ 7: 'revocable',
+ 8: 'reserved',
+ 9: 'key expiration time',
+ 10: 'placeholder for backward compatibility',
+ 11: 'preferred symmetric algorithms',
+ 12: 'revocation key',
+ 13: 'reserved',
+ 14: 'reserved',
+ 15: 'reserved',
+ 16: 'issuer',
+ 17: 'reserved',
+ 18: 'reserved',
+ 19: 'reserved',
+ 20: 'notation data',
+ 21: 'preferred hash algorithms',
+ 22: 'preferred compression algorithms',
+ 23: 'key server preferences',
+ 24: 'preferred key server',
+ 25: 'primary user id',
+ 26: 'policy uri',
+ 27: 'key flags',
+ 28: 'signer user id',
+ 29: 'reason for revocation',
+ 30: 'features',
+ 31: 'signature target',
+ 32: 'embedded signature',
+ 100: 'private',
+ 101: 'private',
+ 102: 'private',
+ 103: 'private',
+ 104: 'private',
+ 105: 'private',
+ 106: 'private',
+ 107: 'private',
+ 108: 'private',
+ 109: 'private',
+ 110: 'private',
+ }
+
+ _clean_type_regex = _re.compile('\W+')
+
+ def _clean_type(self, type=None):
+ if type is None:
+ type = self['type']
+ return self._clean_type_regex.sub('_', type)
+
+ @staticmethod
+ def _reverse(dict, value):
+ """Reverse lookups in dictionaries
+
+ >>> PGPPacket._reverse(PGPPacket._packet_types, 'public-key packet')
+ 6
+ """
+ return [k for k,v in dict.items() if v == value][0]
+
+ def __str__(self):
+ method_name = '_str_{}'.format(self._clean_type())
+ method = getattr(self, method_name, None)
+ if not method:
+ return self['type']
+ details = method()
+ return '{}: {}'.format(self['type'], details)
+
+ def _str_public_key_packet(self):
+ return self._str_generic_key_packet()
+
+ def _str_public_subkey_packet(self):
+ return self._str_generic_key_packet()
+
+ def _str_secret_key_packet(self):
+ return self._str_generic_key_packet()
+
+ def _str_secret_subkey_packet(self):
+ return self._str_generic_key_packet()
+
+ def _str_generic_key_packet(self):
+ return self['fingerprint'][-8:].upper()
+
+ def _str_signature_packet(self):
+ lines = [self['signature-type']]
+ if self['hashed-subpackets']:
+ lines.append(' hashed subpackets:')
+ lines.extend(self._str_signature_subpackets(
+ self['hashed-subpackets'], prefix=' '))
+ if self['unhashed-subpackets']:
+ lines.append(' unhashed subpackets:')
+ lines.extend(self._str_signature_subpackets(
+ self['unhashed-subpackets'], prefix=' '))
+ return '\n'.join(lines)
+
+ def _str_signature_subpackets(self, subpackets, prefix):
+ lines = []
+ for subpacket in subpackets:
+ method_name = '_str_{}_signature_subpacket'.format(
+ self._clean_type(type=subpacket['type']))
+ method = getattr(self, method_name, None)
+ if method:
+ lines.append(' {}: {}'.format(
+ subpacket['type'],
+ method(subpacket=subpacket)))
+ else:
+ lines.append(' {}'.format(subpacket['type']))
+ return lines
+
+ def _str_signature_creation_time_signature_subpacket(self, subpacket):
+ return str(subpacket['signature-creation-time'])
+
+ def _str_issuer_signature_subpacket(self, subpacket):
+ return subpacket['issuer'][-8:].upper()
+
+ def _str_key_expiration_time_signature_subpacket(self, subpacket):
+ return str(subpacket['key-expiration-time'])
+
+ def _str_preferred_symmetric_algorithms_signature_subpacket(
+ self, subpacket):
+ return ', '.join(
+ algo for algo in subpacket['preferred-symmetric-algorithms'])
+
+ def _str_preferred_hash_algorithms_signature_subpacket(
+ self, subpacket):
+ return ', '.join(
+ algo for algo in subpacket['preferred-hash-algorithms'])
+
+ def _str_preferred_compression_algorithms_signature_subpacket(
+ self, subpacket):
+ return ', '.join(
+ algo for algo in subpacket['preferred-compression-algorithms'])
+
+ def _str_key_server_preferences_signature_subpacket(self, subpacket):
+ return ', '.join(
+ x for x in sorted(subpacket['key-server-preferences']))
+
+ def _str_primary_user_id_signature_subpacket(self, subpacket):
+ return str(subpacket['primary-user-id'])
+
+ def _str_key_flags_signature_subpacket(self, subpacket):
+ return ', '.join(x for x in sorted(subpacket['key-flags']))
+
+ def _str_features_signature_subpacket(self, subpacket):
+ return ', '.join(x for x in sorted(subpacket['features']))
+
+ def _str_embedded_signature_signature_subpacket(self, subpacket):
+ return subpacket['embedded']['signature-type']
+
+ def _str_user_id_packet(self):
+ return self['user']
+