def compute_session_keys( cls, *, local_private_key: bytes, remote_public_key: bytes, local_node_id: NodeID, remote_node_id: NodeID, salt: bytes, is_locally_initiated: bool, ) -> SessionKeys: secret = ecdh_agree(local_private_key, remote_public_key) if is_locally_initiated: initiator_node_id, recipient_node_id = local_node_id, remote_node_id else: initiator_node_id, recipient_node_id = remote_node_id, local_node_id initiator_key, recipient_key, auth_response_key = hkdf_expand_and_extract( secret, initiator_node_id, recipient_node_id, salt, ) if is_locally_initiated: encryption_key, decryption_key = initiator_key, recipient_key else: encryption_key, decryption_key = recipient_key, initiator_key return SessionKeys( encryption_key=AES128Key(encryption_key), decryption_key=AES128Key(decryption_key), auth_response_key=AES128Key(auth_response_key), )
def _prepare(*, nonce: Optional[Nonce] = None, initiator_key: Optional[AES128Key] = None, message: BaseMessage, auth_data: TAuthData, source_node_id: Optional[NodeID] = None, dest_node_id: Optional[NodeID] = None, protocol_id: bytes = PROTOCOL_ID) -> Packet[TAuthData]: if nonce is None: nonce = Nonce(secrets.token_bytes(12)) if initiator_key is None: initiator_key = AES128Key(secrets.token_bytes(16)) if source_node_id is None: source_node_id = NodeID(secrets.token_bytes(32)) if dest_node_id is None: dest_node_id = NodeID(secrets.token_bytes(32)) return Packet.prepare( nonce=nonce, initiator_key=initiator_key, message=message, auth_data=auth_data, source_node_id=source_node_id, dest_node_id=dest_node_id, protocol_id=protocol_id, )
def to_wire_bytes(self) -> bytes: auth_data_bytes = self.auth_data.to_wire_bytes() header_wire_bytes = self.header.to_wire_bytes() header_plaintext = header_wire_bytes + auth_data_bytes masking_key = AES128Key(self.dest_node_id[:16]) masked_header = aesctr_encrypt(masking_key, self.iv, header_plaintext) return b"".join(( self.iv, masked_header, self.message_cipher_text, ))
def test_decryption_with_wrong_inputs(): key = AES128Key(b"\x00" * 16) nonce = Nonce(b"\x11" * 12) plain_text = b"\x33" * 5 aad = b"\x44" * 5 cipher_text = aesgcm_encrypt(key, nonce, plain_text, aad) assert aesgcm_decrypt(key, nonce, cipher_text, aad) == plain_text with pytest.raises(ValidationError): aesgcm_decrypt(b"", nonce, cipher_text, aad) with pytest.raises(ValidationError): aesgcm_decrypt(key, b"", cipher_text, aad) with pytest.raises(DecryptionError): aesgcm_decrypt(key, nonce, b"", aad) with pytest.raises(DecryptionError): aesgcm_decrypt(key, nonce, cipher_text, b"")
def test_key_validation_valid(key): validate_aes128_key(AES128Key(key))
def test_key_validation_invalid(): for length in (0, 12, 15, 17, 32): with pytest.raises(ValidationError): validate_aes128_key(AES128Key(b"\x00" * length))