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

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

38 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. 

14from typing import cast 

15 

16import nacl.bindings 

17import nacl.encoding 

18from nacl import exceptions as exc 

19from nacl.exceptions import ensure 

20 

21_strbytes_plus_one = nacl.bindings.crypto_pwhash_scryptsalsa208sha256_STRBYTES 

22 

23AVAILABLE = nacl.bindings.has_crypto_pwhash_scryptsalsa208sha256 

24 

25STRPREFIX = nacl.bindings.crypto_pwhash_scryptsalsa208sha256_STRPREFIX 

26 

27SALTBYTES = nacl.bindings.crypto_pwhash_scryptsalsa208sha256_SALTBYTES 

28 

29PASSWD_MIN = nacl.bindings.crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN 

30PASSWD_MAX = nacl.bindings.crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX 

31 

32PWHASH_SIZE = _strbytes_plus_one - 1 

33 

34BYTES_MIN = nacl.bindings.crypto_pwhash_scryptsalsa208sha256_BYTES_MIN 

35BYTES_MAX = nacl.bindings.crypto_pwhash_scryptsalsa208sha256_BYTES_MAX 

36 

37MEMLIMIT_MIN = nacl.bindings.crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN 

38MEMLIMIT_MAX = nacl.bindings.crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX 

39OPSLIMIT_MIN = nacl.bindings.crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN 

40OPSLIMIT_MAX = nacl.bindings.crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX 

41 

42OPSLIMIT_INTERACTIVE = ( 

43 nacl.bindings.crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE 

44) 

45MEMLIMIT_INTERACTIVE = ( 

46 nacl.bindings.crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE 

47) 

48OPSLIMIT_SENSITIVE = ( 

49 nacl.bindings.crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 

50) 

51MEMLIMIT_SENSITIVE = ( 

52 nacl.bindings.crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 

53) 

54 

55OPSLIMIT_MODERATE = 8 * OPSLIMIT_INTERACTIVE 

56MEMLIMIT_MODERATE = 8 * MEMLIMIT_INTERACTIVE 

57 

58 

59def kdf( 

60 size: int, 

61 password: bytes, 

62 salt: bytes, 

63 opslimit: int = OPSLIMIT_SENSITIVE, 

64 memlimit: int = MEMLIMIT_SENSITIVE, 

65 encoder: nacl.encoding.Encoder = nacl.encoding.RawEncoder, 

66) -> bytes: 

67 """ 

68 Derive a ``size`` bytes long key from a caller-supplied 

69 ``password`` and ``salt`` pair using the scryptsalsa208sha256 

70 memory-hard construct. 

71 

72 

73 the enclosing module provides the constants 

74 

75 - :py:const:`.OPSLIMIT_INTERACTIVE` 

76 - :py:const:`.MEMLIMIT_INTERACTIVE` 

77 - :py:const:`.OPSLIMIT_SENSITIVE` 

78 - :py:const:`.MEMLIMIT_SENSITIVE` 

79 - :py:const:`.OPSLIMIT_MODERATE` 

80 - :py:const:`.MEMLIMIT_MODERATE` 

81 

82 as a guidance for correct settings respectively for the 

83 interactive login and the long term key protecting sensitive data 

84 use cases. 

85 

86 :param size: derived key size, must be between 

87 :py:const:`.BYTES_MIN` and 

88 :py:const:`.BYTES_MAX` 

89 :type size: int 

90 :param password: password used to seed the key derivation procedure; 

91 it length must be between 

92 :py:const:`.PASSWD_MIN` and 

93 :py:const:`.PASSWD_MAX` 

94 :type password: bytes 

95 :param salt: **RANDOM** salt used in the key derivation procedure; 

96 its length must be exactly :py:const:`.SALTBYTES` 

97 :type salt: bytes 

98 :param opslimit: the time component (operation count) 

99 of the key derivation procedure's computational cost; 

100 it must be between 

101 :py:const:`.OPSLIMIT_MIN` and 

102 :py:const:`.OPSLIMIT_MAX` 

103 :type opslimit: int 

104 :param memlimit: the memory occupation component 

105 of the key derivation procedure's computational cost; 

106 it must be between 

107 :py:const:`.MEMLIMIT_MIN` and 

108 :py:const:`.MEMLIMIT_MAX` 

109 :type memlimit: int 

110 :rtype: bytes 

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

112 minimal build of libsodium. 

113 

114 .. versionadded:: 1.2 

115 """ 

116 ensure( 

117 AVAILABLE, 

118 "Not available in minimal build", 

119 raising=exc.UnavailableError, 

120 ) 

121 

122 ensure( 

123 len(salt) == SALTBYTES, 

124 f"The salt must be exactly {SALTBYTES}, not {len(salt)} bytes long", 

125 raising=exc.ValueError, 

126 ) 

127 

128 n_log2, r, p = nacl.bindings.nacl_bindings_pick_scrypt_params( 

129 opslimit, memlimit 

130 ) 

131 maxmem = memlimit + (2**16) 

132 

133 return encoder.encode( 

134 nacl.bindings.crypto_pwhash_scryptsalsa208sha256_ll( 

135 password, 

136 salt, 

137 # Cast safety: n_log2 is a positive integer, and so 2 ** n_log2 is also 

138 # a positive integer. Mypy+typeshed can't deduce this, because there's no 

139 # way to for them to know that n_log2: int is positive. 

140 cast(int, 2**n_log2), 

141 r, 

142 p, 

143 maxmem=maxmem, 

144 dklen=size, 

145 ) 

146 ) 

147 

148 

149def str( 

150 password: bytes, 

151 opslimit: int = OPSLIMIT_INTERACTIVE, 

152 memlimit: int = MEMLIMIT_INTERACTIVE, 

153) -> bytes: 

154 """ 

155 Hashes a password with a random salt, using the memory-hard 

156 scryptsalsa208sha256 construct and returning an ascii string 

157 that has all the needed info to check against a future password 

158 

159 The default settings for opslimit and memlimit are those deemed 

160 correct for the interactive user login case. 

161 

162 :param bytes password: 

163 :param int opslimit: 

164 :param int memlimit: 

165 :rtype: bytes 

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

167 minimal build of libsodium. 

168 

169 .. versionadded:: 1.2 

170 """ 

171 ensure( 

172 AVAILABLE, 

173 "Not available in minimal build", 

174 raising=exc.UnavailableError, 

175 ) 

176 

177 return nacl.bindings.crypto_pwhash_scryptsalsa208sha256_str( 

178 password, opslimit, memlimit 

179 ) 

180 

181 

182def verify(password_hash: bytes, password: bytes) -> bool: 

183 """ 

184 Takes the output of scryptsalsa208sha256 and compares it against 

185 a user provided password to see if they are the same 

186 

187 :param password_hash: bytes 

188 :param password: bytes 

189 :rtype: boolean 

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

191 minimal build of libsodium. 

192 

193 .. versionadded:: 1.2 

194 """ 

195 ensure( 

196 AVAILABLE, 

197 "Not available in minimal build", 

198 raising=exc.UnavailableError, 

199 ) 

200 

201 ensure( 

202 len(password_hash) == PWHASH_SIZE, 

203 f"The password hash must be exactly {nacl.bindings.crypto_pwhash_scryptsalsa208sha256_STRBYTES} bytes long", 

204 raising=exc.ValueError, 

205 ) 

206 

207 return nacl.bindings.crypto_pwhash_scryptsalsa208sha256_str_verify( 

208 password_hash, password 

209 )