1. import hashlib
    
  2. import unittest
    
  3. 
    
  4. from django.test import SimpleTestCase
    
  5. from django.utils.crypto import (
    
  6.     InvalidAlgorithm,
    
  7.     constant_time_compare,
    
  8.     pbkdf2,
    
  9.     salted_hmac,
    
  10. )
    
  11. 
    
  12. 
    
  13. class TestUtilsCryptoMisc(SimpleTestCase):
    
  14.     def test_constant_time_compare(self):
    
  15.         # It's hard to test for constant time, just test the result.
    
  16.         self.assertTrue(constant_time_compare(b"spam", b"spam"))
    
  17.         self.assertFalse(constant_time_compare(b"spam", b"eggs"))
    
  18.         self.assertTrue(constant_time_compare("spam", "spam"))
    
  19.         self.assertFalse(constant_time_compare("spam", "eggs"))
    
  20. 
    
  21.     def test_salted_hmac(self):
    
  22.         tests = [
    
  23.             ((b"salt", b"value"), {}, "b51a2e619c43b1ca4f91d15c57455521d71d61eb"),
    
  24.             (("salt", "value"), {}, "b51a2e619c43b1ca4f91d15c57455521d71d61eb"),
    
  25.             (
    
  26.                 ("salt", "value"),
    
  27.                 {"secret": "abcdefg"},
    
  28.                 "8bbee04ccddfa24772d1423a0ba43bd0c0e24b76",
    
  29.             ),
    
  30.             (
    
  31.                 ("salt", "value"),
    
  32.                 {"secret": "x" * hashlib.sha1().block_size},
    
  33.                 "bd3749347b412b1b0a9ea65220e55767ac8e96b0",
    
  34.             ),
    
  35.             (
    
  36.                 ("salt", "value"),
    
  37.                 {"algorithm": "sha256"},
    
  38.                 "ee0bf789e4e009371a5372c90f73fcf17695a8439c9108b0480f14e347b3f9ec",
    
  39.             ),
    
  40.             (
    
  41.                 ("salt", "value"),
    
  42.                 {
    
  43.                     "algorithm": "blake2b",
    
  44.                     "secret": "x" * hashlib.blake2b().block_size,
    
  45.                 },
    
  46.                 "fc6b9800a584d40732a07fa33fb69c35211269441823bca431a143853c32f"
    
  47.                 "e836cf19ab881689528ede647dac412170cd5d3407b44c6d0f44630690c54"
    
  48.                 "ad3d58",
    
  49.             ),
    
  50.         ]
    
  51.         for args, kwargs, digest in tests:
    
  52.             with self.subTest(args=args, kwargs=kwargs):
    
  53.                 self.assertEqual(salted_hmac(*args, **kwargs).hexdigest(), digest)
    
  54. 
    
  55.     def test_invalid_algorithm(self):
    
  56.         msg = "'whatever' is not an algorithm accepted by the hashlib module."
    
  57.         with self.assertRaisesMessage(InvalidAlgorithm, msg):
    
  58.             salted_hmac("salt", "value", algorithm="whatever")
    
  59. 
    
  60. 
    
  61. class TestUtilsCryptoPBKDF2(unittest.TestCase):
    
  62.     # https://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06
    
  63.     rfc_vectors = [
    
  64.         {
    
  65.             "args": {
    
  66.                 "password": "password",
    
  67.                 "salt": "salt",
    
  68.                 "iterations": 1,
    
  69.                 "dklen": 20,
    
  70.                 "digest": hashlib.sha1,
    
  71.             },
    
  72.             "result": "0c60c80f961f0e71f3a9b524af6012062fe037a6",
    
  73.         },
    
  74.         {
    
  75.             "args": {
    
  76.                 "password": "password",
    
  77.                 "salt": "salt",
    
  78.                 "iterations": 2,
    
  79.                 "dklen": 20,
    
  80.                 "digest": hashlib.sha1,
    
  81.             },
    
  82.             "result": "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957",
    
  83.         },
    
  84.         {
    
  85.             "args": {
    
  86.                 "password": "password",
    
  87.                 "salt": "salt",
    
  88.                 "iterations": 4096,
    
  89.                 "dklen": 20,
    
  90.                 "digest": hashlib.sha1,
    
  91.             },
    
  92.             "result": "4b007901b765489abead49d926f721d065a429c1",
    
  93.         },
    
  94.         # # this takes way too long :(
    
  95.         # {
    
  96.         #     "args": {
    
  97.         #         "password": "password",
    
  98.         #         "salt": "salt",
    
  99.         #         "iterations": 16777216,
    
  100.         #         "dklen": 20,
    
  101.         #         "digest": hashlib.sha1,
    
  102.         #     },
    
  103.         #     "result": "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984",
    
  104.         # },
    
  105.         {
    
  106.             "args": {
    
  107.                 "password": "passwordPASSWORDpassword",
    
  108.                 "salt": "saltSALTsaltSALTsaltSALTsaltSALTsalt",
    
  109.                 "iterations": 4096,
    
  110.                 "dklen": 25,
    
  111.                 "digest": hashlib.sha1,
    
  112.             },
    
  113.             "result": "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038",
    
  114.         },
    
  115.         {
    
  116.             "args": {
    
  117.                 "password": "pass\0word",
    
  118.                 "salt": "sa\0lt",
    
  119.                 "iterations": 4096,
    
  120.                 "dklen": 16,
    
  121.                 "digest": hashlib.sha1,
    
  122.             },
    
  123.             "result": "56fa6aa75548099dcc37d7f03425e0c3",
    
  124.         },
    
  125.     ]
    
  126. 
    
  127.     regression_vectors = [
    
  128.         {
    
  129.             "args": {
    
  130.                 "password": "password",
    
  131.                 "salt": "salt",
    
  132.                 "iterations": 1,
    
  133.                 "dklen": 20,
    
  134.                 "digest": hashlib.sha256,
    
  135.             },
    
  136.             "result": "120fb6cffcf8b32c43e7225256c4f837a86548c9",
    
  137.         },
    
  138.         {
    
  139.             "args": {
    
  140.                 "password": "password",
    
  141.                 "salt": "salt",
    
  142.                 "iterations": 1,
    
  143.                 "dklen": 20,
    
  144.                 "digest": hashlib.sha512,
    
  145.             },
    
  146.             "result": "867f70cf1ade02cff3752599a3a53dc4af34c7a6",
    
  147.         },
    
  148.         {
    
  149.             "args": {
    
  150.                 "password": "password",
    
  151.                 "salt": "salt",
    
  152.                 "iterations": 1000,
    
  153.                 "dklen": 0,
    
  154.                 "digest": hashlib.sha512,
    
  155.             },
    
  156.             "result": (
    
  157.                 "afe6c5530785b6cc6b1c6453384731bd5ee432ee"
    
  158.                 "549fd42fb6695779ad8a1c5bf59de69c48f774ef"
    
  159.                 "c4007d5298f9033c0241d5ab69305e7b64eceeb8d"
    
  160.                 "834cfec"
    
  161.             ),
    
  162.         },
    
  163.         # Check leading zeros are not stripped (#17481)
    
  164.         {
    
  165.             "args": {
    
  166.                 "password": b"\xba",
    
  167.                 "salt": "salt",
    
  168.                 "iterations": 1,
    
  169.                 "dklen": 20,
    
  170.                 "digest": hashlib.sha1,
    
  171.             },
    
  172.             "result": "0053d3b91a7f1e54effebd6d68771e8a6e0b2c5b",
    
  173.         },
    
  174.     ]
    
  175. 
    
  176.     def test_public_vectors(self):
    
  177.         for vector in self.rfc_vectors:
    
  178.             result = pbkdf2(**vector["args"])
    
  179.             self.assertEqual(result.hex(), vector["result"])
    
  180. 
    
  181.     def test_regression_vectors(self):
    
  182.         for vector in self.regression_vectors:
    
  183.             result = pbkdf2(**vector["args"])
    
  184.             self.assertEqual(result.hex(), vector["result"])
    
  185. 
    
  186.     def test_default_hmac_alg(self):
    
  187.         kwargs = {
    
  188.             "password": b"password",
    
  189.             "salt": b"salt",
    
  190.             "iterations": 1,
    
  191.             "dklen": 20,
    
  192.         }
    
  193.         self.assertEqual(
    
  194.             pbkdf2(**kwargs),
    
  195.             hashlib.pbkdf2_hmac(hash_name=hashlib.sha256().name, **kwargs),
    
  196.         )