diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2014-01-29 21:18:06 -0600 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2014-01-29 21:18:06 -0600 |
commit | 5ff316753118ac1445858a111c8d76da1c7c3e40 (patch) | |
tree | f7deaa2a7d54a77ec50e3e1a46f6f1849bc07ceb /tests | |
parent | 3f17c7c68157ec04b98cb5fd61216a6644aa3a7c (diff) | |
parent | 307437b1b401aa3bfd8f911c150a825476d06d9c (diff) | |
download | cryptography-5ff316753118ac1445858a111c8d76da1c7c3e40.tar.gz cryptography-5ff316753118ac1445858a111c8d76da1c7c3e40.tar.bz2 cryptography-5ff316753118ac1445858a111c8d76da1c7c3e40.zip |
Merge branch 'master' into urandom-engine
* master: (108 commits)
PBKDF2HMAC requires a PBKDF2HMACBackend provider.
one more replacement
simplify hmac supported and hash supported calls for commoncrypto
simplify check for algorithm
a bit more language work + changelog changes for pbkdf2hmac
one more style fix
a few typo fixes, capitalization, etc
switch to private attributes in pbkdf2hmac
expand docs to talk more about the purposes of KDFs
update docs re: PBKDF2HMAC iterations
add test for null char replacement
Added installation section to index.rst
called -> used
quotes inside, diff examples
Expose this method because probably someone will need it eventually
fix spacing, remove versionadded since HashAlgorithm was in 0.1
document HashAlgorithm
Added canonical installation document with details about various platforms, fixes #519
update docs for pbkdf2
Add bindings for X509_REQ_get_extensions.
...
Conflicts:
cryptography/hazmat/bindings/openssl/binding.py
docs/hazmat/backends/openssl.rst
Diffstat (limited to 'tests')
-rw-r--r-- | tests/conftest.py | 3 | ||||
-rw-r--r-- | tests/hazmat/backends/test_commoncrypto.py | 65 | ||||
-rw-r--r-- | tests/hazmat/backends/test_openssl.py | 10 | ||||
-rw-r--r-- | tests/hazmat/bindings/test_openssl.py | 73 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_pbkdf2hmac.py | 69 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_pbkdf2hmac_vectors.py | 37 | ||||
-rw-r--r-- | tests/hazmat/primitives/utils.py | 32 | ||||
-rw-r--r-- | tests/hazmat/primitives/vectors/KDF/rfc-5869-HKDF-SHA1.txt | 56 | ||||
-rw-r--r-- | tests/hazmat/primitives/vectors/KDF/rfc-5869-HKDF-SHA256.txt | 40 | ||||
-rw-r--r-- | tests/hazmat/primitives/vectors/KDF/rfc-6070-PBKDF2-SHA1.txt | 48 | ||||
-rw-r--r-- | tests/test_utils.py | 19 | ||||
-rw-r--r-- | tests/utils.py | 27 |
12 files changed, 458 insertions, 21 deletions
diff --git a/tests/conftest.py b/tests/conftest.py index a9acb54a..ecad1b23 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,7 @@ import pytest from cryptography.hazmat.backends import _ALL_BACKENDS from cryptography.hazmat.backends.interfaces import ( - HMACBackend, CipherBackend, HashBackend + HMACBackend, CipherBackend, HashBackend, PBKDF2HMACBackend ) from .utils import check_for_iface, check_backend_support, select_backends @@ -21,6 +21,7 @@ def pytest_runtest_setup(item): check_for_iface("hmac", HMACBackend, item) check_for_iface("cipher", CipherBackend, item) check_for_iface("hash", HashBackend, item) + check_for_iface("pbkdf2hmac", PBKDF2HMACBackend, item) check_backend_support(item) diff --git a/tests/hazmat/backends/test_commoncrypto.py b/tests/hazmat/backends/test_commoncrypto.py new file mode 100644 index 00000000..7cc0f72f --- /dev/null +++ b/tests/hazmat/backends/test_commoncrypto.py @@ -0,0 +1,65 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm, InternalError +from cryptography.hazmat.bindings.commoncrypto.binding import Binding +from cryptography.hazmat.primitives import interfaces +from cryptography.hazmat.primitives.ciphers.algorithms import AES +from cryptography.hazmat.primitives.ciphers.base import Cipher +from cryptography.hazmat.primitives.ciphers.modes import CBC, GCM + + +@utils.register_interface(interfaces.CipherAlgorithm) +class DummyCipher(object): + name = "dummy-cipher" + block_size = 128 + + +@pytest.mark.skipif(not Binding.is_available(), + reason="CommonCrypto not available") +class TestCommonCrypto(object): + def test_supports_cipher(self): + from cryptography.hazmat.backends.commoncrypto.backend import backend + assert backend.cipher_supported(None, None) is False + + def test_register_duplicate_cipher_adapter(self): + from cryptography.hazmat.backends.commoncrypto.backend import backend + with pytest.raises(ValueError): + backend._register_cipher_adapter( + AES, backend._lib.kCCAlgorithmAES128, + CBC, backend._lib.kCCModeCBC + ) + + def test_handle_response(self): + from cryptography.hazmat.backends.commoncrypto.backend import backend + + with pytest.raises(ValueError): + backend._check_response(backend._lib.kCCAlignmentError) + + with pytest.raises(InternalError): + backend._check_response(backend._lib.kCCMemoryFailure) + + with pytest.raises(InternalError): + backend._check_response(backend._lib.kCCDecodeError) + + def test_nonexistent_aead_cipher(self): + from cryptography.hazmat.backends.commoncrypto.backend import Backend + b = Backend() + cipher = Cipher( + DummyCipher(), GCM(b"fake_iv_here"), backend=b, + ) + with pytest.raises(UnsupportedAlgorithm): + cipher.encryptor() diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 51eb408f..e527ed19 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -16,7 +16,7 @@ import cffi import pytest from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.exceptions import UnsupportedAlgorithm, InternalError from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends.openssl.backend import backend, Backend from cryptography.hazmat.primitives import interfaces @@ -168,20 +168,20 @@ class TestOpenSSL(object): cipher.encryptor() def test_handle_unknown_error(self): - with pytest.raises(SystemError): + with pytest.raises(InternalError): backend._handle_error_code(0, 0, 0) - with pytest.raises(SystemError): + with pytest.raises(InternalError): backend._handle_error_code(backend._lib.ERR_LIB_EVP, 0, 0) - with pytest.raises(SystemError): + with pytest.raises(InternalError): backend._handle_error_code( backend._lib.ERR_LIB_EVP, backend._lib.EVP_F_EVP_ENCRYPTFINAL_EX, 0 ) - with pytest.raises(SystemError): + with pytest.raises(InternalError): backend._handle_error_code( backend._lib.ERR_LIB_EVP, backend._lib.EVP_F_EVP_DECRYPTFINAL_EX, diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index d1e85058..35eb7e8d 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + from cryptography.hazmat.bindings.openssl.binding import Binding @@ -23,3 +25,74 @@ class TestOpenSSL(object): def test_is_available(self): assert Binding.is_available() is True + + def test_crypto_lock_init(self): + b = Binding() + b.init_static_locks() + lock_cb = b.lib.CRYPTO_get_locking_callback() + assert lock_cb != b.ffi.NULL + + def _skip_if_not_fallback_lock(self, b): + # only run this test if we are using our locking cb + original_cb = b.lib.CRYPTO_get_locking_callback() + if original_cb != b._lock_cb_handle: + pytest.skip( + "Not using the fallback Python locking callback " + "implementation. Probably because import _ssl set one" + ) + + def test_fallback_crypto_lock_via_openssl_api(self): + b = Binding() + b.init_static_locks() + + self._skip_if_not_fallback_lock(b) + + # check that the lock state changes appropriately + lock = b._locks[b.lib.CRYPTO_LOCK_SSL] + + # starts out unlocked + assert lock.acquire(False) + lock.release() + + b.lib.CRYPTO_lock( + b.lib.CRYPTO_LOCK | b.lib.CRYPTO_READ, + b.lib.CRYPTO_LOCK_SSL, b.ffi.NULL, 0 + ) + + # becomes locked + assert not lock.acquire(False) + + b.lib.CRYPTO_lock( + b.lib.CRYPTO_UNLOCK | b.lib.CRYPTO_READ, + b.lib.CRYPTO_LOCK_SSL, b.ffi.NULL, 0 + ) + + # then unlocked + assert lock.acquire(False) + lock.release() + + def test_fallback_crypto_lock_via_binding_api(self): + b = Binding() + b.init_static_locks() + + self._skip_if_not_fallback_lock(b) + + lock = b._locks[b.lib.CRYPTO_LOCK_SSL] + + with pytest.raises(RuntimeError): + b._lock_cb(0, b.lib.CRYPTO_LOCK_SSL, "<test>", 1) + + # errors shouldnt cause locking + assert lock.acquire(False) + lock.release() + + b._lock_cb(b.lib.CRYPTO_LOCK | b.lib.CRYPTO_READ, + b.lib.CRYPTO_LOCK_SSL, "<test>", 1) + # locked + assert not lock.acquire(False) + + b._lock_cb(b.lib.CRYPTO_UNLOCK | b.lib.CRYPTO_READ, + b.lib.CRYPTO_LOCK_SSL, "<test>", 1) + # unlocked + assert lock.acquire(False) + lock.release() diff --git a/tests/hazmat/primitives/test_pbkdf2hmac.py b/tests/hazmat/primitives/test_pbkdf2hmac.py new file mode 100644 index 00000000..6ad225a8 --- /dev/null +++ b/tests/hazmat/primitives/test_pbkdf2hmac.py @@ -0,0 +1,69 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import, division, print_function + +import pytest +import six + +from cryptography import utils +from cryptography.exceptions import ( + InvalidKey, UnsupportedAlgorithm, AlreadyFinalized +) +from cryptography.hazmat.primitives import hashes, interfaces +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC +from cryptography.hazmat.backends import default_backend + + +@utils.register_interface(interfaces.HashAlgorithm) +class DummyHash(object): + name = "dummy-hash" + + +class TestPBKDF2HMAC(object): + def test_already_finalized(self): + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + kdf.derive(b"password") + with pytest.raises(AlreadyFinalized): + kdf.derive(b"password2") + + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + key = kdf.derive(b"password") + with pytest.raises(AlreadyFinalized): + kdf.verify(b"password", key) + + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + kdf.verify(b"password", key) + with pytest.raises(AlreadyFinalized): + kdf.verify(b"password", key) + + def test_unsupported_algorithm(self): + with pytest.raises(UnsupportedAlgorithm): + PBKDF2HMAC(DummyHash(), 20, b"salt", 10, default_backend()) + + def test_invalid_key(self): + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + key = kdf.derive(b"password") + + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + with pytest.raises(InvalidKey): + kdf.verify(b"password2", key) + + def test_unicode_error_with_salt(self): + with pytest.raises(TypeError): + PBKDF2HMAC(hashes.SHA1(), 20, six.u("salt"), 10, default_backend()) + + def test_unicode_error_with_key_material(self): + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + with pytest.raises(TypeError): + kdf.derive(six.u("unicode here")) diff --git a/tests/hazmat/primitives/test_pbkdf2hmac_vectors.py b/tests/hazmat/primitives/test_pbkdf2hmac_vectors.py new file mode 100644 index 00000000..cbd4cc9d --- /dev/null +++ b/tests/hazmat/primitives/test_pbkdf2hmac_vectors.py @@ -0,0 +1,37 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import, division, print_function + +import pytest + +from cryptography.hazmat.primitives import hashes + +from .utils import generate_pbkdf2_test +from ...utils import load_nist_vectors + + +@pytest.mark.supported( + only_if=lambda backend: backend.pbkdf2_hmac_supported(hashes.SHA1()), + skip_message="Does not support SHA1 for PBKDF2HMAC", +) +@pytest.mark.pbkdf2hmac +class TestPBKDF2HMAC_SHA1(object): + test_pbkdf2_sha1 = generate_pbkdf2_test( + load_nist_vectors, + "KDF", + [ + "rfc-6070-PBKDF2-SHA1.txt", + ], + hashes.SHA1(), + ) diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 6ecc70ff..6b1d055d 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -4,6 +4,7 @@ import os import pytest from cryptography.hazmat.primitives import hashes, hmac +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.exceptions import ( AlreadyFinalized, NotYetFinalized, AlreadyUpdated, InvalidTag, @@ -141,8 +142,7 @@ def generate_hash_test(param_loader, path, file_names, hash_cls): def hash_test(backend, algorithm, params): - msg = params[0] - md = params[1] + msg, md = params m = hashes.Hash(algorithm, backend=backend) m.update(binascii.unhexlify(msg)) expected_md = md.replace(" ", "").lower().encode("ascii") @@ -206,14 +206,36 @@ def generate_hmac_test(param_loader, path, file_names, algorithm): def hmac_test(backend, algorithm, params): - msg = params[0] - md = params[1] - key = params[2] + msg, md, key = params h = hmac.HMAC(binascii.unhexlify(key), algorithm, backend=backend) h.update(binascii.unhexlify(msg)) assert h.finalize() == binascii.unhexlify(md.encode("ascii")) +def generate_pbkdf2_test(param_loader, path, file_names, algorithm): + all_params = _load_all_params(path, file_names, param_loader) + + @pytest.mark.parametrize("params", all_params) + def test_pbkdf2(self, backend, params): + pbkdf2_test(backend, algorithm, params) + return test_pbkdf2 + + +def pbkdf2_test(backend, algorithm, params): + # Password and salt can contain \0, which should be loaded as a null char. + # The NIST loader loads them as literal strings so we replace with the + # proper value. + kdf = PBKDF2HMAC( + algorithm, + int(params["length"]), + params["salt"], + int(params["iterations"]), + backend + ) + derived_key = kdf.derive(params["password"]) + assert binascii.hexlify(derived_key) == params["derived_key"] + + def generate_aead_exception_test(cipher_factory, mode_factory): def test_aead_exception(self, backend): aead_exception_test(backend, cipher_factory, mode_factory) diff --git a/tests/hazmat/primitives/vectors/KDF/rfc-5869-HKDF-SHA1.txt b/tests/hazmat/primitives/vectors/KDF/rfc-5869-HKDF-SHA1.txt new file mode 100644 index 00000000..b3fd03aa --- /dev/null +++ b/tests/hazmat/primitives/vectors/KDF/rfc-5869-HKDF-SHA1.txt @@ -0,0 +1,56 @@ +# A.4. Test Case 4 +# Basic test case with SHA-1 + +COUNT = 4 + +Hash = SHA-1 +IKM = 0b0b0b0b0b0b0b0b0b0b0b +salt = 000102030405060708090a0b0c +info = f0f1f2f3f4f5f6f7f8f9 +L = 42 + +PRK = 9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243 +OKM = 085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896 + +# A.5. Test Case 5 +# Test with SHA-1 and longer inputs/outputs + +COUNT = 5 + +Hash = SHA-1 +IKM = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f +salt = 606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf +info = b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff +L = 82 + +PRK = 8adae09a2a307059478d309b26c4115a224cfaf6 +OKM = 0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4 + +# A.6. Test Case 6 +# Test with SHA-1 and zero-length salt/info + +COUNT = 6 + +Hash = SHA-1 +IKM = 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b +salt = +info = +L = 42 + +PRK = da8c8a73c7fa77288ec6f5e7c297786aa0d32d01 +OKM = 0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918 + +# A.7. Test Case 7 +# Test with SHA-1, salt not provided (defaults to HashLen zero octets), +# zero-length info + +COUNT = 7 + +Hash = SHA-1 +IKM = 0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c +salt = +info = +L = 42 + +PRK = 2adccada18779e7c2077ad2eb19d3f3e731385dd +OKM = 2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48 diff --git a/tests/hazmat/primitives/vectors/KDF/rfc-5869-HKDF-SHA256.txt b/tests/hazmat/primitives/vectors/KDF/rfc-5869-HKDF-SHA256.txt new file mode 100644 index 00000000..9068a739 --- /dev/null +++ b/tests/hazmat/primitives/vectors/KDF/rfc-5869-HKDF-SHA256.txt @@ -0,0 +1,40 @@ +# A.1. Test Case 1 +# Basic test case with SHA-256 + +COUNT = 1 + +Hash = SHA-256 +IKM = 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b +salt = 000102030405060708090a0b0c +info = f0f1f2f3f4f5f6f7f8f9 +L = 42 +PRK = 077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5 +OKM = 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865 + +# A.2. Test Case 2 +# Test with SHA-256 and longer inputs/outputs + +COUNT = 2 + +Hash = SHA-256 +IKM = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f +salt = 606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf +info = b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff +L = 82 + +PRK = 06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244 +OKM = b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87 + +# A.3. Test Case 3 +# Test with SHA-256 and zero-length salt/info + +COUNT = 3 + +Hash = SHA-256 +IKM = 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b +salt = +info = +L = 42 + +PRK = 19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04 +OKM = 8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8 diff --git a/tests/hazmat/primitives/vectors/KDF/rfc-6070-PBKDF2-SHA1.txt b/tests/hazmat/primitives/vectors/KDF/rfc-6070-PBKDF2-SHA1.txt new file mode 100644 index 00000000..739f3f36 --- /dev/null +++ b/tests/hazmat/primitives/vectors/KDF/rfc-6070-PBKDF2-SHA1.txt @@ -0,0 +1,48 @@ +# PBKDF2 SHA1 vectors from http://www.ietf.org/rfc/rfc6070.txt + +COUNT = 0 +PASSWORD = password +SALT = salt +ITERATIONS = 1 +LENGTH = 20 +DERIVED_KEY = 0c60c80f961f0e71f3a9b524af6012062fe037a6 + + +COUNT = 1 +PASSWORD = password +SALT = salt +ITERATIONS = 2 +LENGTH = 20 +DERIVED_KEY = ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957 + + +COUNT = 2 +PASSWORD = password +SALT = salt +ITERATIONS = 4096 +LENGTH = 20 +DERIVED_KEY = 4b007901b765489abead49d926f721d065a429c1 + + +COUNT = 3 +PASSWORD = password +SALT = salt +ITERATIONS = 16777216 +LENGTH = 20 +DERIVED_KEY = eefe3d61cd4da4e4e9945b3d6ba2158c2634e984 + + +COUNT = 4 +PASSWORD = passwordPASSWORDpassword +SALT = saltSALTsaltSALTsaltSALTsaltSALTsalt +ITERATIONS = 4096 +LENGTH = 25 +DERIVED_KEY = 3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038 + + +COUNT = 5 +PASSWORD = pass\0word +SALT = sa\0lt +ITERATIONS = 4096 +LENGTH = 16 +DERIVED_KEY = 56fa6aa75548099dcc37d7f03425e0c3 diff --git a/tests/test_utils.py b/tests/test_utils.py index f852f3ab..8ecb33f9 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -180,6 +180,25 @@ def test_load_nist_vectors(): ] +def test_load_nist_vectors_with_null_chars(): + vector_data = textwrap.dedent(""" + COUNT = 0 + KEY = thing\\0withnulls + + COUNT = 1 + KEY = 00000000000000000000000000000000 + """).splitlines() + + assert load_nist_vectors(vector_data) == [ + { + "key": b"thing\x00withnulls", + }, + { + "key": b"00000000000000000000000000000000", + }, + ] + + def test_load_cryptrec_vectors(): vector_data = textwrap.dedent(""" # Vectors taken from http://info.isl.ntt.co.jp/crypt/eng/camellia/ diff --git a/tests/utils.py b/tests/utils.py index a2432256..5c0e524f 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -11,11 +11,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +import collections import os import pytest +HashVector = collections.namedtuple("HashVector", ["message", "digest"]) +KeyedHashVector = collections.namedtuple( + "KeyedHashVector", ["message", "digest", "key"] +) + + def select_backends(names, backend_list): if names is None: return backend_list @@ -82,6 +89,10 @@ def load_nist_vectors(vector_data): # Build our data using a simple Key = Value format name, value = [c.strip() for c in line.split("=")] + # Some tests (PBKDF2) contain \0, which should be interpreted as a + # null character rather than literal. + value = value.replace("\\0", "\0") + # COUNT is a special token that indicates a new block of data if name.upper() == "COUNT": test_data = {} @@ -158,27 +169,23 @@ def load_hash_vectors(vector_data): if line.startswith("Len"): length = int(line.split(" = ")[1]) elif line.startswith("Key"): - """ - HMAC vectors contain a key attribute. Hash vectors do not. - """ + # HMAC vectors contain a key attribute. Hash vectors do not. key = line.split(" = ")[1].encode("ascii") elif line.startswith("Msg"): - """ - In the NIST vectors they have chosen to represent an empty - string as hex 00, which is of course not actually an empty - string. So we parse the provided length and catch this edge case. - """ + # In the NIST vectors they have chosen to represent an empty + # string as hex 00, which is of course not actually an empty + # string. So we parse the provided length and catch this edge case. msg = line.split(" = ")[1].encode("ascii") if length > 0 else b"" elif line.startswith("MD"): md = line.split(" = ")[1] # after MD is found the Msg+MD (+ potential key) tuple is complete if key is not None: - vectors.append((msg, md, key)) + vectors.append(KeyedHashVector(msg, md, key)) key = None msg = None md = None else: - vectors.append((msg, md)) + vectors.append(HashVector(msg, md)) msg = None md = None else: |