Check the secret key checksum in PGPPacket._parse_generic_secret_key_packet
authorW. Trevor King <wking@tremily.us>
Sat, 21 Dec 2013 02:34:41 +0000 (18:34 -0800)
committerW. Trevor King <wking@tremily.us>
Mon, 23 Dec 2013 02:32:15 +0000 (18:32 -0800)
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

gpg-migrate.py

index 8b0f1a22023388245564ab78886adb73d581a0bf..6d8f8f3eb92bf5253ed3d4cac1568cf0c0b5d3e7 100755 (executable)
@@ -522,9 +522,15 @@ class PGPPacket (dict):
             key_end = -2
         else:
             key_end = 0
-        self['secret-key'] = data[offset:key_end]
+        secret_key = data[offset:key_end]
         if key_end:
-            self['secret-key-checksum'] = data[key_end:]
+            secret_key_checksum = data[key_end:]
+            calculated_checksum = sum(secret_key) % 65536
+            if secret_key_checksum != calculated_checksum:
+                raise ValueError(
+                    'corrupt secret key (checksum {} != expected {})'.format(
+                        secret_key_checksum, calculated_checksum))
+        self['secret-key'] = secret_key
 
     def _parse_signature_subpackets(self, data):
         offset = 0