Parse algorithm-specific data in _parse_generic_secret_key_packet
authorW. Trevor King <wking@tremily.us>
Sun, 22 Dec 2013 22:14:03 +0000 (14:14 -0800)
committerW. Trevor King <wking@tremily.us>
Mon, 23 Dec 2013 21:41:06 +0000 (13:41 -0800)
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.

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

gpg-migrate.py

index de00b49d16dc92b5ec7d650d4767578ba9ff1855..f3eb3f9fa379948619f5f6e8ac55f0bcb6304421 100755 (executable)
@@ -596,6 +596,7 @@ class PGPPacket (dict):
         else:
             key_end = 0
         secret_key = decrypted_data[:key_end]
+        secret_offset = 0
         if key_end:
             secret_key_checksum = decrypted_data[key_end:]
             if key_end == -2:
@@ -608,7 +609,38 @@ class PGPPacket (dict):
                 raise ValueError(
                     'corrupt secret key (checksum {} != expected {})'.format(
                         secret_key_checksum, calculated_checksum))
-        self['secret-key'] = secret_key
+        if self['public-key-algorithm'].startswith('rsa '):
+            o, self['secret-exponent'] = self._parse_multiprecision_integer(
+                secret_key[secret_offset:])
+            secret_offset += o
+            o, self['secret-prime-p'] = self._parse_multiprecision_integer(
+                secret_key[secret_offset:])
+            secret_offset += o
+            o, self['secret-prime-q'] = self._parse_multiprecision_integer(
+                secret_key[secret_offset:])
+            secret_offset += o
+            o, self['secret-inverse-of-p-mod-q'] = (
+                self._parse_multiprecision_integer(
+                    secret_key[secret_offset:]))
+            secret_offset += o
+        elif self['public-key-algorithm'].startswith('dsa '):
+            o, self['secret-exponent'] = self._parse_multiprecision_integer(
+                secret_key[secret_offset:])
+            secret_offset += o
+        elif self['public-key-algorithm'].startswith('elgamal '):
+            o, self['secret-exponent'] = self._parse_multiprecision_integer(
+                secret_key[secret_offset:])
+            secret_offset += o
+        else:
+            raise NotImplementedError(
+                'algorithm-specific key fields for {}'.format(
+                    self['public-key-algorithm']))
+        if secret_offset != len(secret_key):
+            raise ValueError(
+                ('parsed {} out of {} bytes of algorithm-specific key fields '
+                 'for {}').format(
+                     secret_offset, len(secret_key),
+                     self['public-key-algorithm']))
 
     def _parse_signature_subpackets(self, data):
         offset = 0