test_crypto.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. from math import log
  2. import time
  3. from django.test import TestCase
  4. from desecapi import crypto
  5. class CryptoTestCase(TestCase):
  6. context = "desecapi.tests.test_crypto"
  7. def test_retrieved_key_is_reproducible(self):
  8. keys = (
  9. crypto.retrieve_key(label="test", context=self.context) for _ in range(2)
  10. )
  11. self.assertEqual(*keys)
  12. def test_retrieved_key_depends_on_secret(self):
  13. keys = []
  14. for secret in ["abcdefgh", "hgfedcba"]:
  15. with self.settings(SECRET_KEY=secret):
  16. keys.append(crypto.retrieve_key(label="test", context=self.context))
  17. self.assertNotEqual(*keys)
  18. def test_retrieved_key_depends_on_label(self):
  19. keys = (
  20. crypto.retrieve_key(label=f"test_{i}", context=self.context)
  21. for i in range(2)
  22. )
  23. self.assertNotEqual(*keys)
  24. def test_retrieved_key_depends_on_context(self):
  25. keys = (
  26. crypto.retrieve_key(label="test", context=f"{self.context}_{i}")
  27. for i in range(2)
  28. )
  29. self.assertNotEqual(*keys)
  30. def test_encrypt_has_high_entropy(self):
  31. def entropy(value: str):
  32. result = 0
  33. counts = [value.count(char) for char in set(value)]
  34. for count in counts:
  35. count /= len(value)
  36. result -= count * log(count, 2)
  37. return result * len(value)
  38. ciphertext = crypto.encrypt(b"test", context=self.context)
  39. self.assertGreater(entropy(ciphertext), 100) # arbitrary
  40. def test_encrypt_decrypt(self):
  41. plain = b"test"
  42. ciphertext = crypto.encrypt(plain, context=self.context)
  43. timestamp, decrypted = crypto.decrypt(ciphertext, context=self.context)
  44. self.assertEqual(plain, decrypted)
  45. self.assertTrue(0 <= time.time() - timestamp <= 1)
  46. def test_encrypt_decrypt_raises_on_tampering(self):
  47. ciphertext = crypto.encrypt(b"test", context=self.context)
  48. with self.assertRaises(ValueError):
  49. ciphertext_decoded = ciphertext.decode()
  50. ciphertext_tampered = (
  51. ciphertext_decoded[:30] + "TAMPERBEEF" + ciphertext_decoded[40:]
  52. ).encode()
  53. crypto.decrypt(ciphertext_tampered, context=self.context)
  54. with self.assertRaises(ValueError):
  55. crypto.decrypt(ciphertext, context=f"{self.context}2")