from math import log import time from django.test import TestCase from desecapi import crypto class CryptoTestCase(TestCase): context = "desecapi.tests.test_crypto" def test_retrieved_key_is_reproducible(self): keys = ( crypto.retrieve_key(label="test", context=self.context) for _ in range(2) ) self.assertEqual(*keys) def test_retrieved_key_depends_on_secret(self): keys = [] for secret in ["abcdefgh", "hgfedcba"]: with self.settings(SECRET_KEY=secret): keys.append(crypto.retrieve_key(label="test", context=self.context)) self.assertNotEqual(*keys) def test_retrieved_key_depends_on_label(self): keys = ( crypto.retrieve_key(label=f"test_{i}", context=self.context) for i in range(2) ) self.assertNotEqual(*keys) def test_retrieved_key_depends_on_context(self): keys = ( crypto.retrieve_key(label="test", context=f"{self.context}_{i}") for i in range(2) ) self.assertNotEqual(*keys) def test_encrypt_has_high_entropy(self): def entropy(value: str): result = 0 counts = [value.count(char) for char in set(value)] for count in counts: count /= len(value) result -= count * log(count, 2) return result * len(value) ciphertext = crypto.encrypt(b"test", context=self.context) self.assertGreater(entropy(ciphertext), 100) # arbitrary def test_encrypt_decrypt(self): plain = b"test" ciphertext = crypto.encrypt(plain, context=self.context) timestamp, decrypted = crypto.decrypt(ciphertext, context=self.context) self.assertEqual(plain, decrypted) self.assertTrue(0 <= time.time() - timestamp <= 1) def test_encrypt_decrypt_raises_on_tampering(self): ciphertext = crypto.encrypt(b"test", context=self.context) with self.assertRaises(ValueError): ciphertext_decoded = ciphertext.decode() ciphertext_tampered = ( ciphertext_decoded[:30] + "TAMPERBEEF" + ciphertext_decoded[40:] ).encode() crypto.decrypt(ciphertext_tampered, context=self.context) with self.assertRaises(ValueError): crypto.decrypt(ciphertext, context=f"{self.context}2")