it s hard to test for constant time just test the result https tools ietf orghtmldraftjosefssonpbkdf2testvectors06 this takes way too long args password password salt salt iterations 16777216 dklen 20 digest hashlib sha1 result eefe3d61cd4da4e4e9945b3d6ba2158c2634e984 check leading zeros are not stripped 17481 it s hard to test for constant time just test the result https tools ietf org html draft josefsson pbkdf2 test vectors 06 this takes way too long args password password salt salt iterations 16777216 dklen 20 digest hashlib sha1 result eefe3d61cd4da4e4e9945b3d6ba2158c2634e984 check leading zeros are not stripped 17481
import hashlib
import unittest

from django.test import SimpleTestCase
from django.utils.crypto import (
    InvalidAlgorithm,
    constant_time_compare,
    pbkdf2,
    salted_hmac,
)


class TestUtilsCryptoMisc(SimpleTestCase):
    def test_constant_time_compare(self):
        
        self.assertTrue(constant_time_compare(b"spam", b"spam"))
        self.assertFalse(constant_time_compare(b"spam", b"eggs"))
        self.assertTrue(constant_time_compare("spam", "spam"))
        self.assertFalse(constant_time_compare("spam", "eggs"))

    def test_salted_hmac(self):
        tests = [
            ((b"salt", b"value"), {}, "b51a2e619c43b1ca4f91d15c57455521d71d61eb"),
            (("salt", "value"), {}, "b51a2e619c43b1ca4f91d15c57455521d71d61eb"),
            (
                ("salt", "value"),
                {"secret": "abcdefg"},
                "8bbee04ccddfa24772d1423a0ba43bd0c0e24b76",
            ),
            (
                ("salt", "value"),
                {"secret": "x" * hashlib.sha1().block_size},
                "bd3749347b412b1b0a9ea65220e55767ac8e96b0",
            ),
            (
                ("salt", "value"),
                {"algorithm": "sha256"},
                "ee0bf789e4e009371a5372c90f73fcf17695a8439c9108b0480f14e347b3f9ec",
            ),
            (
                ("salt", "value"),
                {
                    "algorithm": "blake2b",
                    "secret": "x" * hashlib.blake2b().block_size,
                },
                "fc6b9800a584d40732a07fa33fb69c35211269441823bca431a143853c32f"
                "e836cf19ab881689528ede647dac412170cd5d3407b44c6d0f44630690c54"
                "ad3d58",
            ),
        ]
        for args, kwargs, digest in tests:
            with self.subTest(args=args, kwargs=kwargs):
                self.assertEqual(salted_hmac(*args, **kwargs).hexdigest(), digest)

    def test_invalid_algorithm(self):
        msg = "'whatever' is not an algorithm accepted by the hashlib module."
        with self.assertRaisesMessage(InvalidAlgorithm, msg):
            salted_hmac("salt", "value", algorithm="whatever")


class TestUtilsCryptoPBKDF2(unittest.TestCase):
    
    rfc_vectors = [
        {
            "args": {
                "password": "password",
                "salt": "salt",
                "iterations": 1,
                "dklen": 20,
                "digest": hashlib.sha1,
            },
            "result": "0c60c80f961f0e71f3a9b524af6012062fe037a6",
        },
        {
            "args": {
                "password": "password",
                "salt": "salt",
                "iterations": 2,
                "dklen": 20,
                "digest": hashlib.sha1,
            },
            "result": "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957",
        },
        {
            "args": {
                "password": "password",
                "salt": "salt",
                "iterations": 4096,
                "dklen": 20,
                "digest": hashlib.sha1,
            },
            "result": "4b007901b765489abead49d926f721d065a429c1",
        },
        
        
        
        
        
        
        
        
        
        
        
        {
            "args": {
                "password": "passwordPASSWORDpassword",
                "salt": "saltSALTsaltSALTsaltSALTsaltSALTsalt",
                "iterations": 4096,
                "dklen": 25,
                "digest": hashlib.sha1,
            },
            "result": "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038",
        },
        {
            "args": {
                "password": "pass\0word",
                "salt": "sa\0lt",
                "iterations": 4096,
                "dklen": 16,
                "digest": hashlib.sha1,
            },
            "result": "56fa6aa75548099dcc37d7f03425e0c3",
        },
    ]

    regression_vectors = [
        {
            "args": {
                "password": "password",
                "salt": "salt",
                "iterations": 1,
                "dklen": 20,
                "digest": hashlib.sha256,
            },
            "result": "120fb6cffcf8b32c43e7225256c4f837a86548c9",
        },
        {
            "args": {
                "password": "password",
                "salt": "salt",
                "iterations": 1,
                "dklen": 20,
                "digest": hashlib.sha512,
            },
            "result": "867f70cf1ade02cff3752599a3a53dc4af34c7a6",
        },
        {
            "args": {
                "password": "password",
                "salt": "salt",
                "iterations": 1000,
                "dklen": 0,
                "digest": hashlib.sha512,
            },
            "result": (
                "afe6c5530785b6cc6b1c6453384731bd5ee432ee"
                "549fd42fb6695779ad8a1c5bf59de69c48f774ef"
                "c4007d5298f9033c0241d5ab69305e7b64eceeb8d"
                "834cfec"
            ),
        },
        
        {
            "args": {
                "password": b"\xba",
                "salt": "salt",
                "iterations": 1,
                "dklen": 20,
                "digest": hashlib.sha1,
            },
            "result": "0053d3b91a7f1e54effebd6d68771e8a6e0b2c5b",
        },
    ]

    def test_public_vectors(self):
        for vector in self.rfc_vectors:
            result = pbkdf2(**vector["args"])
            self.assertEqual(result.hex(), vector["result"])

    def test_regression_vectors(self):
        for vector in self.regression_vectors:
            result = pbkdf2(**vector["args"])
            self.assertEqual(result.hex(), vector["result"])

    def test_default_hmac_alg(self):
        kwargs = {
            "password": b"password",
            "salt": b"salt",
            "iterations": 1,
            "dklen": 20,
        }
        self.assertEqual(
            pbkdf2(**kwargs),
            hashlib.pbkdf2_hmac(hash_name=hashlib.sha256().name, **kwargs),
        )