Clean architecture (core use cases + infra gateways), X25519/AES-GCM E2E encryption, tkinter GUI, and a pytest suite. 45 tests passing.
62 lines
1.9 KiB
Python
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))
|