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
« 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# ===================================================================
24"""This file contains a collection of standard key derivation functions.
26A key derivation function derives one or more secondary secret keys from
27one primary secret (a master key or a pass phrase).
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).
33:undocumented: __revision__
34"""
36__revision__ = "$Id$"
38import math
39import struct
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 *
46from Crypto.Hash import SHA1, HMAC, CMAC
47from Crypto.Util.strxor import strxor
48from Crypto.Util.number import long_to_bytes, bytes_to_long
50def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None):
51 """Derive one key from a password (or passphrase).
53 This function performs key derivation according an old version of
54 the PKCS#5 standard (v1.5).
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.
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`.
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]
91def PBKDF2(password, salt, dkLen=16, count=1000, prf=None):
92 """Derive one or more keys from a password (or passphrase).
94 This performs key derivation according to the PKCS#5 standard (v2.0),
95 by means of the ``PBKDF2`` algorithm.
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.
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]
129class _S2V(object):
130 """String-to-vector PRF as defined in `RFC5297`_.
132 This class implements a pseudorandom function family
133 based on CMAC that takes as input a vector of strings.
135 .. _RFC5297: http://tools.ietf.org/html/rfc5297
136 """
138 def __init__(self, key, ciphermod):
139 """Initialize the S2V PRF.
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 """
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
154 def new(key, ciphermod):
155 """Create a new S2V PRF.
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)
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):]
173 def update(self, item):
174 """Pass the next component of the vector.
176 The maximum number of components you can pass is equal to the block
177 length of the cipher (in bits) minus 1.
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 """
186 if not item:
187 raise ValueError("A component cannot be empty")
189 if self._n_updates==0:
190 raise TypeError("Too many components passed to S2V")
191 self._n_updates -= 1
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
197 def derive(self):
198 """"Derive a secret from the vector of components.
200 :Return: a byte string, as long as the block length of the cipher.
201 """
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()