Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/nacl/bindings/crypto_generichash.py: 38%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

69 statements  

1# Copyright 2013-2019 Donald Stufft and individual contributors 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14from typing import NoReturn, TypeVar 

15 

16from nacl import exceptions as exc 

17from nacl._sodium import ffi, lib 

18from nacl.exceptions import ensure 

19 

20 

21crypto_generichash_BYTES: int = lib.crypto_generichash_blake2b_bytes() 

22crypto_generichash_BYTES_MIN: int = lib.crypto_generichash_blake2b_bytes_min() 

23crypto_generichash_BYTES_MAX: int = lib.crypto_generichash_blake2b_bytes_max() 

24crypto_generichash_KEYBYTES: int = lib.crypto_generichash_blake2b_keybytes() 

25crypto_generichash_KEYBYTES_MIN: int = ( 

26 lib.crypto_generichash_blake2b_keybytes_min() 

27) 

28crypto_generichash_KEYBYTES_MAX: int = ( 

29 lib.crypto_generichash_blake2b_keybytes_max() 

30) 

31crypto_generichash_SALTBYTES: int = lib.crypto_generichash_blake2b_saltbytes() 

32crypto_generichash_PERSONALBYTES: int = ( 

33 lib.crypto_generichash_blake2b_personalbytes() 

34) 

35crypto_generichash_STATEBYTES: int = lib.crypto_generichash_statebytes() 

36 

37_OVERLONG = "{0} length greater than {1} bytes" 

38_TOOBIG = "{0} greater than {1}" 

39 

40 

41def _checkparams( 

42 digest_size: int, key: bytes, salt: bytes, person: bytes 

43) -> None: 

44 """Check hash parameters""" 

45 ensure( 

46 isinstance(key, bytes), 

47 "Key must be a bytes sequence", 

48 raising=exc.TypeError, 

49 ) 

50 

51 ensure( 

52 isinstance(salt, bytes), 

53 "Salt must be a bytes sequence", 

54 raising=exc.TypeError, 

55 ) 

56 

57 ensure( 

58 isinstance(person, bytes), 

59 "Person must be a bytes sequence", 

60 raising=exc.TypeError, 

61 ) 

62 

63 ensure( 

64 isinstance(digest_size, int), 

65 "Digest size must be an integer number", 

66 raising=exc.TypeError, 

67 ) 

68 

69 ensure( 

70 digest_size <= crypto_generichash_BYTES_MAX, 

71 _TOOBIG.format("Digest_size", crypto_generichash_BYTES_MAX), 

72 raising=exc.ValueError, 

73 ) 

74 

75 ensure( 

76 len(key) <= crypto_generichash_KEYBYTES_MAX, 

77 _OVERLONG.format("Key", crypto_generichash_KEYBYTES_MAX), 

78 raising=exc.ValueError, 

79 ) 

80 

81 ensure( 

82 len(salt) <= crypto_generichash_SALTBYTES, 

83 _OVERLONG.format("Salt", crypto_generichash_SALTBYTES), 

84 raising=exc.ValueError, 

85 ) 

86 

87 ensure( 

88 len(person) <= crypto_generichash_PERSONALBYTES, 

89 _OVERLONG.format("Person", crypto_generichash_PERSONALBYTES), 

90 raising=exc.ValueError, 

91 ) 

92 

93 

94def generichash_blake2b_salt_personal( 

95 data: bytes, 

96 digest_size: int = crypto_generichash_BYTES, 

97 key: bytes = b"", 

98 salt: bytes = b"", 

99 person: bytes = b"", 

100) -> bytes: 

101 """One shot hash interface 

102 

103 :param data: the input data to the hash function 

104 :type data: bytes 

105 :param digest_size: must be at most 

106 :py:data:`.crypto_generichash_BYTES_MAX`; 

107 the default digest size is 

108 :py:data:`.crypto_generichash_BYTES` 

109 :type digest_size: int 

110 :param key: must be at most 

111 :py:data:`.crypto_generichash_KEYBYTES_MAX` long 

112 :type key: bytes 

113 :param salt: must be at most 

114 :py:data:`.crypto_generichash_SALTBYTES` long; 

115 will be zero-padded if needed 

116 :type salt: bytes 

117 :param person: must be at most 

118 :py:data:`.crypto_generichash_PERSONALBYTES` long: 

119 will be zero-padded if needed 

120 :type person: bytes 

121 :return: digest_size long digest 

122 :rtype: bytes 

123 """ 

124 

125 _checkparams(digest_size, key, salt, person) 

126 

127 ensure( 

128 isinstance(data, bytes), 

129 "Input data must be a bytes sequence", 

130 raising=exc.TypeError, 

131 ) 

132 

133 digest = ffi.new("unsigned char[]", digest_size) 

134 

135 # both _salt and _personal must be zero-padded to the correct length 

136 _salt = ffi.new("unsigned char []", crypto_generichash_SALTBYTES) 

137 _person = ffi.new("unsigned char []", crypto_generichash_PERSONALBYTES) 

138 

139 ffi.memmove(_salt, salt, len(salt)) 

140 ffi.memmove(_person, person, len(person)) 

141 

142 rc = lib.crypto_generichash_blake2b_salt_personal( 

143 digest, digest_size, data, len(data), key, len(key), _salt, _person 

144 ) 

145 ensure(rc == 0, "Unexpected failure", raising=exc.RuntimeError) 

146 

147 return ffi.buffer(digest, digest_size)[:] 

148 

149 

150_Blake2State = TypeVar("_Blake2State", bound="Blake2State") 

151 

152 

153class Blake2State: 

154 """ 

155 Python-level wrapper for the crypto_generichash_blake2b state buffer 

156 """ 

157 

158 __slots__ = ["_statebuf", "digest_size"] 

159 

160 def __init__(self, digest_size: int): 

161 self._statebuf = ffi.new( 

162 "unsigned char[]", crypto_generichash_STATEBYTES 

163 ) 

164 self.digest_size = digest_size 

165 

166 def __reduce__(self) -> NoReturn: 

167 """ 

168 Raise the same exception as hashlib's blake implementation 

169 on copy.copy() 

170 """ 

171 raise TypeError( 

172 "can't pickle {} objects".format(self.__class__.__name__) 

173 ) 

174 

175 def copy(self: _Blake2State) -> _Blake2State: 

176 _st = self.__class__(self.digest_size) 

177 ffi.memmove( 

178 _st._statebuf, self._statebuf, crypto_generichash_STATEBYTES 

179 ) 

180 return _st 

181 

182 

183def generichash_blake2b_init( 

184 key: bytes = b"", 

185 salt: bytes = b"", 

186 person: bytes = b"", 

187 digest_size: int = crypto_generichash_BYTES, 

188) -> Blake2State: 

189 """ 

190 Create a new initialized blake2b hash state 

191 

192 :param key: must be at most 

193 :py:data:`.crypto_generichash_KEYBYTES_MAX` long 

194 :type key: bytes 

195 :param salt: must be at most 

196 :py:data:`.crypto_generichash_SALTBYTES` long; 

197 will be zero-padded if needed 

198 :type salt: bytes 

199 :param person: must be at most 

200 :py:data:`.crypto_generichash_PERSONALBYTES` long: 

201 will be zero-padded if needed 

202 :type person: bytes 

203 :param digest_size: must be at most 

204 :py:data:`.crypto_generichash_BYTES_MAX`; 

205 the default digest size is 

206 :py:data:`.crypto_generichash_BYTES` 

207 :type digest_size: int 

208 :return: a initialized :py:class:`.Blake2State` 

209 :rtype: object 

210 """ 

211 

212 _checkparams(digest_size, key, salt, person) 

213 

214 state = Blake2State(digest_size) 

215 

216 # both _salt and _personal must be zero-padded to the correct length 

217 _salt = ffi.new("unsigned char []", crypto_generichash_SALTBYTES) 

218 _person = ffi.new("unsigned char []", crypto_generichash_PERSONALBYTES) 

219 

220 ffi.memmove(_salt, salt, len(salt)) 

221 ffi.memmove(_person, person, len(person)) 

222 

223 rc = lib.crypto_generichash_blake2b_init_salt_personal( 

224 state._statebuf, key, len(key), digest_size, _salt, _person 

225 ) 

226 ensure(rc == 0, "Unexpected failure", raising=exc.RuntimeError) 

227 

228 return state 

229 

230 

231def generichash_blake2b_update(state: Blake2State, data: bytes) -> None: 

232 """Update the blake2b hash state 

233 

234 :param state: a initialized Blake2bState object as returned from 

235 :py:func:`.crypto_generichash_blake2b_init` 

236 :type state: :py:class:`.Blake2State` 

237 :param data: 

238 :type data: bytes 

239 """ 

240 

241 ensure( 

242 isinstance(state, Blake2State), 

243 "State must be a Blake2State object", 

244 raising=exc.TypeError, 

245 ) 

246 

247 ensure( 

248 isinstance(data, bytes), 

249 "Input data must be a bytes sequence", 

250 raising=exc.TypeError, 

251 ) 

252 

253 rc = lib.crypto_generichash_blake2b_update( 

254 state._statebuf, data, len(data) 

255 ) 

256 ensure(rc == 0, "Unexpected failure", raising=exc.RuntimeError) 

257 

258 

259def generichash_blake2b_final(state: Blake2State) -> bytes: 

260 """Finalize the blake2b hash state and return the digest. 

261 

262 :param state: a initialized Blake2bState object as returned from 

263 :py:func:`.crypto_generichash_blake2b_init` 

264 :type state: :py:class:`.Blake2State` 

265 :return: the blake2 digest of the passed-in data stream 

266 :rtype: bytes 

267 """ 

268 

269 ensure( 

270 isinstance(state, Blake2State), 

271 "State must be a Blake2State object", 

272 raising=exc.TypeError, 

273 ) 

274 

275 _digest = ffi.new("unsigned char[]", crypto_generichash_BYTES_MAX) 

276 rc = lib.crypto_generichash_blake2b_final( 

277 state._statebuf, _digest, state.digest_size 

278 ) 

279 

280 ensure(rc == 0, "Unexpected failure", raising=exc.RuntimeError) 

281 return ffi.buffer(_digest, state.digest_size)[:]