Parse algorithm-specific data in _parse_generic_public_key_packet
authorW. Trevor King <wking@tremily.us>
Fri, 20 Dec 2013 17:26:47 +0000 (09:26 -0800)
committerW. Trevor King <wking@tremily.us>
Fri, 20 Dec 2013 19:46:30 +0000 (11:46 -0800)
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

gpg-migrate.py

index 3a893522fbc69b7999a6c858c2b5f1eba95d2c5d..c1e32cce9040a4fb913d7d8c65143c379de57b79 100755 (executable)
@@ -223,7 +223,41 @@ class PGPPacket (dict):
             '>IB', data[offset: offset + length])
         offset += length
         self['public-key-algorithm'] = self._public_key_algorithms[algorithm]
-        self['key'] = data[offset:]
+        if self['public-key-algorithm'].startswith('rsa '):
+            o, self['public-modulus'] = self._parse_multiprecision_integer(
+                data[offset:])
+            offset += o
+            o, self['public-exponent'] = self._parse_multiprecision_integer(
+                data[offset:])
+            offset += o
+        elif self['public-key-algorithm'].startswith('dsa '):
+            o, self['prime'] = self._parse_multiprecision_integer(
+                data[offset:])
+            offset += o
+            o, self['group-order'] = self._parse_multiprecision_integer(
+                data[offset:])
+            offset += o
+            o, self['group-generator'] = self._parse_multiprecision_integer(
+                data[offset:])
+            offset += o
+            o, self['public-key'] = self._parse_multiprecision_integer(
+                data[offset:])
+            offset += o
+        elif self['public-key-algorithm'].startswith('elgamal '):
+            o, self['prime'] = self._parse_multiprecision_integer(
+                data[offset:])
+            offset += o
+            o, self['group-generator'] = self._parse_multiprecision_integer(
+                data[offset:])
+            offset += o
+            o, self['public-key'] = self._parse_multiprecision_integer(
+                data[offset:])
+            offset += o
+        else:
+            raise NotImplementedError(
+                'algorithm-specific key fields for {}'.format(
+                    self['public-key-algorithm']))
+        return offset
 
     def to_bytes(self):
         pass