Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/PyNaCl-1.6.2-py3.11-linux-x86_64.egg/nacl/bindings/crypto_pwhash.py: 67%

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

188 statements  

1# Copyright 2013 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. 

14 

15from __future__ import annotations 

16 

17import sys 

18 

19import nacl.exceptions as exc 

20from nacl._sodium import ffi, lib 

21from nacl.exceptions import ensure 

22 

23has_crypto_pwhash_scryptsalsa208sha256 = bool( 

24 lib.PYNACL_HAS_CRYPTO_PWHASH_SCRYPTSALSA208SHA256 

25) 

26 

27crypto_pwhash_scryptsalsa208sha256_STRPREFIX = b"" 

28crypto_pwhash_scryptsalsa208sha256_SALTBYTES = 0 

29crypto_pwhash_scryptsalsa208sha256_STRBYTES = 0 

30crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN = 0 

31crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX = 0 

32crypto_pwhash_scryptsalsa208sha256_BYTES_MIN = 0 

33crypto_pwhash_scryptsalsa208sha256_BYTES_MAX = 0 

34crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN = 0 

35crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX = 0 

36crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN = 0 

37crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX = 0 

38crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE = 0 

39crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE = 0 

40crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE = 0 

41crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE = 0 

42 

43if has_crypto_pwhash_scryptsalsa208sha256: 

44 crypto_pwhash_scryptsalsa208sha256_STRPREFIX = ffi.string( 

45 ffi.cast("char *", lib.crypto_pwhash_scryptsalsa208sha256_strprefix()) 

46 )[:] 

47 crypto_pwhash_scryptsalsa208sha256_SALTBYTES = ( 

48 lib.crypto_pwhash_scryptsalsa208sha256_saltbytes() 

49 ) 

50 crypto_pwhash_scryptsalsa208sha256_STRBYTES = ( 

51 lib.crypto_pwhash_scryptsalsa208sha256_strbytes() 

52 ) 

53 crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN = ( 

54 lib.crypto_pwhash_scryptsalsa208sha256_passwd_min() 

55 ) 

56 crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX = ( 

57 lib.crypto_pwhash_scryptsalsa208sha256_passwd_max() 

58 ) 

59 crypto_pwhash_scryptsalsa208sha256_BYTES_MIN = ( 

60 lib.crypto_pwhash_scryptsalsa208sha256_bytes_min() 

61 ) 

62 crypto_pwhash_scryptsalsa208sha256_BYTES_MAX = ( 

63 lib.crypto_pwhash_scryptsalsa208sha256_bytes_max() 

64 ) 

65 crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN = ( 

66 lib.crypto_pwhash_scryptsalsa208sha256_memlimit_min() 

67 ) 

68 crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX = ( 

69 lib.crypto_pwhash_scryptsalsa208sha256_memlimit_max() 

70 ) 

71 crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN = ( 

72 lib.crypto_pwhash_scryptsalsa208sha256_opslimit_min() 

73 ) 

74 crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX = ( 

75 lib.crypto_pwhash_scryptsalsa208sha256_opslimit_max() 

76 ) 

77 crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE = ( 

78 lib.crypto_pwhash_scryptsalsa208sha256_opslimit_interactive() 

79 ) 

80 crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE = ( 

81 lib.crypto_pwhash_scryptsalsa208sha256_memlimit_interactive() 

82 ) 

83 crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE = ( 

84 lib.crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive() 

85 ) 

86 crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE = ( 

87 lib.crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive() 

88 ) 

89 

90crypto_pwhash_ALG_ARGON2I13: int = lib.crypto_pwhash_alg_argon2i13() 

91crypto_pwhash_ALG_ARGON2ID13: int = lib.crypto_pwhash_alg_argon2id13() 

92crypto_pwhash_ALG_DEFAULT: int = lib.crypto_pwhash_alg_default() 

93 

94crypto_pwhash_SALTBYTES: int = lib.crypto_pwhash_saltbytes() 

95crypto_pwhash_STRBYTES: int = lib.crypto_pwhash_strbytes() 

96 

97crypto_pwhash_PASSWD_MIN: int = lib.crypto_pwhash_passwd_min() 

98crypto_pwhash_PASSWD_MAX: int = lib.crypto_pwhash_passwd_max() 

99crypto_pwhash_BYTES_MIN: int = lib.crypto_pwhash_bytes_min() 

100crypto_pwhash_BYTES_MAX: int = lib.crypto_pwhash_bytes_max() 

101 

102crypto_pwhash_argon2i_STRPREFIX: bytes = ffi.string( 

103 ffi.cast("char *", lib.crypto_pwhash_argon2i_strprefix()) 

104)[:] 

105crypto_pwhash_argon2i_MEMLIMIT_MIN: int = ( 

106 lib.crypto_pwhash_argon2i_memlimit_min() 

107) 

108crypto_pwhash_argon2i_MEMLIMIT_MAX: int = ( 

109 lib.crypto_pwhash_argon2i_memlimit_max() 

110) 

111crypto_pwhash_argon2i_OPSLIMIT_MIN: int = ( 

112 lib.crypto_pwhash_argon2i_opslimit_min() 

113) 

114crypto_pwhash_argon2i_OPSLIMIT_MAX: int = ( 

115 lib.crypto_pwhash_argon2i_opslimit_max() 

116) 

117crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE: int = ( 

118 lib.crypto_pwhash_argon2i_opslimit_interactive() 

119) 

120crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE: int = ( 

121 lib.crypto_pwhash_argon2i_memlimit_interactive() 

122) 

123crypto_pwhash_argon2i_OPSLIMIT_MODERATE: int = ( 

124 lib.crypto_pwhash_argon2i_opslimit_moderate() 

125) 

126crypto_pwhash_argon2i_MEMLIMIT_MODERATE: int = ( 

127 lib.crypto_pwhash_argon2i_memlimit_moderate() 

128) 

129crypto_pwhash_argon2i_OPSLIMIT_SENSITIVE: int = ( 

130 lib.crypto_pwhash_argon2i_opslimit_sensitive() 

131) 

132crypto_pwhash_argon2i_MEMLIMIT_SENSITIVE: int = ( 

133 lib.crypto_pwhash_argon2i_memlimit_sensitive() 

134) 

135 

136crypto_pwhash_argon2id_STRPREFIX: bytes = ffi.string( 

137 ffi.cast("char *", lib.crypto_pwhash_argon2id_strprefix()) 

138)[:] 

139crypto_pwhash_argon2id_MEMLIMIT_MIN: int = ( 

140 lib.crypto_pwhash_argon2id_memlimit_min() 

141) 

142crypto_pwhash_argon2id_MEMLIMIT_MAX: int = ( 

143 lib.crypto_pwhash_argon2id_memlimit_max() 

144) 

145crypto_pwhash_argon2id_OPSLIMIT_MIN: int = ( 

146 lib.crypto_pwhash_argon2id_opslimit_min() 

147) 

148crypto_pwhash_argon2id_OPSLIMIT_MAX: int = ( 

149 lib.crypto_pwhash_argon2id_opslimit_max() 

150) 

151crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE: int = ( 

152 lib.crypto_pwhash_argon2id_opslimit_interactive() 

153) 

154crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE: int = ( 

155 lib.crypto_pwhash_argon2id_memlimit_interactive() 

156) 

157crypto_pwhash_argon2id_OPSLIMIT_MODERATE: int = ( 

158 lib.crypto_pwhash_argon2id_opslimit_moderate() 

159) 

160crypto_pwhash_argon2id_MEMLIMIT_MODERATE: int = ( 

161 lib.crypto_pwhash_argon2id_memlimit_moderate() 

162) 

163crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE: int = ( 

164 lib.crypto_pwhash_argon2id_opslimit_sensitive() 

165) 

166crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE: int = ( 

167 lib.crypto_pwhash_argon2id_memlimit_sensitive() 

168) 

169 

170SCRYPT_OPSLIMIT_INTERACTIVE = ( 

171 crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE 

172) 

173SCRYPT_MEMLIMIT_INTERACTIVE = ( 

174 crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE 

175) 

176SCRYPT_OPSLIMIT_SENSITIVE = ( 

177 crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 

178) 

179SCRYPT_MEMLIMIT_SENSITIVE = ( 

180 crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 

181) 

182SCRYPT_SALTBYTES = crypto_pwhash_scryptsalsa208sha256_SALTBYTES 

183SCRYPT_STRBYTES = crypto_pwhash_scryptsalsa208sha256_STRBYTES 

184 

185SCRYPT_PR_MAX = (1 << 30) - 1 

186LOG2_UINT64_MAX = 63 

187UINT64_MAX = (1 << 64) - 1 

188SCRYPT_MAX_MEM = 32 * (1024 * 1024) 

189 

190 

191def _check_memory_occupation( 

192 n: int, r: int, p: int, maxmem: int = SCRYPT_MAX_MEM 

193) -> None: 

194 ensure(r != 0, "Invalid block size", raising=exc.ValueError) 

195 

196 ensure(p != 0, "Invalid parallelization factor", raising=exc.ValueError) 

197 

198 ensure( 

199 (n & (n - 1)) == 0, 

200 "Cost factor must be a power of 2", 

201 raising=exc.ValueError, 

202 ) 

203 

204 ensure(n > 1, "Cost factor must be at least 2", raising=exc.ValueError) 

205 

206 ensure( 

207 p <= SCRYPT_PR_MAX / r, 

208 f"p*r is greater than {SCRYPT_PR_MAX}", 

209 raising=exc.ValueError, 

210 ) 

211 

212 ensure(n < (1 << (16 * r)), raising=exc.ValueError) 

213 

214 Blen = p * 128 * r 

215 

216 i = UINT64_MAX / 128 

217 

218 ensure(n + 2 <= i / r, raising=exc.ValueError) 

219 

220 Vlen = 32 * r * (n + 2) * 4 

221 

222 ensure(Blen <= UINT64_MAX - Vlen, raising=exc.ValueError) 

223 

224 ensure(Blen <= sys.maxsize - Vlen, raising=exc.ValueError) 

225 

226 ensure( 

227 Blen + Vlen <= maxmem, 

228 "Memory limit would be exceeded with the chosen n, r, p", 

229 raising=exc.ValueError, 

230 ) 

231 

232 

233def nacl_bindings_pick_scrypt_params( 

234 opslimit: int, memlimit: int 

235) -> tuple[int, int, int]: 

236 """Python implementation of libsodium's pickparams""" 

237 

238 opslimit = max(opslimit, 32768) 

239 

240 r = 8 

241 

242 if opslimit < (memlimit // 32): 

243 p = 1 

244 maxn = opslimit // (4 * r) 

245 for n_log2 in range(1, 63): # pragma: no branch 

246 if (2**n_log2) > (maxn // 2): 

247 break 

248 else: 

249 maxn = memlimit // (r * 128) 

250 for n_log2 in range(1, 63): # pragma: no branch 

251 if (2**n_log2) > maxn // 2: 

252 break 

253 

254 maxrp = (opslimit // 4) // (2**n_log2) 

255 

256 maxrp = min(maxrp, 0x3FFFFFFF) 

257 

258 p = maxrp // r 

259 

260 return n_log2, r, p 

261 

262 

263def crypto_pwhash_scryptsalsa208sha256_ll( 

264 passwd: bytes, 

265 salt: bytes, 

266 n: int, 

267 r: int, 

268 p: int, 

269 dklen: int = 64, 

270 maxmem: int = SCRYPT_MAX_MEM, 

271) -> bytes: 

272 """ 

273 Derive a cryptographic key using the ``passwd`` and ``salt`` 

274 given as input. 

275 

276 The work factor can be tuned by by picking different 

277 values for the parameters 

278 

279 :param bytes passwd: 

280 :param bytes salt: 

281 :param bytes salt: *must* be *exactly* :py:const:`.SALTBYTES` long 

282 :param int dklen: 

283 :param int opslimit: 

284 :param int n: 

285 :param int r: block size, 

286 :param int p: the parallelism factor 

287 :param int maxmem: the maximum available memory available for scrypt's 

288 operations 

289 :rtype: bytes 

290 :raises nacl.exceptions.UnavailableError: If called when using a 

291 minimal build of libsodium. 

292 """ 

293 ensure( 

294 has_crypto_pwhash_scryptsalsa208sha256, 

295 "Not available in minimal build", 

296 raising=exc.UnavailableError, 

297 ) 

298 

299 ensure(isinstance(n, int), raising=TypeError) 

300 ensure(isinstance(r, int), raising=TypeError) 

301 ensure(isinstance(p, int), raising=TypeError) 

302 

303 ensure(isinstance(passwd, bytes), raising=TypeError) 

304 ensure(isinstance(salt, bytes), raising=TypeError) 

305 

306 _check_memory_occupation(n, r, p, maxmem) 

307 

308 buf = ffi.new("uint8_t[]", dklen) 

309 

310 ret = lib.crypto_pwhash_scryptsalsa208sha256_ll( 

311 passwd, len(passwd), salt, len(salt), n, r, p, buf, dklen 

312 ) 

313 

314 ensure( 

315 ret == 0, 

316 "Unexpected failure in key derivation", 

317 raising=exc.RuntimeError, 

318 ) 

319 

320 return ffi.buffer(ffi.cast("char *", buf), dklen)[:] 

321 

322 

323def crypto_pwhash_scryptsalsa208sha256_str( 

324 passwd: bytes, 

325 opslimit: int = SCRYPT_OPSLIMIT_INTERACTIVE, 

326 memlimit: int = SCRYPT_MEMLIMIT_INTERACTIVE, 

327) -> bytes: 

328 """ 

329 Derive a cryptographic key using the ``passwd`` and ``salt`` 

330 given as input, returning a string representation which includes 

331 the salt and the tuning parameters. 

332 

333 The returned string can be directly stored as a password hash. 

334 

335 See :py:func:`.crypto_pwhash_scryptsalsa208sha256` for a short 

336 discussion about ``opslimit`` and ``memlimit`` values. 

337 

338 :param bytes passwd: 

339 :param int opslimit: 

340 :param int memlimit: 

341 :return: serialized key hash, including salt and tuning parameters 

342 :rtype: bytes 

343 :raises nacl.exceptions.UnavailableError: If called when using a 

344 minimal build of libsodium. 

345 """ 

346 ensure( 

347 has_crypto_pwhash_scryptsalsa208sha256, 

348 "Not available in minimal build", 

349 raising=exc.UnavailableError, 

350 ) 

351 

352 buf = ffi.new("char[]", SCRYPT_STRBYTES) 

353 

354 ret = lib.crypto_pwhash_scryptsalsa208sha256_str( 

355 buf, passwd, len(passwd), opslimit, memlimit 

356 ) 

357 

358 ensure( 

359 ret == 0, 

360 "Unexpected failure in password hashing", 

361 raising=exc.RuntimeError, 

362 ) 

363 

364 return ffi.string(buf) 

365 

366 

367def crypto_pwhash_scryptsalsa208sha256_str_verify( 

368 passwd_hash: bytes, passwd: bytes 

369) -> bool: 

370 """ 

371 Verifies the ``passwd`` against the ``passwd_hash`` that was generated. 

372 Returns True or False depending on the success 

373 

374 :param passwd_hash: bytes 

375 :param passwd: bytes 

376 :rtype: boolean 

377 :raises nacl.exceptions.UnavailableError: If called when using a 

378 minimal build of libsodium. 

379 """ 

380 ensure( 

381 has_crypto_pwhash_scryptsalsa208sha256, 

382 "Not available in minimal build", 

383 raising=exc.UnavailableError, 

384 ) 

385 

386 ensure( 

387 len(passwd_hash) == SCRYPT_STRBYTES - 1, 

388 "Invalid password hash", 

389 raising=exc.ValueError, 

390 ) 

391 

392 ret = lib.crypto_pwhash_scryptsalsa208sha256_str_verify( 

393 passwd_hash, passwd, len(passwd) 

394 ) 

395 ensure(ret == 0, "Wrong password", raising=exc.InvalidkeyError) 

396 # all went well, therefore: 

397 return True 

398 

399 

400def _check_argon2_limits_alg(opslimit: int, memlimit: int, alg: int) -> None: 

401 if alg == crypto_pwhash_ALG_ARGON2I13: 

402 if memlimit < crypto_pwhash_argon2i_MEMLIMIT_MIN: 

403 raise exc.ValueError( 

404 f"memlimit must be at least {crypto_pwhash_argon2i_MEMLIMIT_MIN} bytes" 

405 ) 

406 elif memlimit > crypto_pwhash_argon2i_MEMLIMIT_MAX: 

407 raise exc.ValueError( 

408 f"memlimit must be at most {crypto_pwhash_argon2i_MEMLIMIT_MAX} bytes" 

409 ) 

410 if opslimit < crypto_pwhash_argon2i_OPSLIMIT_MIN: 

411 raise exc.ValueError( 

412 f"opslimit must be at least {crypto_pwhash_argon2i_OPSLIMIT_MIN}" 

413 ) 

414 elif opslimit > crypto_pwhash_argon2i_OPSLIMIT_MAX: 

415 raise exc.ValueError( 

416 f"opslimit must be at most {crypto_pwhash_argon2i_OPSLIMIT_MAX}" 

417 ) 

418 

419 elif alg == crypto_pwhash_ALG_ARGON2ID13: 

420 if memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN: 

421 raise exc.ValueError( 

422 f"memlimit must be at least {crypto_pwhash_argon2id_MEMLIMIT_MIN} bytes" 

423 ) 

424 elif memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX: 

425 raise exc.ValueError( 

426 f"memlimit must be at most {crypto_pwhash_argon2id_MEMLIMIT_MAX} bytes" 

427 ) 

428 if opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN: 

429 raise exc.ValueError( 

430 f"opslimit must be at least {crypto_pwhash_argon2id_OPSLIMIT_MIN}" 

431 ) 

432 elif opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX: 

433 raise exc.ValueError( 

434 f"opslimit must be at most {crypto_pwhash_argon2id_OPSLIMIT_MAX}" 

435 ) 

436 else: 

437 raise exc.TypeError("Unsupported algorithm") 

438 

439 

440def crypto_pwhash_alg( 

441 outlen: int, 

442 passwd: bytes, 

443 salt: bytes, 

444 opslimit: int, 

445 memlimit: int, 

446 alg: int, 

447) -> bytes: 

448 """ 

449 Derive a raw cryptographic key using the ``passwd`` and the ``salt`` 

450 given as input to the ``alg`` algorithm. 

451 

452 :param outlen: the length of the derived key 

453 :type outlen: int 

454 :param passwd: The input password 

455 :type passwd: bytes 

456 :param salt: 

457 :type salt: bytes 

458 :param opslimit: computational cost 

459 :type opslimit: int 

460 :param memlimit: memory cost 

461 :type memlimit: int 

462 :param alg: algorithm identifier 

463 :type alg: int 

464 :return: derived key 

465 :rtype: bytes 

466 """ 

467 ensure(isinstance(outlen, int), raising=exc.TypeError) 

468 ensure(isinstance(opslimit, int), raising=exc.TypeError) 

469 ensure(isinstance(memlimit, int), raising=exc.TypeError) 

470 ensure(isinstance(alg, int), raising=exc.TypeError) 

471 ensure(isinstance(passwd, bytes), raising=exc.TypeError) 

472 

473 if len(salt) != crypto_pwhash_SALTBYTES: 

474 raise exc.ValueError( 

475 f"salt must be exactly {crypto_pwhash_SALTBYTES} bytes long" 

476 ) 

477 

478 if outlen < crypto_pwhash_BYTES_MIN: 

479 raise exc.ValueError( 

480 f"derived key must be at least {crypto_pwhash_BYTES_MIN} bytes long" 

481 ) 

482 

483 elif outlen > crypto_pwhash_BYTES_MAX: 

484 raise exc.ValueError( 

485 f"derived key must be at most {crypto_pwhash_BYTES_MAX} bytes long" 

486 ) 

487 

488 _check_argon2_limits_alg(opslimit, memlimit, alg) 

489 

490 outbuf = ffi.new("unsigned char[]", outlen) 

491 

492 ret = lib.crypto_pwhash( 

493 outbuf, outlen, passwd, len(passwd), salt, opslimit, memlimit, alg 

494 ) 

495 

496 ensure( 

497 ret == 0, 

498 "Unexpected failure in key derivation", 

499 raising=exc.RuntimeError, 

500 ) 

501 

502 return ffi.buffer(outbuf, outlen)[:] 

503 

504 

505def crypto_pwhash_str_alg( 

506 passwd: bytes, 

507 opslimit: int, 

508 memlimit: int, 

509 alg: int, 

510) -> bytes: 

511 """ 

512 Derive a cryptographic key using the ``passwd`` given as input 

513 and a random salt, returning a string representation which 

514 includes the salt, the tuning parameters and the used algorithm. 

515 

516 :param passwd: The input password 

517 :type passwd: bytes 

518 :param opslimit: computational cost 

519 :type opslimit: int 

520 :param memlimit: memory cost 

521 :type memlimit: int 

522 :param alg: The algorithm to use 

523 :type alg: int 

524 :return: serialized derived key and parameters 

525 :rtype: bytes 

526 """ 

527 ensure(isinstance(opslimit, int), raising=TypeError) 

528 ensure(isinstance(memlimit, int), raising=TypeError) 

529 ensure(isinstance(passwd, bytes), raising=TypeError) 

530 

531 _check_argon2_limits_alg(opslimit, memlimit, alg) 

532 

533 outbuf = ffi.new("char[]", 128) 

534 

535 ret = lib.crypto_pwhash_str_alg( 

536 outbuf, passwd, len(passwd), opslimit, memlimit, alg 

537 ) 

538 

539 ensure( 

540 ret == 0, 

541 "Unexpected failure in key derivation", 

542 raising=exc.RuntimeError, 

543 ) 

544 

545 return ffi.string(outbuf) 

546 

547 

548def crypto_pwhash_str_verify(passwd_hash: bytes, passwd: bytes) -> bool: 

549 """ 

550 Verifies the ``passwd`` against a given password hash. 

551 

552 Returns True on success, raises InvalidkeyError on failure 

553 :param passwd_hash: saved password hash 

554 :type passwd_hash: bytes 

555 :param passwd: password to be checked 

556 :type passwd: bytes 

557 :return: success 

558 :rtype: boolean 

559 """ 

560 ensure(isinstance(passwd_hash, bytes), raising=TypeError) 

561 ensure(isinstance(passwd, bytes), raising=TypeError) 

562 ensure( 

563 len(passwd_hash) <= 127, 

564 "Hash must be at most 127 bytes long", 

565 raising=exc.ValueError, 

566 ) 

567 

568 ret = lib.crypto_pwhash_str_verify(passwd_hash, passwd, len(passwd)) 

569 

570 ensure(ret == 0, "Wrong password", raising=exc.InvalidkeyError) 

571 # all went well, therefore: 

572 return True 

573 

574 

575crypto_pwhash_argon2i_str_verify = crypto_pwhash_str_verify