gpg-migrate.git
11 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.

[1]: http://csrc.nist.gov/publications/fips/fips197/fips-197.{ps,pdf}

11 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.

[1]: http://tools.ietf.org/search/rfc4880#section-5.5.1.4
[2]: http://tools.ietf.org/search/rfc4880#section-5.5.3
[3]: http://tools.ietf.org/search/rfc4880#section-10.3.2
[4]: http://tools.ietf.org/search/rfc4880#section-9.2
[5]: http://csrc.nist.gov/publications/fips/fips197/fips-197.{ps,pdf}

11 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

[1]: http://tools.ietf.org/search/rfc4880#section-3.7.1.3

11 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

[1]: http://tools.ietf.org/search/rfc4880#section-3.7.1.2

11 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

[1]: http://tools.ietf.org/search/rfc4880#section-3.7.1.1

11 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 (3.7.1.1 - 3.7.1.3), 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.

[1]: http://tools.ietf.org/search/rfc4880#section-3.7.1

11 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
      secret).

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.

[1]: http://tools.ietf.org/search/rfc4880#section-5.5.2

11 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.

  Examples:

  (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.

[1]: http://tools.ietf.org/search/rfc4880#section-3.2

11 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 ;).

11 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

[1]: http://tools.ietf.org/search/rfc4880#section-9.4

11 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

[1]: http://tools.ietf.org/search/rfc4880#section-9.3

11 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

[1]: http://tools.ietf.org/search/rfc4880#section-9.2

11 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

[1]: http://tools.ietf.org/search/rfc4880#section-9.1

11 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).

[1]: http://tools.ietf.org/search/rfc4880#section-5.5.1.2
[2]: http://tools.ietf.org/search/rfc4880#section-5.5.2
[3]: http://tools.ietf.org/search/rfc4880#section-5.5.1.1

11 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
PGPPacket._parse_public_key_packet.

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'.

  ...

  \W
    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
      choice).

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

[1]: http://docs.python.org/3/library/re.html#regular-expression-syntax

11 years agogpg-migrate.py: Convert PGPPacket 'packet-tag' key to 'type'
W. Trevor King [Thu, 19 Dec 2013 04:56:42 +0000 (20:56 -0800)]
gpg-migrate.py: 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

[1]: http://tools.ietf.org/search/rfc4880#section-4.3

11 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.

11 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

11 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.

11 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.

11 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) +
  n[3]).

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

[1]: http://tools.ietf.org/search/rfc4880#section-3.1
[2]: http://docs.python.org/3/library/struct.html#byte-order-size-and-alignment

11 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.

[1]: http://tools.ietf.org/search/rfc4880#section-4.2.1
[2]: http://docs.python.org/3/library/struct.html#format-characters

11 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

[1]: http://tools.ietf.org/search/rfc4880#section-4.2

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

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

[1]: http://atom.smasher.org/gpg/gpg-migrate.txt