Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/oscrypto/_openssl/util.py: 21%
53 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:25 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:25 +0000
1# coding: utf-8
2from __future__ import unicode_literals, division, absolute_import, print_function
4from .._errors import pretty_message
5from .._ffi import buffer_from_bytes, bytes_from_buffer
6from ._libcrypto import libcrypto, libcrypto_version_info, handle_openssl_error
7from .._rand import rand_bytes
8from .._types import type_name, byte_cls, int_types
11__all__ = [
12 'pbkdf2',
13 'pkcs12_kdf',
14 'rand_bytes',
15]
18# OpenSSL 0.9.8 does not include PBKDF2
19if libcrypto_version_info < (1,):
20 from .._pkcs5 import pbkdf2
22else:
23 def pbkdf2(hash_algorithm, password, salt, iterations, key_length):
24 """
25 PBKDF2 from PKCS#5
27 :param hash_algorithm:
28 The string name of the hash algorithm to use: "sha1", "sha224", "sha256", "sha384", "sha512"
30 :param password:
31 A byte string of the password to use an input to the KDF
33 :param salt:
34 A cryptographic random byte string
36 :param iterations:
37 The numbers of iterations to use when deriving the key
39 :param key_length:
40 The length of the desired key in bytes
42 :raises:
43 ValueError - when any of the parameters contain an invalid value
44 TypeError - when any of the parameters are of the wrong type
46 :return:
47 The derived key as a byte string
48 """
50 if not isinstance(password, byte_cls):
51 raise TypeError(pretty_message(
52 '''
53 password must be a byte string, not %s
54 ''',
55 type_name(password)
56 ))
58 if not isinstance(salt, byte_cls):
59 raise TypeError(pretty_message(
60 '''
61 salt must be a byte string, not %s
62 ''',
63 type_name(salt)
64 ))
66 if not isinstance(iterations, int_types):
67 raise TypeError(pretty_message(
68 '''
69 iterations must be an integer, not %s
70 ''',
71 type_name(iterations)
72 ))
74 if iterations < 1:
75 raise ValueError('iterations must be greater than 0')
77 if not isinstance(key_length, int_types):
78 raise TypeError(pretty_message(
79 '''
80 key_length must be an integer, not %s
81 ''',
82 type_name(key_length)
83 ))
85 if key_length < 1:
86 raise ValueError('key_length must be greater than 0')
88 if hash_algorithm not in set(['sha1', 'sha224', 'sha256', 'sha384', 'sha512']):
89 raise ValueError(pretty_message(
90 '''
91 hash_algorithm must be one of "sha1", "sha224", "sha256", "sha384",
92 "sha512", not %s
93 ''',
94 repr(hash_algorithm)
95 ))
97 evp_md = {
98 'sha1': libcrypto.EVP_sha1,
99 'sha224': libcrypto.EVP_sha224,
100 'sha256': libcrypto.EVP_sha256,
101 'sha384': libcrypto.EVP_sha384,
102 'sha512': libcrypto.EVP_sha512
103 }[hash_algorithm]()
105 output_buffer = buffer_from_bytes(key_length)
106 result = libcrypto.PKCS5_PBKDF2_HMAC(
107 password,
108 len(password),
109 salt,
110 len(salt),
111 iterations,
112 evp_md,
113 key_length,
114 output_buffer
115 )
116 handle_openssl_error(result)
118 return bytes_from_buffer(output_buffer)
120 pbkdf2.pure_python = False
123def pkcs12_kdf(hash_algorithm, password, salt, iterations, key_length, id_):
124 """
125 KDF from RFC7292 appendix B.2 - https://tools.ietf.org/html/rfc7292#page-19
127 :param hash_algorithm:
128 The string name of the hash algorithm to use: "md5", "sha1", "sha224", "sha256", "sha384", "sha512"
130 :param password:
131 A byte string of the password to use an input to the KDF
133 :param salt:
134 A cryptographic random byte string
136 :param iterations:
137 The numbers of iterations to use when deriving the key
139 :param key_length:
140 The length of the desired key in bytes
142 :param id_:
143 The ID of the usage - 1 for key, 2 for iv, 3 for mac
145 :raises:
146 ValueError - when any of the parameters contain an invalid value
147 TypeError - when any of the parameters are of the wrong type
149 :return:
150 The derived key as a byte string
151 """
153 if not isinstance(password, byte_cls):
154 raise TypeError(pretty_message(
155 '''
156 password must be a byte string, not %s
157 ''',
158 type_name(password)
159 ))
161 if not isinstance(salt, byte_cls):
162 raise TypeError(pretty_message(
163 '''
164 salt must be a byte string, not %s
165 ''',
166 type_name(salt)
167 ))
169 if not isinstance(iterations, int_types):
170 raise TypeError(pretty_message(
171 '''
172 iterations must be an integer, not %s
173 ''',
174 type_name(iterations)
175 ))
177 if iterations < 1:
178 raise ValueError(pretty_message(
179 '''
180 iterations must be greater than 0 - is %s
181 ''',
182 repr(iterations)
183 ))
185 if not isinstance(key_length, int_types):
186 raise TypeError(pretty_message(
187 '''
188 key_length must be an integer, not %s
189 ''',
190 type_name(key_length)
191 ))
193 if key_length < 1:
194 raise ValueError(pretty_message(
195 '''
196 key_length must be greater than 0 - is %s
197 ''',
198 repr(key_length)
199 ))
201 if hash_algorithm not in set(['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512']):
202 raise ValueError(pretty_message(
203 '''
204 hash_algorithm must be one of "md5", "sha1", "sha224", "sha256",
205 "sha384", "sha512", not %s
206 ''',
207 repr(hash_algorithm)
208 ))
210 if id_ not in set([1, 2, 3]):
211 raise ValueError(pretty_message(
212 '''
213 id_ must be one of 1, 2, 3, not %s
214 ''',
215 repr(id_)
216 ))
218 utf16_password = password.decode('utf-8').encode('utf-16be') + b'\x00\x00'
220 digest_type = {
221 'md5': libcrypto.EVP_md5,
222 'sha1': libcrypto.EVP_sha1,
223 'sha224': libcrypto.EVP_sha224,
224 'sha256': libcrypto.EVP_sha256,
225 'sha384': libcrypto.EVP_sha384,
226 'sha512': libcrypto.EVP_sha512,
227 }[hash_algorithm]()
229 output_buffer = buffer_from_bytes(key_length)
230 result = libcrypto.PKCS12_key_gen_uni(
231 utf16_password,
232 len(utf16_password),
233 salt,
234 len(salt),
235 id_,
236 iterations,
237 key_length,
238 output_buffer,
239 digest_type
240 )
241 handle_openssl_error(result)
243 return bytes_from_buffer(output_buffer)