8 years agoPreserve public/secret distinction in _serialize_signature_packet_target master
W. Trevor King [Tue, 7 Jan 2014 17:48:38 +0000 (09:48 -0800)]
Preserve public/secret distinction in _serialize_signature_packet_target

When promoting subkey packets to key packets as signature targets,
keep secret keys secret and public keys public.  This avoids:

  ValueError: corrupted hash

warnings (and was mostly a lucky guess ;), as all RFC 4880 gives us is

  When a signature is made over a key, the hash data starts with the
  octet 0x99, followed by a two-octet length of the key, and then body
  of the key packet.  (Note that this is an old-style packet header
  for a key packet with two-octet length.)  A subkey binding signature
  (type 0x18) or primary key binding signature (type 0x19) then hashes
  the subkey using the same format as the main key (also using 0x99 as
  the first octet).

8 years agoAdd signature verification to PGPPacket and PGPKey
W. Trevor King [Tue, 7 Jan 2014 17:33:19 +0000 (09:33 -0800)]
Add signature verification to PGPPacket and PGPKey

From RFC 4880 [1]:

  With RSA signatures, the hash value is encoded using PKCS#1 encoding
  type EMSA-PKCS1-v1_5 as described in Section 9.2 of RFC 3447.  This
  requires inserting the hash value as an octet string into an ASN.1
  structure.  The object identifier for the type of hash being used is
  included in the structure.  The hexadecimal representations for the
  currently defined hash algorithms are as follows: ...

Rather than coding all these object identifiers in myself, I'm
piggybacking on PyCrypto [2,3,4] which already sets up
per-hash-algarithm OIDs.  However, older versions of PyCrypto attached
the OIDs to the PyCrypto-specific hash implementations, and we're
using hashlib's implementations.  Since 59018ff (Hash: Remove "oid"
attributes; add "name" attribute, 2013-02-17, released in PyCrypto
v2.7a1), PyCrypto has been able to handle hashlib hashes, so you'll
need a fairly modern installation to work with this script.


8 years agoAdd key-binding targets to PGPPacket._parse_signature_packet
W. Trevor King [Mon, 6 Jan 2014 06:03:57 +0000 (22:03 -0800)]
Add key-binding targets to PGPPacket._parse_signature_packet

Also adjust the 'user id and public-key packet' targets to always grab
the first packet in the list (public or private) instead of always
looking in the public packets.

This commit assumes that we're loading public packets first, and if a
key has any secret packets, then the current packet is a new secret

8 years agoAdd type and raw data to embedded signature subpackets
W. Trevor King [Mon, 23 Dec 2013 23:40:57 +0000 (15:40 -0800)]
Add type and raw data to embedded signature subpackets

Reduce the differences between embedded and regular signature packets.
Also add an 'embedded' key (set to True) for situations where we *do*
want to distinguish between embedded and regular packets.

8 years agoShift (sub)key -> public key coercion into _serialize_signature_packet_target
W. Trevor King [Mon, 23 Dec 2013 23:27:08 +0000 (15:27 -0800)]
Shift (sub)key -> public key coercion into _serialize_signature_packet_target

While RFC 4880 explicitly specifies that key fingerprints are
calculated only on the public part of the key packet, it was unclear
if signatures are also only calculated over the public part.  It turns
out that they are, so move the coercion logic from
PGPPacket._parse_generic_public_key_packet into

8 years agoSplit signature packet serialization out in PGPPacket
W. Trevor King [Mon, 23 Dec 2013 23:06:08 +0000 (15:06 -0800)]
Split signature packet serialization out in PGPPacket

We need the serialized hashed version for both signing and verifying,
so pull it's generation out of _serialize_signature_packet and put it
in _serialize_hashed_signature_packet and

8 years agoParse signature MPIs in PGPPacket._parse_signature_packet
W. Trevor King [Mon, 23 Dec 2013 23:01:12 +0000 (15:01 -0800)]
Parse signature MPIs in PGPPacket._parse_signature_packet

And serialize these MPIs in _serialize_signature_packet.  We need the
parsed integers to verify signatures.

8 years agoAdd PyCrypto modules for public-key encryption to PGPPacket._crypto_module
W. Trevor King [Mon, 23 Dec 2013 21:44:00 +0000 (13:44 -0800)]
Add PyCrypto modules for public-key encryption to PGPPacket._crypto_module

Maintained by Dwayne C. Litzenberger [1,2,3].  Also add comments to
the _crypto_module definition, because the symmetric-key and
public-key entries are in different alphebetization blocks.


8 years agoAdd PGPPacket._serialize_signature_packet
W. Trevor King [Mon, 23 Dec 2013 21:22:15 +0000 (13:22 -0800)]
Add PGPPacket._serialize_signature_packet

This is mostly an inverse of the current signature packet parsing
code, except that there's some new stuff in
_serialize_signature_packet_target for serializing signature targets.
PGP 4880 adds a bunch of extra logic, headers, trailers, etc. [1]:

  For binary document signatures (type 0x00), the document data is
  hashed directly.  For text document signatures (type 0x01), the
  document is canonicalized by converting line endings to <CR><LF>,
  and the resulting data is hashed.

  When a signature is made over a key, the hash data starts with the
  octet 0x99, followed by a two-octet length of the key, and then body
  of the key packet.  (Note that this is an old-style packet header
  for a key packet with two-octet length.)  A subkey binding signature
  (type 0x18) or primary key binding signature (type 0x19) then hashes
  the subkey using the same format as the main key (also using 0x99 as
  the first octet).  Key revocation signatures (types 0x20 and 0x28)
  hash only the key being revoked.

  A certification signature (type 0x10 through 0x13) hashes the User
  ID being bound to the key into the hash context after the above
  data.  A V3 certification hashes the contents of the User ID or
  attribute packet packet, without any header.  A V4 certification
  hashes the constant 0xB4 for User ID certifications or the constant
  0xD1 for User Attribute certifications, followed by a four-octet
  number giving the length of the User ID or User Attribute data, and
  then the User ID or User Attribute data.

  When a signature is made over a Signature packet (type 0x50), the
  hash data starts with the octet 0x88, followed by the four-octet
  length of the signature, and then the body of the Signature packet.
  (Note that this is an old-style packet header for a Signature packet
  with the length-of-length set to zero.)  The unhashed subpacket data
  of the Signature packet being hashed is not included in the hash,
  and the unhashed subpacket data length value is set to zero.

  Once the data body is hashed, then a trailer is hashed.  A V3
  signature hashes five octets of the packet body, starting from the
  signature type field.  This data is the signature type, followed by
  the four-octet signature time.  A V4 signature hashes the packet
  body starting from its first field, the version number, through the
  end of the hashed subpacket data.  Thus, the fields hashed are the
  signature version, the signature type, the public-key algorithm, the
  hash algorithm, the hashed subpacket length, and the hashed
  subpacket body.

  V4 signatures also hash in a final trailer of six octets: the
  version of the Signature packet, i.e., 0x04; 0xFF; and a four-octet,
  big-endian number that is the length of the hashed data from the
  Signature packet (note that this number does not include these final
  six octets).

  After all this has been hashed in a single hash context, the
  resulting hash field is used in the signature algorithm and placed
  at the end of the Signature packet.

We don't handle everything in there, but we do handle the key packet
headers (0x99, 2-byte length, packet body) and certification packets
(0x99, 2-byte key body length, key body, 0xb4, user id body).  We also
handle the v4 signature trailer (signature_version, 0xff, 4-byte
hashed signature packet length).


8 years agoCOPYING: Put this thing under the GPLv2
W. Trevor King [Mon, 23 Dec 2013 20:01:51 +0000 (12:01 -0800)]
COPYING: Put this thing under the GPLv2

8 years agoAdd PGPPacket.copy and pull out PGPPacket._serialize_body
W. Trevor King [Mon, 23 Dec 2013 19:55:56 +0000 (11:55 -0800)]
Add PGPPacket.copy and pull out PGPPacket._serialize_body

Use these with _serialize_signature_packet_target to compute key
fingerprints in _parse_generic_public_key_packet.  I'd previously been
hashing over the whole (sub)key packet, but RFC 4880 says the hash
should just be over the public-key part of the packet, even for secret
keys [1]:

  A V4 fingerprint is the 160-bit SHA-1 hash of the octet 0x99,
  followed by the two-octet packet length, followed by the entire
  Public-Key packet starting with the version field.

I've added the fingerprint_target stuff so I don't hash the
secret-key-specific fields.


8 years agoAdjust PGPKey._packets_from_bytes to append on the fly
W. Trevor King [Mon, 23 Dec 2013 16:58:21 +0000 (08:58 -0800)]
Adjust PGPKey._packets_from_bytes to append on the fly

With the list(iterator) approach, signature packets in the stream did
not have access to already-parsed packets for target extraction.  Now
they do.

8 years agoExtract signature packet targets
W. Trevor King [Mon, 23 Dec 2013 03:28:59 +0000 (19:28 -0800)]
Extract signature packet targets

We need to know what we're signing.  From RFC 4880 [1]:

  The concatenation of the data being signed and the signature data
  from the version number through the hashed subpacket data
  (inclusive) is hashed.  The resulting hash value is what is signed.

It's not always clear what the target bytes should be.  RFC 4880 is
clear for some types, and ambiguous for others.  For example, it's
clear that a standalone signature has no target [2]:

  0x02: Standalone signature.
    This signature is a signature of only its own subpacket contents.
    It is calculated identically to a signature over a zero-length
    binary document.

It is less clear how to serialize the targets for a
user-id-and-public-key signature [2]:

  0x10: Generic certification of a User ID and Public-Key packet.
    The issuer of this certification does not make any particular
    assertion as to how well the certifier has checked that the owner
    of the key is in fact the person described by the User ID.

There is a bit more guidance later on, showing that the key packet
should indeed come before the user id packet [3]:

  When a signature is made over a key, the hash data starts with the
  octet 0x99, followed by a two-octet length of the key, and then body
  of the key packet.  (Note that this is an old-style packet header
  for a key packet with two-octet length.)  A subkey binding signature
  (type 0x18) or primary key binding signature (type 0x19) then hashes
  the subkey using the same format as the main key (also using 0x99 as
  the first octet).  Key revocation signatures (types 0x20 and 0x28)
  hash only the key being revoked.

  A certification signature (type 0x10 through 0x13) hashes the User
  ID being bound to the key into the hash context after the above
  data.  A V3 certification hashes the contents of the User ID or
  attribute packet packet, without any header.  A V4 certification
  hashes the constant 0xB4 for User ID certifications or the constant
  0xD1 for User Attribute certifications, followed by a four-octet
  number giving the length of the User ID or User Attribute data, and
  then the User ID or User Attribute data.


  V4 signatures also hash in a final trailer of six octets: the
  version of the Signature packet, i.e., 0x04; 0xFF; and a four-octet,
  big-endian number that is the length of the hashed data from the
  Signature packet (note that this number does not include these final
  six octets).

  After all this has been hashed in a single hash context, the
  resulting hash field is used in the signature algorithm and placed
  at the end of the Signature packet.


8 years agoAdd PGPPacket._serialize_user_id_packet
W. Trevor King [Mon, 23 Dec 2013 00:31:19 +0000 (16:31 -0800)]
Add PGPPacket._serialize_user_id_packet

This is the inverse of _parse_user_id_packet.  See the
_parse_user_id_packet commit for references to RFC 4880.

8 years agoFactor byte-to-string conversion out into byte_string
W. Trevor King [Mon, 23 Dec 2013 00:27:11 +0000 (16:27 -0800)]
Factor byte-to-string conversion out into byte_string

No need to repeat this code everywhere we want to stringify some

8 years agoAdd a serialization check after parsing
W. Trevor King [Mon, 23 Dec 2013 00:23:47 +0000 (16:23 -0800)]
Add a serialization check after parsing

Ensure that we can serialize everything we parse, using the input data
as a check against our output.

8 years agoParse algorithm-specific data in _parse_generic_secret_key_packet
W. Trevor King [Sun, 22 Dec 2013 22:14:03 +0000 (14:14 -0800)]
Parse algorithm-specific data in _parse_generic_secret_key_packet

From RFC 4880 [1]:

  Algorithm-Specific Fields for RSA secret keys:

  - multiprecision integer (MPI) of RSA secret exponent d.
  - MPI of RSA secret prime value p.
  - MPI of RSA secret prime value q (p < q).
  - MPI of u, the multiplicative inverse of p, mod q.

  Algorithm-Specific Fields for DSA secret keys:

  - MPI of DSA secret exponent x.

  Algorithm-Specific Fields for Elgamal secret keys:

  - MPI of Elgamal secret exponent x.

We'll need these if we want to sign new subkey bindings.


8 years agoAdd optional PGPKey-wide passphrase caching
W. Trevor King [Sun, 22 Dec 2013 22:04:22 +0000 (14:04 -0800)]
Add optional PGPKey-wide passphrase caching

Entering your passphrase for each secret key packet is annoying.  The
cache_passphrase option lets you cache that passphrase once, and reuse
it for every secret key PGPPacket in the key.

8 years agoAdd PGPPacket.key pointing back up to the PGPKey
W. Trevor King [Sun, 22 Dec 2013 22:02:11 +0000 (14:02 -0800)]
Add PGPPacket.key pointing back up to the PGPKey

This allows us to do stuff like caching passphrases on a key-wide
level, instead of asking for the passphrase for each packet.  The
actuall caching commit is coming next, this commit just lands the

8 years agoMake packets_from_bytes a PGPKey method
W. Trevor King [Sun, 22 Dec 2013 22:00:47 +0000 (14:00 -0800)]
Make packets_from_bytes a PGPKey method

There's no need to leave this a stand-alone function if it's only used
from PGPKey.

8 years agoAdd twofish block size to PGPPacket._cipher_block_size
W. Trevor King [Sun, 22 Dec 2013 19:49:30 +0000 (11:49 -0800)]
Add twofish block size to PGPPacket._cipher_block_size

From RFC 4880 [1]:

  The AES and Twofish have a block size of 16 octets.


8 years agoAdd iterated-and-salted string-to-key support to PGPPacket._string_to_key
W. Trevor King [Sun, 22 Dec 2013 00:43:35 +0000 (16:43 -0800)]
Add iterated-and-salted string-to-key support to PGPPacket._string_to_key

From RFC 4880 [1]:

  Iterated-Salted S2K hashes the passphrase and salt data multiple
  times.  The total number of octets to be hashed is specified in the
  encoded count in the S2K specifier.  Note that the resulting count
  value is an octet count of how many octets will be hashed, not an
  iteration count.

  Initially, one or more hash contexts are set up as with the other
  S2K algorithms, depending on how many octets of key data are needed.
  Then the salt, followed by the passphrase data, is repeatedly hashed
  until the number of octets specified by the octet count has been
  hashed.  The one exception is that if the octet count is less than
  the size of the salt plus passphrase, the full salt plus passphrase
  will be hashed even though that is greater than the octet count.
  After the hashing is done, the data is unloaded from the hash
  context(s) as with the other S2K algorithms.


8 years agoAdd symmetric encryption information to stringified secret key
W. Trevor King [Sat, 21 Dec 2013 19:54:32 +0000 (11:54 -0800)]
Add symmetric encryption information to stringified secret key

You can compare this output with 'gpg --list-packets' for sanity.

8 years agoAdd salted string-to-key support to PGPPacket._string_to_key
W. Trevor King [Sat, 21 Dec 2013 18:30:44 +0000 (10:30 -0800)]
Add salted string-to-key support to PGPPacket._string_to_key

From RFC 4880 [1]:

  Salted S2K is exactly like Simple S2K, except that the input to the
  hash function(s) consists of the 8 octets of salt from the S2K
  specifier, followed by the passphrase.


8 years agoAdd PGPPacket._string_to_key for calculating decryption keys
W. Trevor King [Sat, 21 Dec 2013 18:25:31 +0000 (10:25 -0800)]
Add PGPPacket._string_to_key for calculating decryption keys

So far we only implement the 'simple' string-to-key type.  From RFC
4880 [1]:

  Simple S2K hashes the passphrase to produce the session key.  The
  manner in which this is done depends on the size of the session key
  (which will depend on the cipher used) and the size of the hash
  algorithm's output.  If the hash size is greater than the session
  key size, the high-order (leftmost) octets of the hash are used as
  the key.

  If the hash size is less than the key size, multiple instances of
  the hash context are created -- enough to produce the required key
  data.  These instances are preloaded with 0, 1, 2, ... octets of
  zeros (that is to say, the first instance has no preloading, the
  second gets preloaded with 1 octet of zero, the third is preloaded
  with two octets of zeros, and so forth).

  As the data is hashed, it is given independently to each hash
  context.  Since the contexts have been initialized differently, they
  will each produce different hash output.  Once the passphrase is
  hashed, the output data from the multiple hashes is concatenated,
  first hash leftmost, to produce the key data, with any excess octets
  on the right discarded.


8 years agoAdd hashlib hash names to PGPPacket._hashlib_name
W. Trevor King [Sat, 21 Dec 2013 18:14:54 +0000 (10:14 -0800)]
Add hashlib hash names to PGPPacket._hashlib_name

The string-to-key algorithm is going to use hashlib for hashing, so
map the OpenPGP-based names to hashlib names for easy lookup.

8 years agoAdd cast5 key size (128 bits) to PGPPacket._key_size
W. Trevor King [Sat, 21 Dec 2013 18:11:53 +0000 (10:11 -0800)]
Add cast5 key size (128 bits) to PGPPacket._key_size

From RFC 4880 [1]

  CAST5 (128 bit key, as per [RFC2144])

From RFC 2144 [2]:

  The CAST-128 encryption algorithm has been designed to allow a key
  size that can vary from 40 bits to 128 bits, in 8-bit increments
  (that is, the allowable key sizes are 40, 48, 56, 64, ..., 112, 120,
  and 128 bits.


8 years agoStub out a PGPPacket._key_size dictionary
W. Trevor King [Sat, 21 Dec 2013 18:10:00 +0000 (10:10 -0800)]
Stub out a PGPPacket._key_size dictionary

The string-to-key algorithm needs to know the key size, so record an
algorithm's key size (in bits) for easy lookup.  The AES key sizes
seem pretty obvious ;).

8 years agoDecode the string-to-key count for iterated and salted S2Ks
W. Trevor King [Sat, 21 Dec 2013 17:45:23 +0000 (09:45 -0800)]
Decode the string-to-key count for iterated and salted S2Ks

We need this for decryption.  From RFC 4880 [1]:

  The count is coded into a one-octet number using the following

      #define EXPBIAS 6
          count = ((Int32)16 + (c & 15)) << ((c >> 4) + EXPBIAS);

  The above formula is in C, where "Int32" is a type for a 32-bit
  integer, and the variable "c" is the coded count, Octet 10.


8 years agoUse PyCrypto for decrypting symmetric encryption
W. Trevor King [Sat, 21 Dec 2013 17:06:40 +0000 (09:06 -0800)]
Use PyCrypto for decrypting symmetric encryption

Maintained by Dwayne C. Litzenberger [1,2,3].  Although there is a
MODE_OPENGP in PyCrypto since v2.6 [4], it seems like v4 secret key
bodies are actually encrypted using plain-vanilla MODE_CFB.


8 years agoAdd secret-key decryption to _parse_generic_secret_key_packet
W. Trevor King [Sat, 21 Dec 2013 05:19:59 +0000 (21:19 -0800)]
Add secret-key decryption to _parse_generic_secret_key_packet

The checksum checks will fail with encrypted algorithm-specific key
data.  This adds handling to decrypt the encrypted section with a new
PGPPacket.decrypt_symmetric_encryption stub that still needs to be
filled in.  From RFC 4880 [1]:

   With V4 keys, a simpler method is used.  All secret MPI values are
   encrypted in CFB mode, including the MPI bitcount prefix.

   The two-octet checksum that follows the algorithm-specific portion
   is the algebraic sum, mod 65536, of the plaintext of all the
   algorithm- specific octets (including MPI prefix and data).  With
   V3 keys, the checksum is stored in the clear.  With V4 keys, the
   checksum is encrypted like the algorithm-specific data.


8 years agoCheck the SHA-1 checksum in PGPPacket._parse_generic_secret_key_packet
W. Trevor King [Sat, 21 Dec 2013 03:07:30 +0000 (19:07 -0800)]
Check the SHA-1 checksum in PGPPacket._parse_generic_secret_key_packet

The previous commit added checks when the string-to-key usage was zero
or 255, but I'd forgotten about the case where the string-to-key usage
was 254.  This commit add handling for that case, where a SHA-1 digest
is used instead of the mod-65536 sum.  See the previous commit message
for RFC 4880 references.

8 years agoCheck the secret key checksum in PGPPacket._parse_generic_secret_key_packet
W. Trevor King [Sat, 21 Dec 2013 02:34:41 +0000 (18:34 -0800)]
Check the secret key checksum in PGPPacket._parse_generic_secret_key_packet

From RFC 4880 [1]:

  - If the string-to-key usage octet is zero or 255, then a two-octet
    checksum of the plaintext of the algorithm-specific portion (sum
    of all octets, mod 65536).  If the string-to-key usage octet was
    254, then a 20-octet SHA-1 hash of the plaintext of the
    algorithm-specific portion.  This checksum or hash is encrypted
    together with the algorithm-specific fields (if string-to-key
    usage octet is not zero).  Note that for all other values, a
    two-octet checksum is required.

[1]: section 5.5.3

8 years agoAdd PGPPacket._serialize_generic_public_key_packet
W. Trevor King [Sat, 21 Dec 2013 02:22:24 +0000 (18:22 -0800)]
Add PGPPacket._serialize_generic_public_key_packet

This is the inverse of _parse_generic_public_key_packet.  See the
_parse_generic_public_key_packet commit for references to RFC 4880.

8 years agoAdd PGPPacket._serialize_string_to_key_specifier
W. Trevor King [Sat, 21 Dec 2013 02:12:12 +0000 (18:12 -0800)]
Add PGPPacket._serialize_string_to_key_specifier

This is the inverse of _parse_string_to_key_specifier.  See the
_parse_string_to_key_specifier commits for references to RFC 4880.

8 years agoAdd PGPPacket._serialize_multiprecision_integer
W. Trevor King [Sat, 21 Dec 2013 02:01:27 +0000 (18:01 -0800)]
Add PGPPacket._serialize_multiprecision_integer

This is the inverse of _parse_multiprecision_integer.  See the
_parse_multiprecision_integer commit for references to RFC 4880.

8 years agoStub out PGPPacket.to_bytes with header serialization
W. Trevor King [Sat, 21 Dec 2013 01:44:00 +0000 (17:44 -0800)]
Stub out PGPPacket.to_bytes with header serialization

Also setup a body serialization framework along the lines of the
existing packet-parsing framework in PGPPacket.from_bytes.

The header serialization in _serialize_header is just the inverse of
the parsing in _parse_header.  See the _parse_header commit for
references to RFC 4880.

8 years agoAdd PGPPacket._reverse for inverse dictionary lookup
W. Trevor King [Sat, 21 Dec 2013 00:56:03 +0000 (16:56 -0800)]
Add PGPPacket._reverse for inverse dictionary lookup

Mapping human-readable values to their binary counterparts for

8 years agoCheck that the first secret-key packet is a 'secret-key packet'
W. Trevor King [Sat, 21 Dec 2013 00:07:00 +0000 (16:07 -0800)]
Check that the first secret-key packet is a 'secret-key packet'

From RFC 4880 [1]:

  The format of a transferable secret key is the same as a
  transferable public key except that secret-key and secret-subkey
  packets are used instead of the public key and public-subkey


8 years agoDescribe packet stream ordering in PGPKey.__doc__
W. Trevor King [Fri, 20 Dec 2013 23:31:29 +0000 (15:31 -0800)]
Describe packet stream ordering in PGPKey.__doc__

Using quotes from RFC 4880, as noted in the docstring itself.

8 years agoAdd key expiration time subpacket parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 23:05:11 +0000 (15:05 -0800)]
Add key expiration time subpacket parsing to PGPPacket

From RFC 4880 [1]:

  (4-octet time field)

  The validity period of the key.  This is the number of seconds after
  the key creation time that the key expires.  If this is not present
  or has a value of zero, the key never expires.  This is found only
  on a self-signature.


8 years agoAdd signature creation time signature subpacket parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 23:02:08 +0000 (15:02 -0800)]
Add signature creation time signature subpacket parsing to PGPPacket

From RFC 4880 [1]:

  (4-octet time field)

  The time the signature was made.

  MUST be present in the hashed area.


8 years agoAdd primary user id signature subpacket parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 22:58:20 +0000 (14:58 -0800)]
Add primary user id signature subpacket parsing to PGPPacket

From RFC 4880 [1]:

  (1 octet, Boolean)

  This is a flag in a User ID's self-signature that states whether
  this User ID is the main User ID for this key.  It is reasonable for
  an implementation to resolve ambiguities in preferences, etc. by
  referring to the primary User ID.  If this flag is absent, its value
  is zero.  If more than one User ID in a key is marked as primary,
  the implementation may resolve the ambiguity in any way it sees fit,
  but it is RECOMMENDED that priority be given to the User ID with the
  most recent self-signature.

  When appearing on a self-signature on a User ID packet, this
  subpacket applies only to User ID packets.  When appearing on a
  self-signature on a User Attribute packet, this subpacket applies
  only to User Attribute packets.  That is to say, there are two
  different and independent "primaries" -- one for User IDs, and one
  for User Attributes.


8 years agoAdd key server preferences signature subpacket parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 22:52:57 +0000 (14:52 -0800)]
Add key server preferences signature subpacket parsing to PGPPacket

From RFC 4880 [1]:

  (N octets of flags)

  This is a list of one-bit flags that indicate preferences that the
  key holder has about how the key is handled on a key server.  All
  undefined flags MUST be zero.

  First octet: 0x80 = No-modify
    the key holder requests that this key only be modified or updated
    by the key holder or an administrator of the key server.

  This is found only on a self-signature.


8 years agoAdd features signature subpacket parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 22:10:21 +0000 (14:10 -0800)]
Add features signature subpacket parsing to PGPPacket

From RFC 4880 [1]:

 (N octets of flags)

 The Features subpacket denotes which advanced OpenPGP features a
 user's implementation supports.  This is so that as features are
 added to OpenPGP that cannot be backwards-compatible, a user can
 state that they can use that feature.  The flags are single bits that
 indicate that a given feature is supported.

 This subpacket is similar to a preferences subpacket, and only
 appears in a self-signature.

 An implementation SHOULD NOT use a feature listed when sending to a
 user who does not state that they can use it.

 Defined features are as follows:

   First octet:

   0x01 - Modification Detection (packets 18 and 19)


8 years agoAdd preferred compression algorithm signature subpacket parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 22:05:22 +0000 (14:05 -0800)]
Add preferred compression algorithm signature subpacket parsing to PGPPacket

From RFC 4880 [1]:

  (array of one-octet values)

  Compression algorithm numbers that indicate which algorithms the key
  holder prefers to use.  Like the preferred symmetric algorithms, the
  list is ordered.  Algorithm numbers are in Section 9.  If this
  subpacket is not included, ZIP is preferred.  A zero denotes that
  uncompressed data is preferred; the key holder's software might have
  no compression software in that implementation.  This is only found
  on a self-signature.


8 years agoAdd preferred hash algorithm signature subpacket parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 22:02:51 +0000 (14:02 -0800)]
Add preferred hash algorithm signature subpacket parsing to PGPPacket

From RFC 4880 [1]:

  (array of one-octet values)

  Message digest algorithm numbers that indicate which algorithms the
  key holder prefers to receive.  Like the preferred symmetric
  algorithms, the list is ordered.  Algorithm numbers are in Section
  9.  This is only found on a self-signature.


8 years agoAdd preferred symmetric algorithm signature subpacket parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 21:59:57 +0000 (13:59 -0800)]
Add preferred symmetric algorithm signature subpacket parsing to PGPPacket

From RFC 4880 [1]:

  (array of one-octet values)

  Symmetric algorithm numbers that indicate which algorithms the key
  holder prefers to use.  The subpacket body is an ordered list of
  octets with the most preferred listed first.  It is assumed that
  only algorithms listed are supported by the recipient's software.
  Algorithm numbers are in Section 9.  This is only found on a self-


8 years agoAdd key flags signature subpacket parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 21:52:10 +0000 (13:52 -0800)]
Add key flags signature subpacket parsing to PGPPacket

From RFC 4880 [1]:

  (N octets of flags)

  This subpacket contains a list of binary flags that hold information
  about a key.  It is a string of octets, and an implementation MUST
  NOT assume a fixed size.  This is so it can grow over time.  If a
  list is shorter than an implementation expects, the unstated flags
  are considered to be zero.  The defined flags are as follows:

    First octet:

    0x01 - This key may be used to certify other keys.
    0x02 - This key may be used to sign data.
    0x04 - This key may be used to encrypt communications.
    0x08 - This key may be used to encrypt storage.
    0x10 - The private component of this key may have been split by a
           secret-sharing mechanism.
    0x20 - This key may be used for authentication.
    0x80 - The private component of this key may be in the possession
           of more than one person.


8 years agoParse and print the hashed signature subpackets too
W. Trevor King [Fri, 20 Dec 2013 21:44:39 +0000 (13:44 -0800)]
Parse and print the hashed signature subpackets too

These packets aren't encrypted, just hashed (i.e. signed).

8 years agoAdd embedded signature subpacket parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 21:34:42 +0000 (13:34 -0800)]
Add embedded signature subpacket parsing to PGPPacket

From RFC 4880 [1]:

  (1 signature packet body)

  This subpacket contains a complete Signature packet body as
  specified in Section 5.2 above.  It is useful when one signature
  needs to refer to, or be incorporated in, another signature.


8 years agoAdd issuer signature subpacket parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 21:27:57 +0000 (13:27 -0800)]
Add issuer signature subpacket parsing to PGPPacket

From RFC 4880 [1]:

  (8-octet Key ID)

  The OpenPGP Key ID of the key issuing the signature.


8 years agoAdd a signature subpacket parsing/display framework to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 21:26:48 +0000 (13:26 -0800)]
Add a signature subpacket parsing/display framework to PGPPacket

Along the lines of the existing packet-parsing framework in

8 years agoAllow explicit types in PGPPacket._clean_type
W. Trevor King [Fri, 20 Dec 2013 21:13:19 +0000 (13:13 -0800)]
Allow explicit types in PGPPacket._clean_type

This will let me use it to clean the signature subpacket type for
parsing signature subpackets.

8 years agoStub out signature subpacket parsing in PGPPacket
W. Trevor King [Fri, 20 Dec 2013 21:09:25 +0000 (13:09 -0800)]
Stub out signature subpacket parsing in PGPPacket

From RFC 4880 [1]:

   Each subpacket consists of a subpacket header and a body.  The
   header consists of:

     - the subpacket length (1, 2, or 5 octets),
     - the subpacket type (1 octet),

   and is followed by the subpacket-specific data.

   The length includes the type octet but not this length.  Its format
   is similar to the "new" format packet header lengths, but cannot
   have Partial Body Lengths.  That is:

       if the 1st octet <  192, then
           lengthOfLength = 1
           subpacketLen = 1st_octet

       if the 1st octet >= 192 and < 255, then
           lengthOfLength = 2
           subpacketLen = ((1st_octet - 192) << 8) + (2nd_octet) + 192

       if the 1st octet = 255, then
           lengthOfLength = 5
           subpacket length = [four-octet scalar starting at 2nd_octet]

   The value of the subpacket type octet may be:

            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's User ID
           29 = Reason for Revocation
           30 = Features
           31 = Signature Target
           32 = Embedded Signature
   100 To 110 = Private or experimental


8 years agoAdd PGPPacket._str_signature_packet
W. Trevor King [Fri, 20 Dec 2013 20:19:38 +0000 (12:19 -0800)]
Add PGPPacket._str_signature_packet

This is not super useful without parsing the subpackets, but you can
usually figure out what's being bound using the context:

  $ ./ F15F5BE8 6D024CA2
  key: F15F5BE8
      public-key packet: F15F5BE8
      user id packet: William Trevor King <>
      signature packet: postitive user id and public-key packet
      signature packet: postitive user id and public-key packet
      user id packet: William Trevor King <>
      signature packet: postitive user id and public-key packet
      signature packet: postitive user id and public-key packet
      signature packet: postitive user id and public-key packet
      signature packet: generic user id and public-key packet
      signature packet: postitive user id and public-key packet
      public-subkey packet: 42407C74
      signature packet: subkey binding

The user id signatures are likely between the previous user id and
F15F5BE8, with positive self-signed signatures and generic signatures
from other folks.  The subkey binding is likely between F15F5BE8 and
42407C74.  Adding subpacket parsing to make this explicit would be
nice, but it's not a priority at the moment.

8 years agoAdd PGPPacket._str_generic_key_packet and fingerprint calculation
W. Trevor King [Fri, 20 Dec 2013 19:54:13 +0000 (11:54 -0800)]
Add PGPPacket._str_generic_key_packet and fingerprint calculation

From RFC 4880 [1]:

  A V4 fingerprint is the 160-bit SHA-1 hash of the octet 0x99,
  followed by the two-octet packet length, followed by the entire
  Public-Key packet starting with the version field.  The Key ID is
  the low-order 64 bits of the fingerprint.

Since all key types (public/private and primary/subkey) have the same
generic public key portion, we can use the same stringification method
for all types.


8 years agoAdd PGPKey with a basic key-level API
W. Trevor King [Fri, 20 Dec 2013 19:43:21 +0000 (11:43 -0800)]
Add PGPKey with a basic key-level API

This currently handles importing keys from GnuPG and stubs out a
key-stringification framework along the lines of the existing
packet-parsing framework in PGPPacket.from_bytes.

8 years agoAdd user id parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 19:28:42 +0000 (11:28 -0800)]
Add user id parsing to PGPPacket

From RFC 4880 [1]:

  A User ID packet consists of UTF-8 text that is intended to
  represent the name and email address of the key holder.  By
  convention, it includes an RFC 2822 [RFC2822] mail name-addr, but
  there are no restrictions on its content.  The packet length in the
  header specifies the length of the User ID.


8 years agoAdd version-4-signature parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 19:17:09 +0000 (11:17 -0800)]
Add version-4-signature parsing to PGPPacket

From RFC 4880 [1]:

  The body of a version 4 Signature packet contains:

  - One-octet version number (4).
  - One-octet signature type.
  - One-octet public-key algorithm.
  - One-octet hash algorithm.
  - Two-octet scalar octet count for following hashed subpacket data.
    Note that this is the length in octets of all of the hashed
    subpackets; a pointer incremented by this number will skip over
    the hashed subpackets.
  - Hashed subpacket data set (zero or more subpackets).
  - Two-octet scalar octet count for the following unhashed subpacket
    data.  Note that this is the length in octets of all of the
    unhashed subpackets; a pointer incremented by this number will
    skip over the unhashed subpackets.
  - Unhashed subpacket data set (zero or more subpackets).
  - Two-octet field holding the left 16 bits of the signed hash value.
  - One or more multiprecision integers comprising the signature.
    This portion is algorithm specific, as described above.

I've stashed all of the algorithm-specific MPI values in the
'signature' field, because I don't care about verifying signatures at
the moment.


8 years agoAdd PGPPacket._signature_types
W. Trevor King [Fri, 20 Dec 2013 19:06:44 +0000 (11:06 -0800)]
Add PGPPacket._signature_types

From RFC 4880 [1]:

  There are a number of possible meanings for a signature, which are
  indicated in a signature type octet in any given signature.  Please
  note that the vagueness of these meanings is not a flaw, but a
  feature of the system.  Because OpenPGP places final authority for
  validity upon the receiver of a signature, it may be that one
  signer's casual act might be more rigorous than some other
  authority's positive act.  See Section 5.2.4, "Computing
  Signatures", for detailed information on how to compute and verify
  signatures of each type.

  These meanings are as follows:

  0x00: Signature of a binary document.
    This means the signer owns it, created it, or certifies that it
    has not been modified.

  0x01: Signature of a canonical text document.
    This means the signer owns it, created it, or certifies that it
    has not been modified.  The signature is calculated over the text
    data with its line endings converted to <CR><LF>.

  0x02: Standalone signature.
    This signature is a signature of only its own subpacket contents.
    It is calculated identically to a signature over a zero-length
    binary document.  Note that it doesn't make sense to have a V3
    standalone signature.

  0x10: Generic certification of a User ID and Public-Key packet.
    The issuer of this certification does not make any particular
    assertion as to how well the certifier has checked that the owner
    of the key is in fact the person described by the User ID.

  0x11: Persona certification of a User ID and Public-Key packet.
    The issuer of this certification has not done any verification of
    the claim that the owner of this key is the User ID specified.

  0x12: Casual certification of a User ID and Public-Key packet.
    The issuer of this certification has done some casual verification
    of the claim of identity.

  0x13: Positive certification of a User ID and Public-Key packet.
    The issuer of this certification has done substantial verification
    of the claim of identity.

    Most OpenPGP implementations make their "key signatures" as 0x10
    certifications.  Some implementations can issue 0x11-0x13
    certifications, but few differentiate between the types.

  0x18: Subkey Binding Signature
    This signature is a statement by the top-level signing key that
    indicates that it owns the subkey.  This signature is calculated
    directly on the primary key and subkey, and not on any User ID or
    other packets.  A signature that binds a signing subkey MUST have
    an Embedded Signature subpacket in this binding signature that
    contains a 0x19 signature made by the signing subkey on the
    primary key and subkey.

  0x19: Primary Key Binding Signature
    This signature is a statement by a signing subkey, indicating that
    it is owned by the primary key [2].  This signature is calculated
    the same way as a 0x18 signature: directly on the primary key and
    subkey, and not on any User ID or other packets.

  0x1F: Signature directly on a key
    This signature is calculated directly on a key.  It binds the
    information in the Signature subpackets to the key, and is
    appropriate to be used for subpackets that provide information
    about the key, such as the Revocation Key subpacket.  It is also
    appropriate for statements that non-self certifiers want to make
    about the key itself, rather than the binding between a key and a

  0x20: Key revocation signature
    The signature is calculated directly on the key being revoked.  A
    revoked key is not to be used.  Only revocation signatures by the
    key being revoked, or by an authorized revocation key, should be
    considered valid revocation signatures.

  0x28: Subkey revocation signature
    The signature is calculated directly on the subkey being revoked.
    A revoked subkey is not to be used.  Only revocation signatures by
    the top-level signature key that is bound to this subkey, or by an
    authorized revocation key, should be considered valid revocation

  0x30: Certification revocation signature
    This signature revokes an earlier User ID certification signature
    (signature class 0x10 through 0x13) or direct-key signature
    (0x1F).  It should be issued by the same key that issued the
    revoked signature or an authorized revocation key.  The signature
    is computed over the same data as the certificate that it revokes,
    and should have a later creation date than that certificate.

  0x40: Timestamp signature.
    This signature is only meaningful for the timestamp contained in

  0x50: Third-Party Confirmation signature.
    This signature is a signature over some other OpenPGP Signature
    packet(s).  It is analogous to a notary seal on the signed data.
    A third-party signature SHOULD include Signature Target
    subpacket(s) to give easy identification.  Note that we really do
    mean SHOULD.  There are plausible uses for this (such as a blind
    party that only sees the signature, not the key or source
    document) that cannot include a target subpacket.

     Errata ID: 2208
     Reported By: Constantin Hagemeier
     Date Reported: 2010-04-28
     Held for Document Update by: Sean Turner
     Date Held: 2010-07-20

     Section 5.2.1. says:

       This signature is a statement by a signing subkey, indicating
       that it is owned by the primary key and subkey.

     It should say:

       This signature is a statement by a signing subkey, indicating
       that it is owned by the primary key.


       The subkey does not own itself.

8 years agoStub out PGPPacket._parse_signature_packet
W. Trevor King [Fri, 20 Dec 2013 18:58:13 +0000 (10:58 -0800)]
Stub out PGPPacket._parse_signature_packet

The first octet of each signature packet is it's version number.  That
means we can parse the first octet of the signature packet and use its
value to determine which version we're parsing.  From RFC 4880 [1]:

  The body of a version 3 Signature Packet contains:

  - One-octet version number (3).
  - ...

And in the next section [2]:

  The body of a version 4 Signature Packet contains:

  - One-octet version number (4).
  - ...


8 years agoAdd CAST5 block size to PGPPacket._cipher_block_size
W. Trevor King [Fri, 20 Dec 2013 18:49:01 +0000 (10:49 -0800)]
Add CAST5 block size to PGPPacket._cipher_block_size

From RFC 4880 [1]:

  CAST5 (128 bit key, as per [RFC2144])

From RFC 2144 [2]:

  CAST-128 is a 12- or 16-round Feistel cipher that has a blocksize of
  64 bits and a keysize of up to 128 bits...


8 years agoAdd AES block sizes to PGPPacket._cipher_block_size
W. Trevor King [Fri, 20 Dec 2013 18:45:47 +0000 (10:45 -0800)]
Add AES block sizes to PGPPacket._cipher_block_size

From the AES spec [1]:

  This standard specifies the Rijndael algorithm (...), a symmetric
  block cipher that can process data blocks of 128 bits, using cipher
  keys with lengths of 128, 192, and 256 bits.


8 years agoAdd secret key parsing to PGPPacket
W. Trevor King [Fri, 20 Dec 2013 18:25:59 +0000 (10:25 -0800)]
Add secret key parsing to PGPPacket

Use the same parser for public-key and public-subkey packets.  From
RFC 4880 [1]:

  A Secret-Subkey packet (tag 7) is the subkey analog of the Secret
  Key packet and has exactly the same format.

The generic (sub)key parsing is specified in section 5.5.3 [2]:

  The Secret-Key and Secret-Subkey packets contain all the data of the
  Public-Key and Public-Subkey packets, with additional algorithm-
  specific secret-key data appended, usually in encrypted form.

  The packet contains:

  - A Public-Key or Public-Subkey packet, as described above.
  - One octet indicating string-to-key usage conventions.  Zero
    indicates that the secret-key data is not encrypted.  255 or 254
    indicates that a string-to-key specifier is being given.  Any
    other value is a symmetric-key encryption algorithm identifier.
  - [Optional] If string-to-key usage octet was 255 or 254, a one-
    octet symmetric encryption algorithm.
  - [Optional] If string-to-key usage octet was 255 or 254, a
    string-to-key specifier.  The length of the string-to-key
    specifier is implied by its type, as described above.
  - [Optional] If secret data is encrypted (string-to-key usage octet
    not zero), an Initial Vector (IV) of the same length as the
    cipher's block size.
  - Plain or encrypted multiprecision integers comprising the secret
    key data.  These algorithm-specific fields are as described below.
  - If the string-to-key usage octet is zero or 255, then a two-octet
    checksum of the plaintext of the algorithm-specific portion (sum
    of all octets, mod 65536).  If the string-to-key usage octet was
    254, then a 20-octet SHA-1 hash of the plaintext of the
    algorithm-specific portion.  This checksum or hash is encrypted
    together with the algorithm-specific fields (if string-to-key
    usage octet is not zero).  Note that for all other values, a
    two-octet checksum is required.

RFC 4880 claims to list block sizes (needed for the IV length) [3]:

  OpenPGP specifies a number of symmetric-key algorithms.  This
  specification creates a registry of symmetric-key algorithm
  identifiers.  The registry includes the algorithm name, its key
  sizes and block size, and a reference to the defining specification.
  The initial values for this registry can be found in Section 9.

But in section 9.2 [4], they just list key size.  It looks like the
block size is usually equal to the key size, but not always.  From
section one of the AES spec [5]:

  This standard specifies the Rijndael algorithm (...), a symmetric
  block cipher that can process data blocks of 128 bits, using cipher
  keys with lengths of 128, 192, and 256 bits.

So it looks like the block size for each cipher needs research beyond
RFC 4880.


8 years agoAdd iterated and salted S2K parsing to _parse_string_to_key_specifier
W. Trevor King [Fri, 20 Dec 2013 18:09:23 +0000 (10:09 -0800)]
Add iterated and salted S2K parsing to _parse_string_to_key_specifier

From RFC 4880 [1]:

   Octet  0:        0x03
   Octet  1:        hash algorithm
   Octets 2-9:      8-octet salt value
   Octet  10:       count, a one-octet, coded value


8 years agoAdd salted S2K parsing to PGPPacket._parse_string_to_key_specifier
W. Trevor King [Fri, 20 Dec 2013 18:02:41 +0000 (10:02 -0800)]
Add salted S2K parsing to PGPPacket._parse_string_to_key_specifier

From RFC 4880 [1]:

   Octet  0:        0x01
   Octet  1:        hash algorithm
   Octets 2-9:      8-octet salt value


8 years agoAdd simple S2K parsing to PGPPacket._parse_string_to_key_specifier
W. Trevor King [Fri, 20 Dec 2013 17:59:58 +0000 (09:59 -0800)]
Add simple S2K parsing to PGPPacket._parse_string_to_key_specifier

From RFC 4880 [1]:

   Octet 0:        0x00
   Octet 1:        hash algorithm


8 years agoStub out PGPPacket._parse_string_to_key_specifier
W. Trevor King [Fri, 20 Dec 2013 17:55:53 +0000 (09:55 -0800)]
Stub out PGPPacket._parse_string_to_key_specifier

From RFC 4880 [1]:

       ID          S2K Type
       --          --------
       0           Simple S2K
       1           Salted S2K
       2           Reserved value
       3           Iterated and Salted S2K
       100 to 110  Private/Experimental S2K

In the following sections ( -, the first octet of each
specifier is it's type (simple starts with 0x00, salted starts with
0x01, and iterated and salted starts with 0x03).  That means we can
parse the first octet of the S2K specifier and use its value to
determine which type of specifier we're parsing.


8 years agoParse algorithm-specific data in _parse_generic_public_key_packet
W. Trevor King [Fri, 20 Dec 2013 17:26:47 +0000 (09:26 -0800)]
Parse algorithm-specific data in _parse_generic_public_key_packet

From RFC 4880 [1]:

  This algorithm-specific portion is:

  Algorithm-Specific Fields for RSA public keys:

    - multiprecision integer (MPI) of RSA public modulus n;
    - MPI of RSA public encryption exponent e.

  Algorithm-Specific Fields for DSA public keys:

    - MPI of DSA prime p;
    - MPI of DSA group order q (q is a prime divisor of p-1);
    - MPI of DSA group generator g;
    - MPI of DSA public-key value y (= g**x mod p where x is secret).

  Algorithm-Specific Fields for Elgamal public keys:

    - MPI of Elgamal prime p;
    - MPI of Elgamal group generator g;
    - MPI of Elgamal public key value y (= g**x mod p where x is

We need to parse these fields explicitly, because the secret key
packets start with public key packets.  In order to tell where the
rest of the secret key data starts, we need to know the length of the
public key packet; simply treating the rest of the packet as an opaque
public key doesn't work.


8 years agoAdd PGPPacket._parse_multiprecision_integer
W. Trevor King [Fri, 20 Dec 2013 17:16:45 +0000 (09:16 -0800)]
Add PGPPacket._parse_multiprecision_integer

From RFC 4880 [1]:

  An MPI consists of two pieces: a two-octet scalar that is the length
  of the MPI in bits followed by a string of octets that contain the
  actual integer.

  These octets form a big-endian number; a big-endian number can be
  made into an MPI by prefixing it with the appropriate length.


  (all numbers are in hexadecimal)

  The string of octets [00 01 01] forms an MPI with the value 1.  The
  string [00 09 01 FF] forms an MPI with the value of 511.

  Additional rules:

  The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.

  The length field of an MPI describes the length starting from its
  most significant non-zero bit.  Thus, the MPI [00 02 01] is not
  formed correctly.  It should be [00 01 01].

  Unused bits of an MPI MUST be zero.

  Also note that when an MPI is encrypted, the length refers to the
  plaintext MPI.  It may be ill-formed in its ciphertext.


8 years agoDecode public key algorithm in _parse_generic_public_key_packet
W. Trevor King [Fri, 20 Dec 2013 05:27:27 +0000 (21:27 -0800)]
Decode public key algorithm in _parse_generic_public_key_packet

It's easier for humans to parse the text representation ;).

8 years agoAdd PGPPacket._hash_algorithms
W. Trevor King [Fri, 20 Dec 2013 05:18:01 +0000 (21:18 -0800)]
Add PGPPacket._hash_algorithms

From RFC 4880 [1]:

      ID           Algorithm                             Text Name
      --           ---------                             ---------
      1          - MD5 [HAC]                             "MD5"
      2          - SHA-1 [FIPS180]                       "SHA1"
      3          - RIPE-MD/160 [HAC]                     "RIPEMD160"
      4          - Reserved
      5          - Reserved
      6          - Reserved
      7          - Reserved
      8          - SHA256 [FIPS180]                      "SHA256"
      9          - SHA384 [FIPS180]                      "SHA384"
      10         - SHA512 [FIPS180]                      "SHA512"
      11         - SHA224 [FIPS180]                      "SHA224"
      100 to 110 - Private/Experimental algorithm


8 years agoAdd PGPPacket._compression_algorithms
W. Trevor King [Fri, 20 Dec 2013 05:16:05 +0000 (21:16 -0800)]
Add PGPPacket._compression_algorithms

From RFC 4880 [1]:

       ID           Algorithm
       --           ---------
       0          - Uncompressed
       1          - ZIP [RFC1951]
       2          - ZLIB [RFC1950]
       3          - BZip2 [BZ2]
       100 to 110 - Private/Experimental algorithm


8 years agoAdd PGPPacket._symmetric_key_algorithms
W. Trevor King [Fri, 20 Dec 2013 05:13:57 +0000 (21:13 -0800)]
Add PGPPacket._symmetric_key_algorithms

From RFC 4880 [1]:

       ID           Algorithm
       --           ---------
       0          - Plaintext or unencrypted data
       1          - IDEA [IDEA]
       2          - TripleDES (DES-EDE, [SCHNEIER] [HAC] -
                    168 bit key derived from 192)
       3          - CAST5 (128 bit key, as per [RFC2144])
       4          - Blowfish (128 bit key, 16 rounds) [BLOWFISH]
       5          - Reserved
       6          - Reserved
       7          - AES with 128-bit key [AES]
       8          - AES with 192-bit key
       9          - AES with 256-bit key
       10         - Twofish with 256-bit key [TWOFISH]
       100 to 110 - Private/Experimental algorithm


8 years agoAdd PGPPacket._public_key_algorithms
W. Trevor King [Fri, 20 Dec 2013 05:08:26 +0000 (21:08 -0800)]
Add PGPPacket._public_key_algorithms

From RFC 4880 [1]:

      ID           Algorithm
      --           ---------
      1          - RSA (Encrypt or Sign) [HAC]
      2          - RSA Encrypt-Only [HAC]
      3          - RSA Sign-Only [HAC]
      16         - Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
      17         - DSA (Digital Signature Algorithm) [FIPS186] [HAC]
      18         - Reserved for Elliptic Curve
      19         - Reserved for ECDSA
      20         - Reserved (formerly Elgamal Encrypt or Sign)
      21         - Reserved for Diffie-Hellman (X9.42,
                   as defined for IETF-S/MIME)
      100 to 110 - Private/Experimental algorithm


8 years agoAdd public key parsing to PGPPacket
W. Trevor King [Thu, 19 Dec 2013 05:52:42 +0000 (21:52 -0800)]
Add public key parsing to PGPPacket

Use the same parser for public-key and public-subkey packets.  From
RFC 4880 [1]:

  A Public-Subkey packet (tag 14) has exactly the same format as a
  Public-Key packet, but denotes a subkey.  One or more subkeys may be
  associated with a top-level key.

The generic (sub)key parsing is specified in section 5.5.2 [2]:

  OpenPGP implementations MUST create keys with version 4 format.  V3
  keys are deprecated; an implementation MUST NOT generate a V3 key,
  but MAY accept it.


  A version 4 packet contains:

  - A one-octet version number (4).
  - A four-octet number denoting the time that the key was created.
  - A one-octet number denoting the public-key algorithm of this key.
  - A series of multiprecision integers comprising the key material.

Also check that the --export packets begin with a public-key packet.
From RFC 4880 [3]:

  A Public-Key packet starts a series of packets that forms an OpenPGP
  key (sometimes called an OpenPGP certificate).


8 years agoAdd a flexible packet-parsing framework
W. Trevor King [Thu, 19 Dec 2013 05:09:42 +0000 (21:09 -0800)]
Add a flexible packet-parsing framework

Shunting packet-type processing out to type-specific methods.  For
example, 'public-key packet' packets will be parsed by

From the re docs [1]:

    Causes the resulting RE to match 1 or more repetitions of the
    preceding RE. ab+ will match 'a' followed by any non-zero number
    of 'b's; it will not match just 'a'.


    For Unicode (str) patterns:
      Matches Unicode word characters; this includes most characters
      that can be part of a word in any language, as well as numbers
      and the underscore. If the ASCII flag is used, only [a-zA-Z0-9_]
      is matched (but the flag affects the entire regular expression,
      so in such cases using an explicit [a-zA-Z0-9_] may be a better

    For 8-bit (bytes) patterns:
      Matches characters considered alphanumeric in the ASCII
      character set; this is equivalent to [a-zA-Z0-9_].


8 years Convert PGPPacket 'packet-tag' key to 'type'
W. Trevor King [Thu, 19 Dec 2013 04:56:42 +0000 (20:56 -0800)] Convert PGPPacket 'packet-tag' key to 'type'

And convert the integer to a string using the table from RFC 4880 [1]:

  The packet tag denotes what type of packet the body holds.  Note
  that old format headers can only have tags less than 16, whereas new
  format headers can have tags as great as 63.  The defined tags (in
  decimal) are as follows:

       0        -- Reserved - a packet tag MUST NOT have this value
       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 to 63 -- Private or Experimental Values


8 years agoPull PGPPacket header parsing out into _parse_header
W. Trevor King [Thu, 19 Dec 2013 04:46:48 +0000 (20:46 -0800)]
Pull PGPPacket header parsing out into _parse_header

This parsing is distinct from the payload parsing, so stash it in a
separate method.

8 years agoAdd packets_from_bytes to help parse multi-packet streams
W. Trevor King [Thu, 19 Dec 2013 04:45:21 +0000 (20:45 -0800)]
Add packets_from_bytes to help parse multi-packet streams

8 years agoCheck for short packets in PGPPacket.from_bytes
W. Trevor King [Thu, 19 Dec 2013 04:44:30 +0000 (20:44 -0800)]
Check for short packets in PGPPacket.from_bytes

When the data is longer than expected, the packet may just be part of
a stream.

8 years agoTrack data offset in bytes, and extract the packet payload
W. Trevor King [Thu, 19 Dec 2013 04:37:33 +0000 (20:37 -0800)]
Track data offset in bytes, and extract the packet payload

Return the offset when we're done, because there may be multiple
packets in a stream.

8 years agoExtract the packet length from the old-format length header
W. Trevor King [Thu, 19 Dec 2013 04:31:15 +0000 (20:31 -0800)]
Extract the packet length from the old-format length header

From RFC 4880 [1]:

  Scalar numbers are unsigned and are always stored in big-endian
  format.  Using n[k] to refer to the kth octet being interpreted, the
  value of a two-octet scalar is ((n[0] << 8) + n[1]).  The value of a
  four-octet scalar is ((n[0] << 24) + (n[1] << 16) + (n[2] << 8) +

The struct big-endian byte-order character is '>' [2].


8 years agoAdd PGPPacket._old_format_packet_lengths
W. Trevor King [Thu, 19 Dec 2013 04:05:25 +0000 (20:05 -0800)]
Add PGPPacket._old_format_packet_lengths

From RFC 4880 [1]:

   The meaning of the length-type in old format packets is:

   0 - The packet has a one-octet length.  The header is 2 octets long.

   1 - The packet has a two-octet length.  The header is 3 octets long.

   2 - The packet has a four-octet length.  The header is 5 octets long.

   3 - The packet is of indeterminate length.  The header is 1 octet
       long, and the implementation must determine how long the packet
       is.  If the packet is in a file, this means that the packet
       extends until the end of the file.  In general, an implementation
       SHOULD NOT use indeterminate-length packets except where the end
       of the data will be clear from the context, and even then it is
       better to use a definite length, or a new format header.  The new
       format headers described below have a mechanism for precisely
       encoding data of indeterminate length.

The struct format characters are [2]:

  Format   C Type           Python type   Standard size   Notes
  B        unsigned char    integer       1               (3)
  H        unsigned short   integer       2               (3)
  I        unsigned int     integer       4               (3)

  3. When attempting to pack a non-integer using any of the integer
     conversion codes, if the non-integer has a __index__() method
     then that method is called to convert the argument to an integer
     before packing.

     Changed in version 3.2: Use of the __index__() method for
     non-integers is new in 3.2.


8 years agoExtract the packet tag
W. Trevor King [Thu, 19 Dec 2013 03:51:10 +0000 (19:51 -0800)]
Extract the packet tag

From RFC 4880 [1]:

  The first octet of the packet header is called the "Packet Tag".  It
  determines the format of the header and denotes the packet contents.
  The remainder of the packet header is the length of the packet.

  Note that the most significant bit is the leftmost bit, called bit
  7.  A mask for this bit is 0x80 in hexadecimal.

         PTag |7 6 5 4 3 2 1 0|
         Bit 7 -- Always one
         Bit 6 -- New packet format if set

  PGP 2.6.x only uses old format packets.  Thus, software that
  interoperates with those versions of PGP must only use old format
  packets.  If interoperability is not an issue, the new packet format
  is RECOMMENDED.  Note that old format packets have four bits of
  packet tags, and new format packets have six; some features cannot
  be used and still be backward-compatible.

  Also note that packets with a tag greater than or equal to 16 MUST
  use new format packets.  The old format packets can only express
  tags less than or equal to 15.

  Old format packets contain:

         Bits 5-2 -- packet tag
         Bits 1-0 -- length-type

  New format packets contain:

         Bits 5-0 -- packet tag


8 years agoStub out
W. Trevor King [Thu, 19 Dec 2013 03:49:08 +0000 (19:49 -0800)]
Stub out

Following the general approach outlined by Atom Smasher [1], but I'll
just parse the packets directly in Python.