crypto_pwhash.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  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. import sys
  15. from typing import Tuple
  16. import nacl.exceptions as exc
  17. from nacl._sodium import ffi, lib
  18. from nacl.exceptions import ensure
  19. has_crypto_pwhash_scryptsalsa208sha256 = bool(
  20. lib.PYNACL_HAS_CRYPTO_PWHASH_SCRYPTSALSA208SHA256
  21. )
  22. crypto_pwhash_scryptsalsa208sha256_STRPREFIX = b""
  23. crypto_pwhash_scryptsalsa208sha256_SALTBYTES = 0
  24. crypto_pwhash_scryptsalsa208sha256_STRBYTES = 0
  25. crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN = 0
  26. crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX = 0
  27. crypto_pwhash_scryptsalsa208sha256_BYTES_MIN = 0
  28. crypto_pwhash_scryptsalsa208sha256_BYTES_MAX = 0
  29. crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN = 0
  30. crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX = 0
  31. crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN = 0
  32. crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX = 0
  33. crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE = 0
  34. crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE = 0
  35. crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE = 0
  36. crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE = 0
  37. if has_crypto_pwhash_scryptsalsa208sha256:
  38. crypto_pwhash_scryptsalsa208sha256_STRPREFIX = ffi.string(
  39. ffi.cast("char *", lib.crypto_pwhash_scryptsalsa208sha256_strprefix())
  40. )[:]
  41. crypto_pwhash_scryptsalsa208sha256_SALTBYTES = (
  42. lib.crypto_pwhash_scryptsalsa208sha256_saltbytes()
  43. )
  44. crypto_pwhash_scryptsalsa208sha256_STRBYTES = (
  45. lib.crypto_pwhash_scryptsalsa208sha256_strbytes()
  46. )
  47. crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN = (
  48. lib.crypto_pwhash_scryptsalsa208sha256_passwd_min()
  49. )
  50. crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX = (
  51. lib.crypto_pwhash_scryptsalsa208sha256_passwd_max()
  52. )
  53. crypto_pwhash_scryptsalsa208sha256_BYTES_MIN = (
  54. lib.crypto_pwhash_scryptsalsa208sha256_bytes_min()
  55. )
  56. crypto_pwhash_scryptsalsa208sha256_BYTES_MAX = (
  57. lib.crypto_pwhash_scryptsalsa208sha256_bytes_max()
  58. )
  59. crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN = (
  60. lib.crypto_pwhash_scryptsalsa208sha256_memlimit_min()
  61. )
  62. crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX = (
  63. lib.crypto_pwhash_scryptsalsa208sha256_memlimit_max()
  64. )
  65. crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN = (
  66. lib.crypto_pwhash_scryptsalsa208sha256_opslimit_min()
  67. )
  68. crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX = (
  69. lib.crypto_pwhash_scryptsalsa208sha256_opslimit_max()
  70. )
  71. crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE = (
  72. lib.crypto_pwhash_scryptsalsa208sha256_opslimit_interactive()
  73. )
  74. crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE = (
  75. lib.crypto_pwhash_scryptsalsa208sha256_memlimit_interactive()
  76. )
  77. crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE = (
  78. lib.crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive()
  79. )
  80. crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE = (
  81. lib.crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive()
  82. )
  83. crypto_pwhash_ALG_ARGON2I13: int = lib.crypto_pwhash_alg_argon2i13()
  84. crypto_pwhash_ALG_ARGON2ID13: int = lib.crypto_pwhash_alg_argon2id13()
  85. crypto_pwhash_ALG_DEFAULT: int = lib.crypto_pwhash_alg_default()
  86. crypto_pwhash_SALTBYTES: int = lib.crypto_pwhash_saltbytes()
  87. crypto_pwhash_STRBYTES: int = lib.crypto_pwhash_strbytes()
  88. crypto_pwhash_PASSWD_MIN: int = lib.crypto_pwhash_passwd_min()
  89. crypto_pwhash_PASSWD_MAX: int = lib.crypto_pwhash_passwd_max()
  90. crypto_pwhash_BYTES_MIN: int = lib.crypto_pwhash_bytes_min()
  91. crypto_pwhash_BYTES_MAX: int = lib.crypto_pwhash_bytes_max()
  92. crypto_pwhash_argon2i_STRPREFIX: bytes = ffi.string(
  93. ffi.cast("char *", lib.crypto_pwhash_argon2i_strprefix())
  94. )[:]
  95. crypto_pwhash_argon2i_MEMLIMIT_MIN: int = (
  96. lib.crypto_pwhash_argon2i_memlimit_min()
  97. )
  98. crypto_pwhash_argon2i_MEMLIMIT_MAX: int = (
  99. lib.crypto_pwhash_argon2i_memlimit_max()
  100. )
  101. crypto_pwhash_argon2i_OPSLIMIT_MIN: int = (
  102. lib.crypto_pwhash_argon2i_opslimit_min()
  103. )
  104. crypto_pwhash_argon2i_OPSLIMIT_MAX: int = (
  105. lib.crypto_pwhash_argon2i_opslimit_max()
  106. )
  107. crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE: int = (
  108. lib.crypto_pwhash_argon2i_opslimit_interactive()
  109. )
  110. crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE: int = (
  111. lib.crypto_pwhash_argon2i_memlimit_interactive()
  112. )
  113. crypto_pwhash_argon2i_OPSLIMIT_MODERATE: int = (
  114. lib.crypto_pwhash_argon2i_opslimit_moderate()
  115. )
  116. crypto_pwhash_argon2i_MEMLIMIT_MODERATE: int = (
  117. lib.crypto_pwhash_argon2i_memlimit_moderate()
  118. )
  119. crypto_pwhash_argon2i_OPSLIMIT_SENSITIVE: int = (
  120. lib.crypto_pwhash_argon2i_opslimit_sensitive()
  121. )
  122. crypto_pwhash_argon2i_MEMLIMIT_SENSITIVE: int = (
  123. lib.crypto_pwhash_argon2i_memlimit_sensitive()
  124. )
  125. crypto_pwhash_argon2id_STRPREFIX: bytes = ffi.string(
  126. ffi.cast("char *", lib.crypto_pwhash_argon2id_strprefix())
  127. )[:]
  128. crypto_pwhash_argon2id_MEMLIMIT_MIN: int = (
  129. lib.crypto_pwhash_argon2id_memlimit_min()
  130. )
  131. crypto_pwhash_argon2id_MEMLIMIT_MAX: int = (
  132. lib.crypto_pwhash_argon2id_memlimit_max()
  133. )
  134. crypto_pwhash_argon2id_OPSLIMIT_MIN: int = (
  135. lib.crypto_pwhash_argon2id_opslimit_min()
  136. )
  137. crypto_pwhash_argon2id_OPSLIMIT_MAX: int = (
  138. lib.crypto_pwhash_argon2id_opslimit_max()
  139. )
  140. crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE: int = (
  141. lib.crypto_pwhash_argon2id_opslimit_interactive()
  142. )
  143. crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE: int = (
  144. lib.crypto_pwhash_argon2id_memlimit_interactive()
  145. )
  146. crypto_pwhash_argon2id_OPSLIMIT_MODERATE: int = (
  147. lib.crypto_pwhash_argon2id_opslimit_moderate()
  148. )
  149. crypto_pwhash_argon2id_MEMLIMIT_MODERATE: int = (
  150. lib.crypto_pwhash_argon2id_memlimit_moderate()
  151. )
  152. crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE: int = (
  153. lib.crypto_pwhash_argon2id_opslimit_sensitive()
  154. )
  155. crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE: int = (
  156. lib.crypto_pwhash_argon2id_memlimit_sensitive()
  157. )
  158. SCRYPT_OPSLIMIT_INTERACTIVE = (
  159. crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE
  160. )
  161. SCRYPT_MEMLIMIT_INTERACTIVE = (
  162. crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE
  163. )
  164. SCRYPT_OPSLIMIT_SENSITIVE = (
  165. crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE
  166. )
  167. SCRYPT_MEMLIMIT_SENSITIVE = (
  168. crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE
  169. )
  170. SCRYPT_SALTBYTES = crypto_pwhash_scryptsalsa208sha256_SALTBYTES
  171. SCRYPT_STRBYTES = crypto_pwhash_scryptsalsa208sha256_STRBYTES
  172. SCRYPT_PR_MAX = (1 << 30) - 1
  173. LOG2_UINT64_MAX = 63
  174. UINT64_MAX = (1 << 64) - 1
  175. SCRYPT_MAX_MEM = 32 * (1024 * 1024)
  176. def _check_memory_occupation(
  177. n: int, r: int, p: int, maxmem: int = SCRYPT_MAX_MEM
  178. ) -> None:
  179. ensure(r != 0, "Invalid block size", raising=exc.ValueError)
  180. ensure(p != 0, "Invalid parallelization factor", raising=exc.ValueError)
  181. ensure(
  182. (n & (n - 1)) == 0,
  183. "Cost factor must be a power of 2",
  184. raising=exc.ValueError,
  185. )
  186. ensure(n > 1, "Cost factor must be at least 2", raising=exc.ValueError)
  187. ensure(
  188. p <= SCRYPT_PR_MAX / r,
  189. "p*r is greater than {}".format(SCRYPT_PR_MAX),
  190. raising=exc.ValueError,
  191. )
  192. ensure(n < (1 << (16 * r)), raising=exc.ValueError)
  193. Blen = p * 128 * r
  194. i = UINT64_MAX / 128
  195. ensure(n + 2 <= i / r, raising=exc.ValueError)
  196. Vlen = 32 * r * (n + 2) * 4
  197. ensure(Blen <= UINT64_MAX - Vlen, raising=exc.ValueError)
  198. ensure(Blen <= sys.maxsize - Vlen, raising=exc.ValueError)
  199. ensure(
  200. Blen + Vlen <= maxmem,
  201. "Memory limit would be exceeded with the choosen n, r, p",
  202. raising=exc.ValueError,
  203. )
  204. def nacl_bindings_pick_scrypt_params(
  205. opslimit: int, memlimit: int
  206. ) -> Tuple[int, int, int]:
  207. """Python implementation of libsodium's pickparams"""
  208. if opslimit < 32768:
  209. opslimit = 32768
  210. r = 8
  211. if opslimit < (memlimit // 32):
  212. p = 1
  213. maxn = opslimit // (4 * r)
  214. for n_log2 in range(1, 63): # pragma: no branch
  215. if (2 ** n_log2) > (maxn // 2):
  216. break
  217. else:
  218. maxn = memlimit // (r * 128)
  219. for n_log2 in range(1, 63): # pragma: no branch
  220. if (2 ** n_log2) > maxn // 2:
  221. break
  222. maxrp = (opslimit // 4) // (2 ** n_log2)
  223. if maxrp > 0x3FFFFFFF: # pragma: no cover
  224. maxrp = 0x3FFFFFFF
  225. p = maxrp // r
  226. return n_log2, r, p
  227. def crypto_pwhash_scryptsalsa208sha256_ll(
  228. passwd: bytes,
  229. salt: bytes,
  230. n: int,
  231. r: int,
  232. p: int,
  233. dklen: int = 64,
  234. maxmem: int = SCRYPT_MAX_MEM,
  235. ) -> bytes:
  236. """
  237. Derive a cryptographic key using the ``passwd`` and ``salt``
  238. given as input.
  239. The work factor can be tuned by by picking different
  240. values for the parameters
  241. :param bytes passwd:
  242. :param bytes salt:
  243. :param bytes salt: *must* be *exactly* :py:const:`.SALTBYTES` long
  244. :param int dklen:
  245. :param int opslimit:
  246. :param int n:
  247. :param int r: block size,
  248. :param int p: the parallelism factor
  249. :param int maxmem: the maximum available memory available for scrypt's
  250. operations
  251. :rtype: bytes
  252. :raises nacl.exceptions.UnavailableError: If called when using a
  253. minimal build of libsodium.
  254. """
  255. ensure(
  256. has_crypto_pwhash_scryptsalsa208sha256,
  257. "Not available in minimal build",
  258. raising=exc.UnavailableError,
  259. )
  260. ensure(isinstance(n, int), raising=TypeError)
  261. ensure(isinstance(r, int), raising=TypeError)
  262. ensure(isinstance(p, int), raising=TypeError)
  263. ensure(isinstance(passwd, bytes), raising=TypeError)
  264. ensure(isinstance(salt, bytes), raising=TypeError)
  265. _check_memory_occupation(n, r, p, maxmem)
  266. buf = ffi.new("uint8_t[]", dklen)
  267. ret = lib.crypto_pwhash_scryptsalsa208sha256_ll(
  268. passwd, len(passwd), salt, len(salt), n, r, p, buf, dklen
  269. )
  270. ensure(
  271. ret == 0,
  272. "Unexpected failure in key derivation",
  273. raising=exc.RuntimeError,
  274. )
  275. return ffi.buffer(ffi.cast("char *", buf), dklen)[:]
  276. def crypto_pwhash_scryptsalsa208sha256_str(
  277. passwd: bytes,
  278. opslimit: int = SCRYPT_OPSLIMIT_INTERACTIVE,
  279. memlimit: int = SCRYPT_MEMLIMIT_INTERACTIVE,
  280. ) -> bytes:
  281. """
  282. Derive a cryptographic key using the ``passwd`` and ``salt``
  283. given as input, returning a string representation which includes
  284. the salt and the tuning parameters.
  285. The returned string can be directly stored as a password hash.
  286. See :py:func:`.crypto_pwhash_scryptsalsa208sha256` for a short
  287. discussion about ``opslimit`` and ``memlimit`` values.
  288. :param bytes passwd:
  289. :param int opslimit:
  290. :param int memlimit:
  291. :return: serialized key hash, including salt and tuning parameters
  292. :rtype: bytes
  293. :raises nacl.exceptions.UnavailableError: If called when using a
  294. minimal build of libsodium.
  295. """
  296. ensure(
  297. has_crypto_pwhash_scryptsalsa208sha256,
  298. "Not available in minimal build",
  299. raising=exc.UnavailableError,
  300. )
  301. buf = ffi.new("char[]", SCRYPT_STRBYTES)
  302. ret = lib.crypto_pwhash_scryptsalsa208sha256_str(
  303. buf, passwd, len(passwd), opslimit, memlimit
  304. )
  305. ensure(
  306. ret == 0,
  307. "Unexpected failure in password hashing",
  308. raising=exc.RuntimeError,
  309. )
  310. return ffi.string(buf)
  311. def crypto_pwhash_scryptsalsa208sha256_str_verify(
  312. passwd_hash: bytes, passwd: bytes
  313. ) -> bool:
  314. """
  315. Verifies the ``passwd`` against the ``passwd_hash`` that was generated.
  316. Returns True or False depending on the success
  317. :param passwd_hash: bytes
  318. :param passwd: bytes
  319. :rtype: boolean
  320. :raises nacl.exceptions.UnavailableError: If called when using a
  321. minimal build of libsodium.
  322. """
  323. ensure(
  324. has_crypto_pwhash_scryptsalsa208sha256,
  325. "Not available in minimal build",
  326. raising=exc.UnavailableError,
  327. )
  328. ensure(
  329. len(passwd_hash) == SCRYPT_STRBYTES - 1,
  330. "Invalid password hash",
  331. raising=exc.ValueError,
  332. )
  333. ret = lib.crypto_pwhash_scryptsalsa208sha256_str_verify(
  334. passwd_hash, passwd, len(passwd)
  335. )
  336. ensure(ret == 0, "Wrong password", raising=exc.InvalidkeyError)
  337. # all went well, therefore:
  338. return True
  339. def _check_argon2_limits_alg(opslimit: int, memlimit: int, alg: int) -> None:
  340. if alg == crypto_pwhash_ALG_ARGON2I13:
  341. if memlimit < crypto_pwhash_argon2i_MEMLIMIT_MIN:
  342. raise exc.ValueError(
  343. "memlimit must be at least {} bytes".format(
  344. crypto_pwhash_argon2i_MEMLIMIT_MIN
  345. )
  346. )
  347. elif memlimit > crypto_pwhash_argon2i_MEMLIMIT_MAX:
  348. raise exc.ValueError(
  349. "memlimit must be at most {} bytes".format(
  350. crypto_pwhash_argon2i_MEMLIMIT_MAX
  351. )
  352. )
  353. if opslimit < crypto_pwhash_argon2i_OPSLIMIT_MIN:
  354. raise exc.ValueError(
  355. "opslimit must be at least {}".format(
  356. crypto_pwhash_argon2i_OPSLIMIT_MIN
  357. )
  358. )
  359. elif opslimit > crypto_pwhash_argon2i_OPSLIMIT_MAX:
  360. raise exc.ValueError(
  361. "opslimit must be at most {}".format(
  362. crypto_pwhash_argon2i_OPSLIMIT_MAX
  363. )
  364. )
  365. elif alg == crypto_pwhash_ALG_ARGON2ID13:
  366. if memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN:
  367. raise exc.ValueError(
  368. "memlimit must be at least {} bytes".format(
  369. crypto_pwhash_argon2id_MEMLIMIT_MIN
  370. )
  371. )
  372. elif memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX:
  373. raise exc.ValueError(
  374. "memlimit must be at most {} bytes".format(
  375. crypto_pwhash_argon2id_MEMLIMIT_MAX
  376. )
  377. )
  378. if opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN:
  379. raise exc.ValueError(
  380. "opslimit must be at least {}".format(
  381. crypto_pwhash_argon2id_OPSLIMIT_MIN
  382. )
  383. )
  384. elif opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX:
  385. raise exc.ValueError(
  386. "opslimit must be at most {}".format(
  387. crypto_pwhash_argon2id_OPSLIMIT_MAX
  388. )
  389. )
  390. else:
  391. raise exc.TypeError("Unsupported algorithm")
  392. def crypto_pwhash_alg(
  393. outlen: int,
  394. passwd: bytes,
  395. salt: bytes,
  396. opslimit: int,
  397. memlimit: int,
  398. alg: int,
  399. ) -> bytes:
  400. """
  401. Derive a raw cryptographic key using the ``passwd`` and the ``salt``
  402. given as input to the ``alg`` algorithm.
  403. :param outlen: the length of the derived key
  404. :type outlen: int
  405. :param passwd: The input password
  406. :type passwd: bytes
  407. :param salt:
  408. :type salt: bytes
  409. :param opslimit: computational cost
  410. :type opslimit: int
  411. :param memlimit: memory cost
  412. :type memlimit: int
  413. :param alg: algorithm identifier
  414. :type alg: int
  415. :return: derived key
  416. :rtype: bytes
  417. """
  418. ensure(isinstance(outlen, int), raising=exc.TypeError)
  419. ensure(isinstance(opslimit, int), raising=exc.TypeError)
  420. ensure(isinstance(memlimit, int), raising=exc.TypeError)
  421. ensure(isinstance(alg, int), raising=exc.TypeError)
  422. ensure(isinstance(passwd, bytes), raising=exc.TypeError)
  423. if len(salt) != crypto_pwhash_SALTBYTES:
  424. raise exc.ValueError(
  425. "salt must be exactly {} bytes long".format(
  426. crypto_pwhash_SALTBYTES
  427. )
  428. )
  429. if outlen < crypto_pwhash_BYTES_MIN:
  430. raise exc.ValueError(
  431. "derived key must be at least {} bytes long".format(
  432. crypto_pwhash_BYTES_MIN
  433. )
  434. )
  435. elif outlen > crypto_pwhash_BYTES_MAX:
  436. raise exc.ValueError(
  437. "derived key must be at most {} bytes long".format(
  438. crypto_pwhash_BYTES_MAX
  439. )
  440. )
  441. _check_argon2_limits_alg(opslimit, memlimit, alg)
  442. outbuf = ffi.new("unsigned char[]", outlen)
  443. ret = lib.crypto_pwhash(
  444. outbuf, outlen, passwd, len(passwd), salt, opslimit, memlimit, alg
  445. )
  446. ensure(
  447. ret == 0,
  448. "Unexpected failure in key derivation",
  449. raising=exc.RuntimeError,
  450. )
  451. return ffi.buffer(outbuf, outlen)[:]
  452. def crypto_pwhash_str_alg(
  453. passwd: bytes,
  454. opslimit: int,
  455. memlimit: int,
  456. alg: int,
  457. ) -> bytes:
  458. """
  459. Derive a cryptographic key using the ``passwd`` given as input
  460. and a random salt, returning a string representation which
  461. includes the salt, the tuning parameters and the used algorithm.
  462. :param passwd: The input password
  463. :type passwd: bytes
  464. :param opslimit: computational cost
  465. :type opslimit: int
  466. :param memlimit: memory cost
  467. :type memlimit: int
  468. :param alg: The algorithm to use
  469. :type alg: int
  470. :return: serialized derived key and parameters
  471. :rtype: bytes
  472. """
  473. ensure(isinstance(opslimit, int), raising=TypeError)
  474. ensure(isinstance(memlimit, int), raising=TypeError)
  475. ensure(isinstance(passwd, bytes), raising=TypeError)
  476. _check_argon2_limits_alg(opslimit, memlimit, alg)
  477. outbuf = ffi.new("char[]", 128)
  478. ret = lib.crypto_pwhash_str_alg(
  479. outbuf, passwd, len(passwd), opslimit, memlimit, alg
  480. )
  481. ensure(
  482. ret == 0,
  483. "Unexpected failure in key derivation",
  484. raising=exc.RuntimeError,
  485. )
  486. return ffi.string(outbuf)
  487. def crypto_pwhash_str_verify(passwd_hash: bytes, passwd: bytes) -> bool:
  488. """
  489. Verifies the ``passwd`` against a given password hash.
  490. Returns True on success, raises InvalidkeyError on failure
  491. :param passwd_hash: saved password hash
  492. :type passwd_hash: bytes
  493. :param passwd: password to be checked
  494. :type passwd: bytes
  495. :return: success
  496. :rtype: boolean
  497. """
  498. ensure(isinstance(passwd_hash, bytes), raising=TypeError)
  499. ensure(isinstance(passwd, bytes), raising=TypeError)
  500. ensure(
  501. len(passwd_hash) <= 127,
  502. "Hash must be at most 127 bytes long",
  503. raising=exc.ValueError,
  504. )
  505. ret = lib.crypto_pwhash_str_verify(passwd_hash, passwd, len(passwd))
  506. ensure(ret == 0, "Wrong password", raising=exc.InvalidkeyError)
  507. # all went well, therefore:
  508. return True
  509. crypto_pwhash_argon2i_str_verify = crypto_pwhash_str_verify