neotalk/tests/infra/test_x25519_crypto.py
Andros Fenollosa bfd8b510b6 Initial neotalk: P2P encrypted chat over UDP discovery + TCP streaming
Clean architecture (core use cases + infra gateways), X25519/AES-GCM E2E
encryption, tkinter GUI, and a pytest suite. 45 tests passing.
2026-08-21 09:16:07 +02:00

62 lines
1.9 KiB
Python

"""Tests for the real X25519 + AES-GCM crypto implementation."""
import pytest
from neotalk.infra.crypto.x25519_crypto import X25519Crypto
def test_two_parties_derive_the_same_shared_key():
# Given two independent key pairs
alice = X25519Crypto()
bob = X25519Crypto()
# When each derives the shared key from the other's public key
alice_key = alice.derive_shared_key(bob.public_key_bytes())
bob_key = bob.derive_shared_key(alice.public_key_bytes())
# Then both reach the same 256-bit key
assert alice_key == bob_key
assert len(alice_key) == 32
def test_encrypt_then_decrypt_round_trips():
# Given a shared key between two parties
alice = X25519Crypto()
bob = X25519Crypto()
key = alice.derive_shared_key(bob.public_key_bytes())
# When Alice encrypts and Bob decrypts
ciphertext = alice.encrypt(key, b"secret message")
plaintext = bob.decrypt(bob.derive_shared_key(alice.public_key_bytes()), ciphertext)
# Then the plaintext is recovered
assert plaintext == b"secret message"
def test_ciphertext_differs_each_time():
# Given a key and a message
crypto = X25519Crypto()
peer = X25519Crypto()
key = crypto.derive_shared_key(peer.public_key_bytes())
# When encrypting the same plaintext twice
first = crypto.encrypt(key, b"same")
second = crypto.encrypt(key, b"same")
# Then the random nonce makes the ciphertexts differ
assert first != second
def test_tampered_ciphertext_is_rejected():
# Given a valid ciphertext
crypto = X25519Crypto()
peer = X25519Crypto()
key = crypto.derive_shared_key(peer.public_key_bytes())
ciphertext = bytearray(crypto.encrypt(key, b"secret"))
# When a byte is flipped
ciphertext[-1] ^= 0x01
# Then AES-GCM authentication fails
with pytest.raises(Exception): # noqa: B017 - InvalidTag from cryptography
crypto.decrypt(key, bytes(ciphertext))