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