Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/Crypto/Protocol/KDF.py: 28%

68 statements  

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

1# 

2# KDF.py : a collection of Key Derivation Functions 

3# 

4# Part of the Python Cryptography Toolkit 

5# 

6# =================================================================== 

7# The contents of this file are dedicated to the public domain. To 

8# the extent that dedication to the public domain is not available, 

9# everyone is granted a worldwide, perpetual, royalty-free, 

10# non-exclusive license to exercise all rights associated with the 

11# contents of this file for any purpose whatsoever. 

12# No rights are reserved. 

13# 

14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 

15# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 

16# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 

17# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 

18# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 

19# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 

20# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 

21# SOFTWARE. 

22# =================================================================== 

23 

24"""This file contains a collection of standard key derivation functions. 

25 

26A key derivation function derives one or more secondary secret keys from 

27one primary secret (a master key or a pass phrase). 

28 

29This is typically done to insulate the secondary keys from each other, 

30to avoid that leakage of a secondary key compromises the security of the 

31master key, or to thwart attacks on pass phrases (e.g. via rainbow tables). 

32 

33:undocumented: __revision__ 

34""" 

35 

36__revision__ = "$Id$" 

37 

38import math 

39import struct 

40 

41import sys 

42if sys.version_info[0] == 2 and sys.version_info[1] == 1: 

43 from Crypto.Util.py21compat import * 

44from Crypto.Util.py3compat import * 

45 

46from Crypto.Hash import SHA1, HMAC, CMAC 

47from Crypto.Util.strxor import strxor 

48from Crypto.Util.number import long_to_bytes, bytes_to_long 

49 

50def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None): 

51 """Derive one key from a password (or passphrase). 

52 

53 This function performs key derivation according an old version of 

54 the PKCS#5 standard (v1.5). 

55 

56 This algorithm is called ``PBKDF1``. Even though it is still described 

57 in the latest version of the PKCS#5 standard (version 2, or RFC2898), 

58 newer applications should use the more secure and versatile `PBKDF2` instead. 

59 

60 :Parameters: 

61 password : string 

62 The secret password or pass phrase to generate the key from. 

63 salt : byte string 

64 An 8 byte string to use for better protection from dictionary attacks. 

65 This value does not need to be kept secret, but it should be randomly 

66 chosen for each derivation. 

67 dkLen : integer 

68 The length of the desired key. Default is 16 bytes, suitable for instance for `Crypto.Cipher.AES`. 

69 count : integer 

70 The number of iterations to carry out. It's recommended to use at least 1000. 

71 hashAlgo : module 

72 The hash algorithm to use, as a module or an object from the `Crypto.Hash` package. 

73 The digest length must be no shorter than ``dkLen``. 

74 The default algorithm is `SHA1`. 

75 

76 :Return: A byte string of length `dkLen` that can be used as key. 

77 """ 

78 if not hashAlgo: 

79 hashAlgo = SHA1 

80 password = tobytes(password) 

81 pHash = hashAlgo.new(password+salt) 

82 digest = pHash.digest_size 

83 if dkLen>digest: 

84 raise TypeError("Selected hash algorithm has a too short digest (%d bytes)." % digest) 

85 if len(salt)!=8: 

86 raise ValueError("Salt is not 8 bytes long.") 

87 for i in range(count-1): 

88 pHash = pHash.new(pHash.digest()) 

89 return pHash.digest()[:dkLen] 

90 

91def PBKDF2(password, salt, dkLen=16, count=1000, prf=None): 

92 """Derive one or more keys from a password (or passphrase). 

93 

94 This performs key derivation according to the PKCS#5 standard (v2.0), 

95 by means of the ``PBKDF2`` algorithm. 

96 

97 :Parameters: 

98 password : string 

99 The secret password or pass phrase to generate the key from. 

100 salt : string 

101 A string to use for better protection from dictionary attacks. 

102 This value does not need to be kept secret, but it should be randomly 

103 chosen for each derivation. It is recommended to be at least 8 bytes long. 

104 dkLen : integer 

105 The cumulative length of the desired keys. Default is 16 bytes, suitable for instance for `Crypto.Cipher.AES`. 

106 count : integer 

107 The number of iterations to carry out. It's recommended to use at least 1000. 

108 prf : callable 

109 A pseudorandom function. It must be a function that returns a pseudorandom string 

110 from two parameters: a secret and a salt. If not specified, HMAC-SHA1 is used. 

111 

112 :Return: A byte string of length `dkLen` that can be used as key material. 

113 If you wanted multiple keys, just break up this string into segments of the desired length. 

114""" 

115 password = tobytes(password) 

116 if prf is None: 

117 prf = lambda p,s: HMAC.new(p,s,SHA1).digest() 

118 key = b('') 

119 i = 1 

120 while len(key)<dkLen: 

121 U = previousU = prf(password,salt+struct.pack(">I", i)) 

122 for j in range(count-1): 

123 previousU = t = prf(password,previousU) 

124 U = strxor(U,t) 

125 key += U 

126 i = i + 1 

127 return key[:dkLen] 

128 

129class _S2V(object): 

130 """String-to-vector PRF as defined in `RFC5297`_. 

131 

132 This class implements a pseudorandom function family 

133 based on CMAC that takes as input a vector of strings. 

134 

135 .. _RFC5297: http://tools.ietf.org/html/rfc5297 

136 """ 

137 

138 def __init__(self, key, ciphermod): 

139 """Initialize the S2V PRF. 

140 

141 :Parameters: 

142 key : byte string 

143 A secret that can be used as key for CMACs 

144 based on ciphers from ``ciphermod``. 

145 ciphermod : module 

146 A block cipher module from `Crypto.Cipher`. 

147 """ 

148 

149 self._key = key 

150 self._ciphermod = ciphermod 

151 self._last_string = self._cache = bchr(0)*ciphermod.block_size 

152 self._n_updates = ciphermod.block_size*8-1 

153 

154 def new(key, ciphermod): 

155 """Create a new S2V PRF. 

156 

157 :Parameters: 

158 key : byte string 

159 A secret that can be used as key for CMACs 

160 based on ciphers from ``ciphermod``. 

161 ciphermod : module 

162 A block cipher module from `Crypto.Cipher`. 

163 """ 

164 return _S2V(key, ciphermod) 

165 new = staticmethod(new) 

166 

167 def _double(self, bs): 

168 doubled = bytes_to_long(bs)<<1 

169 if bord(bs[0]) & 0x80: 

170 doubled ^= 0x87 

171 return long_to_bytes(doubled, len(bs))[-len(bs):] 

172 

173 def update(self, item): 

174 """Pass the next component of the vector. 

175 

176 The maximum number of components you can pass is equal to the block 

177 length of the cipher (in bits) minus 1. 

178 

179 :Parameters: 

180 item : byte string 

181 The next component of the vector. 

182 :Raise TypeError: when the limit on the number of components has been reached. 

183 :Raise ValueError: when the component is empty 

184 """ 

185 

186 if not item: 

187 raise ValueError("A component cannot be empty") 

188 

189 if self._n_updates==0: 

190 raise TypeError("Too many components passed to S2V") 

191 self._n_updates -= 1 

192 

193 mac = CMAC.new(self._key, msg=self._last_string, ciphermod=self._ciphermod) 

194 self._cache = strxor(self._double(self._cache), mac.digest()) 

195 self._last_string = item 

196 

197 def derive(self): 

198 """"Derive a secret from the vector of components. 

199 

200 :Return: a byte string, as long as the block length of the cipher. 

201 """ 

202 

203 if len(self._last_string)>=16: 

204 final = self._last_string[:-16] + strxor(self._last_string[-16:], self._cache) 

205 else: 

206 padded = (self._last_string + bchr(0x80)+ bchr(0)*15)[:16] 

207 final = strxor(padded, self._double(self._cache)) 

208 mac = CMAC.new(self._key, msg=final, ciphermod=self._ciphermod) 

209 return mac.digest()