Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/bcrypt/__init__.py: 32%
38 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:36 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:36 +0000
1# Author:: Donald Stufft (<donald@stufft.io>)
2# Copyright:: Copyright (c) 2013 Donald Stufft
3# License:: Apache License, Version 2.0
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16from __future__ import absolute_import
17from __future__ import division
19import hmac
20import os
21import warnings
23from .__about__ import (
24 __author__,
25 __copyright__,
26 __email__,
27 __license__,
28 __summary__,
29 __title__,
30 __uri__,
31 __version__,
32)
33from . import _bcrypt # noqa: I100
36__all__ = [
37 "__title__",
38 "__summary__",
39 "__uri__",
40 "__version__",
41 "__author__",
42 "__email__",
43 "__license__",
44 "__copyright__",
45 "gensalt",
46 "hashpw",
47 "kdf",
48 "checkpw",
49]
52def gensalt(rounds: int = 12, prefix: bytes = b"2b") -> bytes:
53 if prefix not in (b"2a", b"2b"):
54 raise ValueError("Supported prefixes are b'2a' or b'2b'")
56 if rounds < 4 or rounds > 31:
57 raise ValueError("Invalid rounds")
59 salt = os.urandom(16)
60 output = _bcrypt.encode_base64(salt)
62 return (
63 b"$"
64 + prefix
65 + b"$"
66 + ("%2.2u" % rounds).encode("ascii")
67 + b"$"
68 + output
69 )
72def hashpw(password: bytes, salt: bytes) -> bytes:
73 if isinstance(password, str) or isinstance(salt, str):
74 raise TypeError("Strings must be encoded before hashing")
76 # bcrypt originally suffered from a wraparound bug:
77 # http://www.openwall.com/lists/oss-security/2012/01/02/4
78 # This bug was corrected in the OpenBSD source by truncating inputs to 72
79 # bytes on the updated prefix $2b$, but leaving $2a$ unchanged for
80 # compatibility. However, pyca/bcrypt 2.0.0 *did* correctly truncate inputs
81 # on $2a$, so we do it here to preserve compatibility with 2.0.0
82 password = password[:72]
84 return _bcrypt.hashpass(password, salt)
87def checkpw(password: bytes, hashed_password: bytes) -> bool:
88 if isinstance(password, str) or isinstance(hashed_password, str):
89 raise TypeError("Strings must be encoded before checking")
91 ret = hashpw(password, hashed_password)
92 return hmac.compare_digest(ret, hashed_password)
95def kdf(
96 password: bytes,
97 salt: bytes,
98 desired_key_bytes: int,
99 rounds: int,
100 ignore_few_rounds: bool = False,
101) -> bytes:
102 if isinstance(password, str) or isinstance(salt, str):
103 raise TypeError("Strings must be encoded before hashing")
105 if len(password) == 0 or len(salt) == 0:
106 raise ValueError("password and salt must not be empty")
108 if desired_key_bytes <= 0 or desired_key_bytes > 512:
109 raise ValueError("desired_key_bytes must be 1-512")
111 if rounds < 1:
112 raise ValueError("rounds must be 1 or more")
114 if rounds < 50 and not ignore_few_rounds:
115 # They probably think bcrypt.kdf()'s rounds parameter is logarithmic,
116 # expecting this value to be slow enough (it probably would be if this
117 # were bcrypt). Emit a warning.
118 warnings.warn(
119 (
120 "Warning: bcrypt.kdf() called with only {0} round(s). "
121 "This few is not secure: the parameter is linear, like PBKDF2."
122 ).format(rounds),
123 UserWarning,
124 stacklevel=2,
125 )
127 return _bcrypt.pbkdf(password, salt, rounds, desired_key_bytes)