Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/PyNaCl-1.6.0.dev1-py3.8-linux-x86_64.egg/nacl/bindings/crypto_pwhash.py: 68%

187 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-06 06:06 +0000

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 

15import sys 

16from typing import Tuple 

17 

18import nacl.exceptions as exc 

19from nacl._sodium import ffi, lib 

20from nacl.exceptions import ensure 

21 

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 "p*r is greater than {}".format(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 if opslimit < 32768: 

239 opslimit = 32768 

240 

241 r = 8 

242 

243 if opslimit < (memlimit // 32): 

244 p = 1 

245 maxn = opslimit // (4 * r) 

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

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

248 break 

249 else: 

250 maxn = memlimit // (r * 128) 

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

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

253 break 

254 

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

256 

257 if maxrp > 0x3FFFFFFF: # pragma: no cover 

258 maxrp = 0x3FFFFFFF 

259 

260 p = maxrp // r 

261 

262 return n_log2, r, p 

263 

264 

265def crypto_pwhash_scryptsalsa208sha256_ll( 

266 passwd: bytes, 

267 salt: bytes, 

268 n: int, 

269 r: int, 

270 p: int, 

271 dklen: int = 64, 

272 maxmem: int = SCRYPT_MAX_MEM, 

273) -> bytes: 

274 """ 

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

276 given as input. 

277 

278 The work factor can be tuned by by picking different 

279 values for the parameters 

280 

281 :param bytes passwd: 

282 :param bytes salt: 

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

284 :param int dklen: 

285 :param int opslimit: 

286 :param int n: 

287 :param int r: block size, 

288 :param int p: the parallelism factor 

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

290 operations 

291 :rtype: bytes 

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

293 minimal build of libsodium. 

294 """ 

295 ensure( 

296 has_crypto_pwhash_scryptsalsa208sha256, 

297 "Not available in minimal build", 

298 raising=exc.UnavailableError, 

299 ) 

300 

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

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

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

304 

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

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

307 

308 _check_memory_occupation(n, r, p, maxmem) 

309 

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

311 

312 ret = lib.crypto_pwhash_scryptsalsa208sha256_ll( 

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

314 ) 

315 

316 ensure( 

317 ret == 0, 

318 "Unexpected failure in key derivation", 

319 raising=exc.RuntimeError, 

320 ) 

321 

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

323 

324 

325def crypto_pwhash_scryptsalsa208sha256_str( 

326 passwd: bytes, 

327 opslimit: int = SCRYPT_OPSLIMIT_INTERACTIVE, 

328 memlimit: int = SCRYPT_MEMLIMIT_INTERACTIVE, 

329) -> bytes: 

330 """ 

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

332 given as input, returning a string representation which includes 

333 the salt and the tuning parameters. 

334 

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

336 

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

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

339 

340 :param bytes passwd: 

341 :param int opslimit: 

342 :param int memlimit: 

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

344 :rtype: bytes 

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

346 minimal build of libsodium. 

347 """ 

348 ensure( 

349 has_crypto_pwhash_scryptsalsa208sha256, 

350 "Not available in minimal build", 

351 raising=exc.UnavailableError, 

352 ) 

353 

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

355 

356 ret = lib.crypto_pwhash_scryptsalsa208sha256_str( 

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

358 ) 

359 

360 ensure( 

361 ret == 0, 

362 "Unexpected failure in password hashing", 

363 raising=exc.RuntimeError, 

364 ) 

365 

366 return ffi.string(buf) 

367 

368 

369def crypto_pwhash_scryptsalsa208sha256_str_verify( 

370 passwd_hash: bytes, passwd: bytes 

371) -> bool: 

372 """ 

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

374 Returns True or False depending on the success 

375 

376 :param passwd_hash: bytes 

377 :param passwd: bytes 

378 :rtype: boolean 

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

380 minimal build of libsodium. 

381 """ 

382 ensure( 

383 has_crypto_pwhash_scryptsalsa208sha256, 

384 "Not available in minimal build", 

385 raising=exc.UnavailableError, 

386 ) 

387 

388 ensure( 

389 len(passwd_hash) == SCRYPT_STRBYTES - 1, 

390 "Invalid password hash", 

391 raising=exc.ValueError, 

392 ) 

393 

394 ret = lib.crypto_pwhash_scryptsalsa208sha256_str_verify( 

395 passwd_hash, passwd, len(passwd) 

396 ) 

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

398 # all went well, therefore: 

399 return True 

400 

401 

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

403 if alg == crypto_pwhash_ALG_ARGON2I13: 

404 if memlimit < crypto_pwhash_argon2i_MEMLIMIT_MIN: 

405 raise exc.ValueError( 

406 "memlimit must be at least {} bytes".format( 

407 crypto_pwhash_argon2i_MEMLIMIT_MIN 

408 ) 

409 ) 

410 elif memlimit > crypto_pwhash_argon2i_MEMLIMIT_MAX: 

411 raise exc.ValueError( 

412 "memlimit must be at most {} bytes".format( 

413 crypto_pwhash_argon2i_MEMLIMIT_MAX 

414 ) 

415 ) 

416 if opslimit < crypto_pwhash_argon2i_OPSLIMIT_MIN: 

417 raise exc.ValueError( 

418 "opslimit must be at least {}".format( 

419 crypto_pwhash_argon2i_OPSLIMIT_MIN 

420 ) 

421 ) 

422 elif opslimit > crypto_pwhash_argon2i_OPSLIMIT_MAX: 

423 raise exc.ValueError( 

424 "opslimit must be at most {}".format( 

425 crypto_pwhash_argon2i_OPSLIMIT_MAX 

426 ) 

427 ) 

428 

429 elif alg == crypto_pwhash_ALG_ARGON2ID13: 

430 if memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN: 

431 raise exc.ValueError( 

432 "memlimit must be at least {} bytes".format( 

433 crypto_pwhash_argon2id_MEMLIMIT_MIN 

434 ) 

435 ) 

436 elif memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX: 

437 raise exc.ValueError( 

438 "memlimit must be at most {} bytes".format( 

439 crypto_pwhash_argon2id_MEMLIMIT_MAX 

440 ) 

441 ) 

442 if opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN: 

443 raise exc.ValueError( 

444 "opslimit must be at least {}".format( 

445 crypto_pwhash_argon2id_OPSLIMIT_MIN 

446 ) 

447 ) 

448 elif opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX: 

449 raise exc.ValueError( 

450 "opslimit must be at most {}".format( 

451 crypto_pwhash_argon2id_OPSLIMIT_MAX 

452 ) 

453 ) 

454 else: 

455 raise exc.TypeError("Unsupported algorithm") 

456 

457 

458def crypto_pwhash_alg( 

459 outlen: int, 

460 passwd: bytes, 

461 salt: bytes, 

462 opslimit: int, 

463 memlimit: int, 

464 alg: int, 

465) -> bytes: 

466 """ 

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

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

469 

470 :param outlen: the length of the derived key 

471 :type outlen: int 

472 :param passwd: The input password 

473 :type passwd: bytes 

474 :param salt: 

475 :type salt: bytes 

476 :param opslimit: computational cost 

477 :type opslimit: int 

478 :param memlimit: memory cost 

479 :type memlimit: int 

480 :param alg: algorithm identifier 

481 :type alg: int 

482 :return: derived key 

483 :rtype: bytes 

484 """ 

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

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

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

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

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

490 

491 if len(salt) != crypto_pwhash_SALTBYTES: 

492 raise exc.ValueError( 

493 "salt must be exactly {} bytes long".format( 

494 crypto_pwhash_SALTBYTES 

495 ) 

496 ) 

497 

498 if outlen < crypto_pwhash_BYTES_MIN: 

499 raise exc.ValueError( 

500 "derived key must be at least {} bytes long".format( 

501 crypto_pwhash_BYTES_MIN 

502 ) 

503 ) 

504 

505 elif outlen > crypto_pwhash_BYTES_MAX: 

506 raise exc.ValueError( 

507 "derived key must be at most {} bytes long".format( 

508 crypto_pwhash_BYTES_MAX 

509 ) 

510 ) 

511 

512 _check_argon2_limits_alg(opslimit, memlimit, alg) 

513 

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

515 

516 ret = lib.crypto_pwhash( 

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

518 ) 

519 

520 ensure( 

521 ret == 0, 

522 "Unexpected failure in key derivation", 

523 raising=exc.RuntimeError, 

524 ) 

525 

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

527 

528 

529def crypto_pwhash_str_alg( 

530 passwd: bytes, 

531 opslimit: int, 

532 memlimit: int, 

533 alg: int, 

534) -> bytes: 

535 """ 

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

537 and a random salt, returning a string representation which 

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

539 

540 :param passwd: The input password 

541 :type passwd: bytes 

542 :param opslimit: computational cost 

543 :type opslimit: int 

544 :param memlimit: memory cost 

545 :type memlimit: int 

546 :param alg: The algorithm to use 

547 :type alg: int 

548 :return: serialized derived key and parameters 

549 :rtype: bytes 

550 """ 

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

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

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

554 

555 _check_argon2_limits_alg(opslimit, memlimit, alg) 

556 

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

558 

559 ret = lib.crypto_pwhash_str_alg( 

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

561 ) 

562 

563 ensure( 

564 ret == 0, 

565 "Unexpected failure in key derivation", 

566 raising=exc.RuntimeError, 

567 ) 

568 

569 return ffi.string(outbuf) 

570 

571 

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

573 """ 

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

575 

576 Returns True on success, raises InvalidkeyError on failure 

577 :param passwd_hash: saved password hash 

578 :type passwd_hash: bytes 

579 :param passwd: password to be checked 

580 :type passwd: bytes 

581 :return: success 

582 :rtype: boolean 

583 """ 

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

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

586 ensure( 

587 len(passwd_hash) <= 127, 

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

589 raising=exc.ValueError, 

590 ) 

591 

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

593 

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

595 # all went well, therefore: 

596 return True 

597 

598 

599crypto_pwhash_argon2i_str_verify = crypto_pwhash_str_verify