x963kdf.py 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. import typing
  5. from cryptography import utils
  6. from cryptography.exceptions import (
  7. AlreadyFinalized,
  8. InvalidKey,
  9. )
  10. from cryptography.hazmat.primitives import constant_time, hashes
  11. from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
  12. def _int_to_u32be(n: int) -> bytes:
  13. return n.to_bytes(length=4, byteorder="big")
  14. class X963KDF(KeyDerivationFunction):
  15. def __init__(
  16. self,
  17. algorithm: hashes.HashAlgorithm,
  18. length: int,
  19. sharedinfo: typing.Optional[bytes],
  20. backend: typing.Any = None,
  21. ):
  22. max_len = algorithm.digest_size * (2**32 - 1)
  23. if length > max_len:
  24. raise ValueError(
  25. "Cannot derive keys larger than {} bits.".format(max_len)
  26. )
  27. if sharedinfo is not None:
  28. utils._check_bytes("sharedinfo", sharedinfo)
  29. self._algorithm = algorithm
  30. self._length = length
  31. self._sharedinfo = sharedinfo
  32. self._used = False
  33. def derive(self, key_material: bytes) -> bytes:
  34. if self._used:
  35. raise AlreadyFinalized
  36. self._used = True
  37. utils._check_byteslike("key_material", key_material)
  38. output = [b""]
  39. outlen = 0
  40. counter = 1
  41. while self._length > outlen:
  42. h = hashes.Hash(self._algorithm)
  43. h.update(key_material)
  44. h.update(_int_to_u32be(counter))
  45. if self._sharedinfo is not None:
  46. h.update(self._sharedinfo)
  47. output.append(h.finalize())
  48. outlen += len(output[-1])
  49. counter += 1
  50. return b"".join(output)[: self._length]
  51. def verify(self, key_material: bytes, expected_key: bytes) -> None:
  52. if not constant_time.bytes_eq(self.derive(key_material), expected_key):
  53. raise InvalidKey