Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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 

5import abc 

6import typing 

7 

8from cryptography import utils 

9from cryptography.exceptions import ( 

10 AlreadyFinalized, 

11 UnsupportedAlgorithm, 

12 _Reasons, 

13) 

14from cryptography.hazmat.backends import _get_backend 

15from cryptography.hazmat.backends.interfaces import HashBackend 

16 

17 

18class HashAlgorithm(metaclass=abc.ABCMeta): 

19 @abc.abstractproperty 

20 def name(self) -> str: 

21 """ 

22 A string naming this algorithm (e.g. "sha256", "md5"). 

23 """ 

24 

25 @abc.abstractproperty 

26 def digest_size(self) -> int: 

27 """ 

28 The size of the resulting digest in bytes. 

29 """ 

30 

31 @abc.abstractproperty 

32 def block_size(self) -> typing.Optional[int]: 

33 """ 

34 The internal block size of the hash function, or None if the hash 

35 function does not use blocks internally (e.g. SHA3). 

36 """ 

37 

38 

39class HashContext(metaclass=abc.ABCMeta): 

40 @abc.abstractproperty 

41 def algorithm(self) -> HashAlgorithm: 

42 """ 

43 A HashAlgorithm that will be used by this context. 

44 """ 

45 

46 @abc.abstractmethod 

47 def update(self, data: bytes) -> None: 

48 """ 

49 Processes the provided bytes through the hash. 

50 """ 

51 

52 @abc.abstractmethod 

53 def finalize(self) -> bytes: 

54 """ 

55 Finalizes the hash context and returns the hash digest as bytes. 

56 """ 

57 

58 @abc.abstractmethod 

59 def copy(self) -> "HashContext": 

60 """ 

61 Return a HashContext that is a copy of the current context. 

62 """ 

63 

64 

65class ExtendableOutputFunction(metaclass=abc.ABCMeta): 

66 """ 

67 An interface for extendable output functions. 

68 """ 

69 

70 

71class Hash(HashContext): 

72 def __init__(self, algorithm: HashAlgorithm, backend=None, ctx=None): 

73 backend = _get_backend(backend) 

74 if not isinstance(backend, HashBackend): 

75 raise UnsupportedAlgorithm( 

76 "Backend object does not implement HashBackend.", 

77 _Reasons.BACKEND_MISSING_INTERFACE, 

78 ) 

79 

80 if not isinstance(algorithm, HashAlgorithm): 

81 raise TypeError("Expected instance of hashes.HashAlgorithm.") 

82 self._algorithm = algorithm 

83 

84 self._backend = backend 

85 

86 if ctx is None: 

87 self._ctx = self._backend.create_hash_ctx(self.algorithm) 

88 else: 

89 self._ctx = ctx 

90 

91 algorithm = utils.read_only_property("_algorithm") 

92 

93 def update(self, data: bytes) -> None: 

94 if self._ctx is None: 

95 raise AlreadyFinalized("Context was already finalized.") 

96 utils._check_byteslike("data", data) 

97 self._ctx.update(data) 

98 

99 def copy(self) -> "Hash": 

100 if self._ctx is None: 

101 raise AlreadyFinalized("Context was already finalized.") 

102 return Hash( 

103 self.algorithm, backend=self._backend, ctx=self._ctx.copy() 

104 ) 

105 

106 def finalize(self) -> bytes: 

107 if self._ctx is None: 

108 raise AlreadyFinalized("Context was already finalized.") 

109 digest = self._ctx.finalize() 

110 self._ctx = None 

111 return digest 

112 

113 

114class SHA1(HashAlgorithm): 

115 name = "sha1" 

116 digest_size = 20 

117 block_size = 64 

118 

119 

120class SHA512_224(HashAlgorithm): # noqa: N801 

121 name = "sha512-224" 

122 digest_size = 28 

123 block_size = 128 

124 

125 

126class SHA512_256(HashAlgorithm): # noqa: N801 

127 name = "sha512-256" 

128 digest_size = 32 

129 block_size = 128 

130 

131 

132class SHA224(HashAlgorithm): 

133 name = "sha224" 

134 digest_size = 28 

135 block_size = 64 

136 

137 

138class SHA256(HashAlgorithm): 

139 name = "sha256" 

140 digest_size = 32 

141 block_size = 64 

142 

143 

144class SHA384(HashAlgorithm): 

145 name = "sha384" 

146 digest_size = 48 

147 block_size = 128 

148 

149 

150class SHA512(HashAlgorithm): 

151 name = "sha512" 

152 digest_size = 64 

153 block_size = 128 

154 

155 

156class SHA3_224(HashAlgorithm): # noqa: N801 

157 name = "sha3-224" 

158 digest_size = 28 

159 block_size = None 

160 

161 

162class SHA3_256(HashAlgorithm): # noqa: N801 

163 name = "sha3-256" 

164 digest_size = 32 

165 block_size = None 

166 

167 

168class SHA3_384(HashAlgorithm): # noqa: N801 

169 name = "sha3-384" 

170 digest_size = 48 

171 block_size = None 

172 

173 

174class SHA3_512(HashAlgorithm): # noqa: N801 

175 name = "sha3-512" 

176 digest_size = 64 

177 block_size = None 

178 

179 

180class SHAKE128(HashAlgorithm, ExtendableOutputFunction): 

181 name = "shake128" 

182 block_size = None 

183 

184 def __init__(self, digest_size: int): 

185 if not isinstance(digest_size, int): 

186 raise TypeError("digest_size must be an integer") 

187 

188 if digest_size < 1: 

189 raise ValueError("digest_size must be a positive integer") 

190 

191 self._digest_size = digest_size 

192 

193 digest_size = utils.read_only_property("_digest_size") 

194 

195 

196class SHAKE256(HashAlgorithm, ExtendableOutputFunction): 

197 name = "shake256" 

198 block_size = None 

199 

200 def __init__(self, digest_size: int): 

201 if not isinstance(digest_size, int): 

202 raise TypeError("digest_size must be an integer") 

203 

204 if digest_size < 1: 

205 raise ValueError("digest_size must be a positive integer") 

206 

207 self._digest_size = digest_size 

208 

209 digest_size = utils.read_only_property("_digest_size") 

210 

211 

212class MD5(HashAlgorithm): 

213 name = "md5" 

214 digest_size = 16 

215 block_size = 64 

216 

217 

218class BLAKE2b(HashAlgorithm): 

219 name = "blake2b" 

220 _max_digest_size = 64 

221 _min_digest_size = 1 

222 block_size = 128 

223 

224 def __init__(self, digest_size: int): 

225 

226 if digest_size != 64: 

227 raise ValueError("Digest size must be 64") 

228 

229 self._digest_size = digest_size 

230 

231 digest_size = utils.read_only_property("_digest_size") 

232 

233 

234class BLAKE2s(HashAlgorithm): 

235 name = "blake2s" 

236 block_size = 64 

237 _max_digest_size = 32 

238 _min_digest_size = 1 

239 

240 def __init__(self, digest_size: int): 

241 

242 if digest_size != 32: 

243 raise ValueError("Digest size must be 32") 

244 

245 self._digest_size = digest_size 

246 

247 digest_size = utils.read_only_property("_digest_size")