From fe7ae6bbc191d71fd9d50f6d54aaf4b46346fb65 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 20 Dec 2013 09:16:45 -0800 Subject: [PATCH] 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 --- gpg-migrate.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gpg-migrate.py b/gpg-migrate.py index d2049c2..3a89352 100755 --- a/gpg-migrate.py +++ b/gpg-migrate.py @@ -187,6 +187,24 @@ class PGPPacket (dict): self['type'] = self._packet_types[type_code] return offset + @staticmethod + def _parse_multiprecision_integer(data): + r"""Parse RFC 4880's multiprecision integers + + >>> PGPPacket._parse_multiprecision_integer(b'\x00\x01\x01') + (3, 1) + >>> PGPPacket._parse_multiprecision_integer(b'\x00\x09\x01\xff') + (4, 511) + """ + bits = _struct.unpack('>H', data[:2])[0] + offset = 2 + length = (bits + 7) // 8 + value = 0 + for i in range(length): + value += data[offset + i] * 1 << (8 * (length - i - 1)) + offset += length + return (offset, value) + def _parse_public_key_packet(self, data): self._parse_generic_public_key_packet(data=data) -- 2.26.2