self['public-key-algorithm']))
return b''.join(chunks)
+ def _serialize_signature_subpackets(self, subpackets):
+ return b''.join(
+ self._serialize_signature_subpacket(subpacket=subpacket)
+ for subpacket in subpackets)
+
+ def _serialize_signature_subpacket(self, subpacket):
+ method_name = '_serialize_{}_signature_subpacket'.format(
+ self._clean_type(type=subpacket['type']))
+ method = getattr(self, method_name, None)
+ if not method:
+ raise NotImplementedError(
+ 'cannot serialize signature subpacket type {!r}'.format(
+ subpacket['type']))
+ body = method(subpacket=subpacket)
+ length = len(body) + 1
+ chunks = []
+ if length < 192:
+ chunks.append(bytes([length]))
+ else:
+ first = ((length - 192) >> 8) + 192
+ if first < 255:
+ chunks.extend([
+ first,
+ (length - 192) % 256,
+ ])
+ else:
+ chunks.append(_struct.pack('>I', length))
+ chunks.append(bytes([self._reverse(
+ self._signature_subpacket_types, subpacket['type'])]))
+ chunks.append(body)
+ return b''.join(chunks)
+
+ def _serialize_signature_packet_target(self, target):
+ if target is None:
+ return b''
+ elif isinstance(target, bytes):
+ return target
+ elif isinstance(target, PGPPacket):
+ serialized = target._serialize_body()
+ if target['type'] in [
+ 'public-key packet',
+ 'public-subkey packet'
+ 'secret-key packet',
+ 'secret-subkey packet'
+ ]:
+ serialized = b''.join([
+ b'\x99',
+ _struct.pack('>H', len(serialized)),
+ serialized,
+ ])
+ elif target['type'] == 'user id packet':
+ serialized = b''.join([
+ b'\xb4',
+ _struct.pack('>I', len(serialized)),
+ serialized,
+ ])
+ elif target['type'] == 'user attribute packet':
+ serialized = b''.join([
+ b'\xd1',
+ _struct.pack('>I', len(serialized)),
+ serialized,
+ ])
+ return serialized
+ elif isinstance(target, list):
+ return b''.join(
+ self._serialize_signature_packet_target(target=x)
+ for x in target)
+
+ def _serialize_signature_packet(self):
+ if self['signature-version'] != 4:
+ raise NotImplementedError(
+ 'signature packet version {}'.format(
+ self['signature-version']))
+ signature_version = bytes([self['signature-version']])
+ chunks = [signature_version]
+ chunks.append(bytes([self._reverse(
+ self._signature_types, self['signature-type'])]))
+ chunks.append(bytes([self._reverse(
+ self._public_key_algorithms, self['public-key-algorithm'])]))
+ chunks.append(bytes([self._reverse(
+ self._hash_algorithms, self['hash-algorithm'])]))
+ hashed_subpackets = self._serialize_signature_subpackets(
+ self['hashed-subpackets'])
+ chunks.append(_struct.pack('>H', len(hashed_subpackets)))
+ chunks.append(hashed_subpackets)
+ hashed_signature_data = b''.join(chunks)
+ unhashed_subpackets = self._serialize_signature_subpackets(
+ self['unhashed-subpackets'])
+ chunks.append(_struct.pack('>H', len(unhashed_subpackets)))
+ chunks.append(unhashed_subpackets)
+ target = self._serialize_signature_packet_target(target=self['target'])
+ signed_data = b''.join([
+ target,
+ hashed_signature_data,
+ signature_version,
+ b'\xff',
+ _struct.pack('>I', len(hashed_signature_data)),
+ ])
+ digest, signature = self.key.sign(
+ data=signed_data, hash_algorithm=self['hash-algorithm'],
+ signature_algorithm=self['public-key-algorithm'])
+ chunks.extend([digest[:2], signature])
+ return b''.join(chunks)
+
+ def _serialize_signature_creation_time_signature_subpacket(
+ self, subpacket):
+ return _struct.pack('>I', subpacket['signature-creation-time'])
+
+ def _serialize_issuer_signature_subpacket(self, subpacket):
+ return string_bytes(data=subpacket['issuer'], sep='')
+
+ def _serialize_key_expiration_time_signature_subpacket(self, subpacket):
+ return _struct.pack('>I', subpacket['key-expiration-time'])
+
+ def _serialize_preferred_symmetric_algorithms_signature_subpacket(
+ self, subpacket):
+ return bytes(
+ self._reverse(self._symmetric_key_algorithms, a)
+ for a in subpacket['preferred-symmetric-algorithms'])
+
+ def _serialize_preferred_hash_algorithms_signature_subpacket(
+ self, subpacket):
+ return bytes(
+ self._reverse(self._hash_algorithms, a)
+ for a in subpacket['preferred-hash-algorithms'])
+
+ def _serialize_preferred_compression_algorithms_signature_subpacket(
+ self, subpacket):
+ return bytes(
+ self._reverse(self._compression_algorithms, a)
+ for a in subpacket['preferred-compression-algorithms'])
+
+ def _serialize_key_server_preferences_signature_subpacket(self, subpacket):
+ return bytes([
+ 0x80 * ('no-modify' in subpacket['key-server-preferences']) |
+ 0,
+ ])
+
+ def _serialize_primary_user_id_signature_subpacket(self, subpacket):
+ return bytes([0x1 * subpacket['primary-user-id']])
+
+ def _serialize_key_flags_signature_subpacket(self, subpacket):
+ return bytes([
+ 0x1 * ('can certify' in subpacket['key-flags']) |
+ 0x2 * ('can sign' in subpacket['key-flags']) |
+ 0x4 * ('can encrypt communications' in subpacket['key-flags']) |
+ 0x8 * ('can encrypt storage' in subpacket['key-flags']) |
+ 0x10 * ('private split' in subpacket['key-flags']) |
+ 0x20 * ('can authenticate' in subpacket['key-flags']) |
+ 0x80 * ('private shated' in subpacket['key-flags']) |
+ 0,
+ ])
+
+ def _serialize_features_signature_subpacket(self, subpacket):
+ return bytes([
+ 0x1 * ('modification detection' in subpacket['features']) |
+ 0,
+ ])
+
+ def _serialize_embedded_signature_signature_subpacket(self, subpacket):
+ return subpacket['embedded'].to_bytes()
+
def _serialize_user_id_packet(self):
return self['user'].encode('utf-8')