diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-09-24 19:17:26 -0500 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-09-24 19:17:26 -0500 |
commit | ddc9a581efbc11d9b6ccf74c9bcc11c4318be9ae (patch) | |
tree | 90709d01b4c81fe34f206760a4d7ed7c993d3768 /src | |
parent | 6272e95912ae8dc4eae295cd6bf27e6dfa0bdce9 (diff) | |
parent | 0e1989c211d52b93771db3e48524fc7975f796fa (diff) | |
download | cryptography-ddc9a581efbc11d9b6ccf74c9bcc11c4318be9ae.tar.gz cryptography-ddc9a581efbc11d9b6ccf74c9bcc11c4318be9ae.tar.bz2 cryptography-ddc9a581efbc11d9b6ccf74c9bcc11c4318be9ae.zip |
Merge pull request #2343 from simo5/ANS_X963
Implement ANSI X9.63 KDF
Diffstat (limited to 'src')
-rw-r--r-- | src/cryptography/hazmat/primitives/kdf/x963kdf.py | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/src/cryptography/hazmat/primitives/kdf/x963kdf.py b/src/cryptography/hazmat/primitives/kdf/x963kdf.py new file mode 100644 index 00000000..83789b31 --- /dev/null +++ b/src/cryptography/hazmat/primitives/kdf/x963kdf.py @@ -0,0 +1,70 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import struct + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HashBackend +from cryptography.hazmat.primitives import constant_time, hashes +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +def _int_to_u32be(n): + return struct.pack('>I', n) + + +@utils.register_interface(KeyDerivationFunction) +class X963KDF(object): + def __init__(self, algorithm, length, sharedinfo, backend): + + max_len = algorithm.digest_size * (2 ** 32 - 1) + if length > max_len: + raise ValueError( + "Can not derive keys larger than {0} bits.".format(max_len)) + if not (sharedinfo is None or isinstance(sharedinfo, bytes)): + raise TypeError("sharedinfo must be bytes.") + self._algorithm = algorithm + self._length = length + self._sharedinfo = sharedinfo + + if not isinstance(backend, HashBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HashBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + self._backend = backend + self._used = False + + def derive(self, key_material): + if self._used: + raise AlreadyFinalized + self._used = True + + if not isinstance(key_material, bytes): + raise TypeError("key_material must be bytes.") + + output = [b""] + outlen = 0 + counter = 1 + + while self._length > outlen: + h = hashes.Hash(self._algorithm, self._backend) + h.update(key_material) + h.update(_int_to_u32be(counter)) + if self._sharedinfo is not None: + h.update(self._sharedinfo) + output.append(h.finalize()) + outlen += len(output[-1]) + counter += 1 + + return b"".join(output)[:self._length] + + def verify(self, key_material, expected_key): + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey |