Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py: 85%

55 statements  

« prev     ^ index     » next       coverage.py v7.2.1, created at 2023-03-14 06:36 +0000

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 

5 

6import typing 

7 

8from cryptography import utils 

9from cryptography.exceptions import AlreadyFinalized, InvalidKey 

10from cryptography.hazmat.primitives import constant_time, hashes, hmac 

11from cryptography.hazmat.primitives.kdf import KeyDerivationFunction 

12 

13 

14class HKDF(KeyDerivationFunction): 

15 def __init__( 

16 self, 

17 algorithm: hashes.HashAlgorithm, 

18 length: int, 

19 salt: typing.Optional[bytes], 

20 info: typing.Optional[bytes], 

21 backend: typing.Any = None, 

22 ): 

23 self._algorithm = algorithm 

24 

25 if salt is None: 

26 salt = b"\x00" * self._algorithm.digest_size 

27 else: 

28 utils._check_bytes("salt", salt) 

29 

30 self._salt = salt 

31 

32 self._hkdf_expand = HKDFExpand(self._algorithm, length, info) 

33 

34 def _extract(self, key_material: bytes) -> bytes: 

35 h = hmac.HMAC(self._salt, self._algorithm) 

36 h.update(key_material) 

37 return h.finalize() 

38 

39 def derive(self, key_material: bytes) -> bytes: 

40 utils._check_byteslike("key_material", key_material) 

41 return self._hkdf_expand.derive(self._extract(key_material)) 

42 

43 def verify(self, key_material: bytes, expected_key: bytes) -> None: 

44 if not constant_time.bytes_eq(self.derive(key_material), expected_key): 

45 raise InvalidKey 

46 

47 

48class HKDFExpand(KeyDerivationFunction): 

49 def __init__( 

50 self, 

51 algorithm: hashes.HashAlgorithm, 

52 length: int, 

53 info: typing.Optional[bytes], 

54 backend: typing.Any = None, 

55 ): 

56 self._algorithm = algorithm 

57 

58 max_length = 255 * algorithm.digest_size 

59 

60 if length > max_length: 

61 raise ValueError( 

62 f"Cannot derive keys larger than {max_length} octets." 

63 ) 

64 

65 self._length = length 

66 

67 if info is None: 

68 info = b"" 

69 else: 

70 utils._check_bytes("info", info) 

71 

72 self._info = info 

73 

74 self._used = False 

75 

76 def _expand(self, key_material: bytes) -> bytes: 

77 output = [b""] 

78 counter = 1 

79 

80 while self._algorithm.digest_size * (len(output) - 1) < self._length: 

81 h = hmac.HMAC(key_material, self._algorithm) 

82 h.update(output[-1]) 

83 h.update(self._info) 

84 h.update(bytes([counter])) 

85 output.append(h.finalize()) 

86 counter += 1 

87 

88 return b"".join(output)[: self._length] 

89 

90 def derive(self, key_material: bytes) -> bytes: 

91 utils._check_byteslike("key_material", key_material) 

92 if self._used: 

93 raise AlreadyFinalized 

94 

95 self._used = True 

96 return self._expand(key_material) 

97 

98 def verify(self, key_material: bytes, expected_key: bytes) -> None: 

99 if not constant_time.bytes_eq(self.derive(key_material), expected_key): 

100 raise InvalidKey