1214501Srpaulo/*
2214501Srpaulo * PKCS #5 (Password-based Encryption)
3337817Scy * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "includes.h"
10214501Srpaulo
11214501Srpaulo#include "common.h"
12214501Srpaulo#include "crypto/crypto.h"
13214501Srpaulo#include "crypto/md5.h"
14337817Scy#include "crypto/sha1.h"
15214501Srpaulo#include "asn1.h"
16214501Srpaulo#include "pkcs5.h"
17214501Srpaulo
18214501Srpaulo
19214501Srpaulostruct pkcs5_params {
20214501Srpaulo	enum pkcs5_alg {
21214501Srpaulo		PKCS5_ALG_UNKNOWN,
22337817Scy		PKCS5_ALG_MD5_DES_CBC,
23337817Scy		PKCS5_ALG_PBES2,
24337817Scy		PKCS5_ALG_SHA1_3DES_CBC,
25214501Srpaulo	} alg;
26337817Scy	u8 salt[64];
27214501Srpaulo	size_t salt_len;
28214501Srpaulo	unsigned int iter_count;
29337817Scy	enum pbes2_enc_alg {
30337817Scy		PBES2_ENC_ALG_UNKNOWN,
31337817Scy		PBES2_ENC_ALG_DES_EDE3_CBC,
32337817Scy	} enc_alg;
33337817Scy	u8 iv[8];
34337817Scy	size_t iv_len;
35214501Srpaulo};
36214501Srpaulo
37214501Srpaulo
38337817Scystatic int oid_is_rsadsi(struct asn1_oid *oid)
39337817Scy{
40337817Scy	return oid->len >= 4 &&
41337817Scy		oid->oid[0] == 1 /* iso */ &&
42337817Scy		oid->oid[1] == 2 /* member-body */ &&
43337817Scy		oid->oid[2] == 840 /* us */ &&
44337817Scy		oid->oid[3] == 113549 /* rsadsi */;
45337817Scy}
46337817Scy
47337817Scy
48337817Scystatic int pkcs5_is_oid(struct asn1_oid *oid, unsigned long alg)
49337817Scy{
50337817Scy	return oid->len == 7 &&
51337817Scy		oid_is_rsadsi(oid) &&
52337817Scy		oid->oid[4] == 1 /* pkcs */ &&
53337817Scy		oid->oid[5] == 5 /* pkcs-5 */ &&
54337817Scy		oid->oid[6] == alg;
55337817Scy}
56337817Scy
57337817Scy
58337817Scystatic int enc_alg_is_oid(struct asn1_oid *oid, unsigned long alg)
59337817Scy{
60337817Scy	return oid->len == 6 &&
61337817Scy		oid_is_rsadsi(oid) &&
62337817Scy		oid->oid[4] == 3 /* encryptionAlgorithm */ &&
63337817Scy		oid->oid[5] == alg;
64337817Scy}
65337817Scy
66337817Scy
67337817Scystatic int pkcs12_is_pbe_oid(struct asn1_oid *oid, unsigned long alg)
68337817Scy{
69337817Scy	return oid->len == 8 &&
70337817Scy		oid_is_rsadsi(oid) &&
71337817Scy		oid->oid[4] == 1 /* pkcs */ &&
72337817Scy		oid->oid[5] == 12 /* pkcs-12 */ &&
73337817Scy		oid->oid[6] == 1 /* pkcs-12PbeIds */ &&
74337817Scy		oid->oid[7] == alg;
75337817Scy}
76337817Scy
77337817Scy
78252726Srpaulostatic enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
79214501Srpaulo{
80337817Scy	if (pkcs5_is_oid(oid, 3)) /* pbeWithMD5AndDES-CBC (PBES1) */
81214501Srpaulo		return PKCS5_ALG_MD5_DES_CBC;
82337817Scy	if (pkcs12_is_pbe_oid(oid, 3)) /* pbeWithSHAAnd3-KeyTripleDES-CBC */
83337817Scy		return PKCS5_ALG_SHA1_3DES_CBC;
84337817Scy	if (pkcs5_is_oid(oid, 13)) /* id-PBES2 (PBES2) */
85337817Scy		return PKCS5_ALG_PBES2;
86214501Srpaulo	return PKCS5_ALG_UNKNOWN;
87214501Srpaulo}
88214501Srpaulo
89214501Srpaulo
90337817Scystatic int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos,
91337817Scy				  const u8 *enc_alg_end)
92337817Scy{
93337817Scy	struct asn1_hdr hdr;
94337817Scy	const u8 *end, *kdf_end;
95337817Scy	struct asn1_oid oid;
96337817Scy	char obuf[80];
97337817Scy
98337817Scy	/*
99337817Scy	 * RFC 2898, Ch. A.4
100337817Scy	 *
101337817Scy	 * PBES2-params ::= SEQUENCE {
102337817Scy	 *     keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
103337817Scy	 *     encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
104337817Scy	 *
105337817Scy	 * PBES2-KDFs ALGORITHM-IDENTIFIER ::=
106337817Scy	 *     { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
107337817Scy	 */
108337817Scy
109337817Scy	if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
110337817Scy	    hdr.class != ASN1_CLASS_UNIVERSAL ||
111337817Scy	    hdr.tag != ASN1_TAG_SEQUENCE) {
112337817Scy		wpa_printf(MSG_DEBUG,
113337817Scy			   "PKCS #5: Expected SEQUENCE (PBES2-params) - found class %d tag 0x%x",
114337817Scy			   hdr.class, hdr.tag);
115337817Scy		return -1;
116337817Scy	}
117337817Scy	pos = hdr.payload;
118337817Scy	end = hdr.payload + hdr.length;
119337817Scy
120337817Scy	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
121337817Scy	    hdr.class != ASN1_CLASS_UNIVERSAL ||
122337817Scy	    hdr.tag != ASN1_TAG_SEQUENCE) {
123337817Scy		wpa_printf(MSG_DEBUG,
124337817Scy			   "PKCS #5: Expected SEQUENCE (keyDerivationFunc) - found class %d tag 0x%x",
125337817Scy			   hdr.class, hdr.tag);
126337817Scy		return -1;
127337817Scy	}
128337817Scy
129337817Scy	pos = hdr.payload;
130337817Scy	kdf_end = end = hdr.payload + hdr.length;
131337817Scy
132337817Scy	if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
133337817Scy		wpa_printf(MSG_DEBUG,
134337817Scy			   "PKCS #5: Failed to parse OID (keyDerivationFunc algorithm)");
135337817Scy		return -1;
136337817Scy	}
137337817Scy
138337817Scy	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
139337817Scy	wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 keyDerivationFunc algorithm %s",
140337817Scy		   obuf);
141337817Scy	if (!pkcs5_is_oid(&oid, 12)) /* id-PBKDF2 */ {
142337817Scy		wpa_printf(MSG_DEBUG,
143337817Scy			   "PKCS #5: Unsupported PBES2 keyDerivationFunc algorithm %s",
144337817Scy			   obuf);
145337817Scy		return -1;
146337817Scy	}
147337817Scy
148337817Scy	/*
149337817Scy	 * RFC 2898, C.
150337817Scy	 *
151337817Scy	 * PBKDF2-params ::= SEQUENCE {
152337817Scy	 *     salt CHOICE {
153337817Scy	 *       specified OCTET STRING,
154337817Scy	 *       otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
155337817Scy	 *     },
156337817Scy	 *     iterationCount INTEGER (1..MAX),
157337817Scy	 *     keyLength INTEGER (1..MAX) OPTIONAL,
158337817Scy	 *     prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
159337817Scy	 *     algid-hmacWithSHA1
160337817Scy	 * }
161337817Scy	 */
162337817Scy
163337817Scy	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
164337817Scy	    hdr.class != ASN1_CLASS_UNIVERSAL ||
165337817Scy	    hdr.tag != ASN1_TAG_SEQUENCE) {
166337817Scy		wpa_printf(MSG_DEBUG,
167337817Scy			   "PKCS #5: Expected SEQUENCE (PBKDF2-params) - found class %d tag 0x%x",
168337817Scy			   hdr.class, hdr.tag);
169337817Scy		return -1;
170337817Scy	}
171337817Scy
172337817Scy	pos = hdr.payload;
173337817Scy	end = hdr.payload + hdr.length;
174337817Scy
175337817Scy	/* For now, only support the salt CHOICE specified (OCTET STRING) */
176337817Scy	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
177337817Scy	    hdr.class != ASN1_CLASS_UNIVERSAL ||
178337817Scy	    hdr.tag != ASN1_TAG_OCTETSTRING ||
179337817Scy	    hdr.length > sizeof(params->salt)) {
180337817Scy		wpa_printf(MSG_DEBUG,
181337817Scy			   "PKCS #5: Expected OCTET STRING (salt.specified) - found class %d tag 0x%x size %d",
182337817Scy			   hdr.class, hdr.tag, hdr.length);
183337817Scy		return -1;
184337817Scy	}
185337817Scy	pos = hdr.payload + hdr.length;
186337817Scy	os_memcpy(params->salt, hdr.payload, hdr.length);
187337817Scy	params->salt_len = hdr.length;
188337817Scy	wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", params->salt, params->salt_len);
189337817Scy
190337817Scy	/* iterationCount INTEGER */
191337817Scy	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
192337817Scy	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
193337817Scy		wpa_printf(MSG_DEBUG,
194337817Scy			   "PKCS #5: Expected INTEGER - found class %d tag 0x%x",
195337817Scy			   hdr.class, hdr.tag);
196337817Scy		return -1;
197337817Scy	}
198337817Scy	if (hdr.length == 1) {
199337817Scy		params->iter_count = *hdr.payload;
200337817Scy	} else if (hdr.length == 2) {
201337817Scy		params->iter_count = WPA_GET_BE16(hdr.payload);
202337817Scy	} else if (hdr.length == 4) {
203337817Scy		params->iter_count = WPA_GET_BE32(hdr.payload);
204337817Scy	} else {
205337817Scy		wpa_hexdump(MSG_DEBUG,
206337817Scy			    "PKCS #5: Unsupported INTEGER value (iterationCount)",
207337817Scy			    hdr.payload, hdr.length);
208337817Scy		return -1;
209337817Scy	}
210337817Scy	wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x",
211337817Scy		   params->iter_count);
212337817Scy	if (params->iter_count == 0 || params->iter_count > 0xffff) {
213337817Scy		wpa_printf(MSG_INFO, "PKCS #5: Unsupported iterationCount=0x%x",
214337817Scy			   params->iter_count);
215337817Scy		return -1;
216337817Scy	}
217337817Scy
218337817Scy	/* For now, ignore optional keyLength and prf */
219337817Scy
220337817Scy	pos = kdf_end;
221337817Scy
222337817Scy	/* encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} */
223337817Scy
224337817Scy	if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
225337817Scy	    hdr.class != ASN1_CLASS_UNIVERSAL ||
226337817Scy	    hdr.tag != ASN1_TAG_SEQUENCE) {
227337817Scy		wpa_printf(MSG_DEBUG,
228337817Scy			   "PKCS #5: Expected SEQUENCE (encryptionScheme) - found class %d tag 0x%x",
229337817Scy			   hdr.class, hdr.tag);
230337817Scy		return -1;
231337817Scy	}
232337817Scy
233337817Scy	pos = hdr.payload;
234337817Scy	end = hdr.payload + hdr.length;
235337817Scy
236337817Scy	if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
237337817Scy		wpa_printf(MSG_DEBUG,
238337817Scy			   "PKCS #5: Failed to parse OID (encryptionScheme algorithm)");
239337817Scy		return -1;
240337817Scy	}
241337817Scy
242337817Scy	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
243337817Scy	wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 encryptionScheme algorithm %s",
244337817Scy		   obuf);
245337817Scy	if (enc_alg_is_oid(&oid, 7)) {
246337817Scy		params->enc_alg = PBES2_ENC_ALG_DES_EDE3_CBC;
247337817Scy	} else {
248337817Scy		wpa_printf(MSG_DEBUG,
249337817Scy			   "PKCS #5: Unsupported PBES2 encryptionScheme algorithm %s",
250337817Scy			   obuf);
251337817Scy		return -1;
252337817Scy	}
253337817Scy
254337817Scy	/*
255337817Scy	 * RFC 2898, B.2.2:
256337817Scy	 * The parameters field associated with this OID in an
257337817Scy	 * AlgorithmIdentifier shall have type OCTET STRING (SIZE(8)),
258337817Scy	 * specifying the initialization vector for CBC mode.
259337817Scy	 */
260337817Scy	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
261337817Scy	    hdr.class != ASN1_CLASS_UNIVERSAL ||
262337817Scy	    hdr.tag != ASN1_TAG_OCTETSTRING ||
263337817Scy	    hdr.length != 8) {
264337817Scy		wpa_printf(MSG_DEBUG,
265337817Scy			   "PKCS #5: Expected OCTET STRING (SIZE(8)) (IV) - found class %d tag 0x%x size %d",
266337817Scy			   hdr.class, hdr.tag, hdr.length);
267337817Scy		return -1;
268337817Scy	}
269337817Scy	os_memcpy(params->iv, hdr.payload, hdr.length);
270337817Scy	params->iv_len = hdr.length;
271337817Scy	wpa_hexdump(MSG_DEBUG, "PKCS #5: IV", params->iv, params->iv_len);
272337817Scy
273337817Scy	return 0;
274337817Scy}
275337817Scy
276337817Scy
277214501Srpaulostatic int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
278214501Srpaulo			    struct pkcs5_params *params)
279214501Srpaulo{
280214501Srpaulo	struct asn1_hdr hdr;
281214501Srpaulo	const u8 *enc_alg_end, *pos, *end;
282214501Srpaulo	struct asn1_oid oid;
283214501Srpaulo	char obuf[80];
284214501Srpaulo
285214501Srpaulo	/* AlgorithmIdentifier */
286214501Srpaulo
287214501Srpaulo	enc_alg_end = enc_alg + enc_alg_len;
288214501Srpaulo
289214501Srpaulo	os_memset(params, 0, sizeof(*params));
290214501Srpaulo
291214501Srpaulo	if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) {
292214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID "
293214501Srpaulo			   "(algorithm)");
294214501Srpaulo		return -1;
295214501Srpaulo	}
296214501Srpaulo
297214501Srpaulo	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
298214501Srpaulo	wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf);
299214501Srpaulo	params->alg = pkcs5_get_alg(&oid);
300214501Srpaulo	if (params->alg == PKCS5_ALG_UNKNOWN) {
301214501Srpaulo		wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption "
302214501Srpaulo			   "algorithm %s", obuf);
303214501Srpaulo		return -1;
304214501Srpaulo	}
305214501Srpaulo
306337817Scy	if (params->alg == PKCS5_ALG_PBES2)
307337817Scy		return pkcs5_get_params_pbes2(params, pos, enc_alg_end);
308337817Scy
309337817Scy	/* PBES1 */
310337817Scy
311214501Srpaulo	/*
312214501Srpaulo	 * PKCS#5, Section 8
313214501Srpaulo	 * PBEParameter ::= SEQUENCE {
314214501Srpaulo	 *   salt OCTET STRING SIZE(8),
315214501Srpaulo	 *   iterationCount INTEGER }
316337817Scy	 *
317337817Scy	 * Note: The same implementation can be used to parse the PKCS #12
318337817Scy	 * version described in RFC 7292, C:
319337817Scy	 * pkcs-12PbeParams ::= SEQUENCE {
320337817Scy	 *     salt        OCTET STRING,
321337817Scy	 *     iterations  INTEGER
322337817Scy	 * }
323214501Srpaulo	 */
324214501Srpaulo
325214501Srpaulo	if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
326214501Srpaulo	    hdr.class != ASN1_CLASS_UNIVERSAL ||
327214501Srpaulo	    hdr.tag != ASN1_TAG_SEQUENCE) {
328214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE "
329214501Srpaulo			   "(PBEParameter) - found class %d tag 0x%x",
330214501Srpaulo			   hdr.class, hdr.tag);
331214501Srpaulo		return -1;
332214501Srpaulo	}
333214501Srpaulo	pos = hdr.payload;
334214501Srpaulo	end = hdr.payload + hdr.length;
335214501Srpaulo
336337817Scy	/* salt OCTET STRING SIZE(8) (PKCS #5) or OCTET STRING (PKCS #12) */
337214501Srpaulo	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
338214501Srpaulo	    hdr.class != ASN1_CLASS_UNIVERSAL ||
339214501Srpaulo	    hdr.tag != ASN1_TAG_OCTETSTRING ||
340337817Scy	    hdr.length > sizeof(params->salt)) {
341214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) "
342214501Srpaulo			   "(salt) - found class %d tag 0x%x size %d",
343214501Srpaulo			   hdr.class, hdr.tag, hdr.length);
344214501Srpaulo		return -1;
345214501Srpaulo	}
346214501Srpaulo	pos = hdr.payload + hdr.length;
347214501Srpaulo	os_memcpy(params->salt, hdr.payload, hdr.length);
348214501Srpaulo	params->salt_len = hdr.length;
349214501Srpaulo	wpa_hexdump(MSG_DEBUG, "PKCS #5: salt",
350214501Srpaulo		    params->salt, params->salt_len);
351214501Srpaulo
352214501Srpaulo	/* iterationCount INTEGER */
353214501Srpaulo	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
354214501Srpaulo	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
355214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found "
356214501Srpaulo			   "class %d tag 0x%x", hdr.class, hdr.tag);
357214501Srpaulo		return -1;
358214501Srpaulo	}
359214501Srpaulo	if (hdr.length == 1)
360214501Srpaulo		params->iter_count = *hdr.payload;
361214501Srpaulo	else if (hdr.length == 2)
362214501Srpaulo		params->iter_count = WPA_GET_BE16(hdr.payload);
363214501Srpaulo	else if (hdr.length == 4)
364214501Srpaulo		params->iter_count = WPA_GET_BE32(hdr.payload);
365214501Srpaulo	else {
366214501Srpaulo		wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value "
367214501Srpaulo			    " (iterationCount)",
368214501Srpaulo			    hdr.payload, hdr.length);
369214501Srpaulo		return -1;
370214501Srpaulo	}
371214501Srpaulo	wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x",
372214501Srpaulo		   params->iter_count);
373214501Srpaulo	if (params->iter_count == 0 || params->iter_count > 0xffff) {
374214501Srpaulo		wpa_printf(MSG_INFO, "PKCS #5: Unsupported "
375214501Srpaulo			   "iterationCount=0x%x", params->iter_count);
376214501Srpaulo		return -1;
377214501Srpaulo	}
378214501Srpaulo
379214501Srpaulo	return 0;
380214501Srpaulo}
381214501Srpaulo
382214501Srpaulo
383337817Scystatic struct crypto_cipher *
384337817Scypkcs5_crypto_init_pbes2(struct pkcs5_params *params, const char *passwd)
385337817Scy{
386337817Scy	u8 key[24];
387337817Scy
388337817Scy	if (params->enc_alg != PBES2_ENC_ALG_DES_EDE3_CBC ||
389337817Scy	    params->iv_len != 8)
390337817Scy		return NULL;
391337817Scy
392337817Scy	wpa_hexdump_ascii_key(MSG_DEBUG, "PKCS #5: PBES2 password for PBKDF2",
393337817Scy			      passwd, os_strlen(passwd));
394337817Scy	wpa_hexdump(MSG_DEBUG, "PKCS #5: PBES2 salt for PBKDF2",
395337817Scy		    params->salt, params->salt_len);
396337817Scy	wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 PBKDF2 iterations: %u",
397337817Scy		   params->iter_count);
398337817Scy	if (pbkdf2_sha1(passwd, params->salt, params->salt_len,
399337817Scy			params->iter_count, key, sizeof(key)) < 0)
400337817Scy		return NULL;
401337817Scy	wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES EDE3 key", key, sizeof(key));
402337817Scy	wpa_hexdump(MSG_DEBUG, "PKCS #5: DES IV", params->iv, params->iv_len);
403337817Scy
404337817Scy	return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, params->iv,
405337817Scy				  key, sizeof(key));
406337817Scy}
407337817Scy
408337817Scy
409337817Scystatic void add_byte_array_mod(u8 *a, const u8 *b, size_t len)
410337817Scy{
411337817Scy	size_t i;
412337817Scy	unsigned int carry = 0;
413337817Scy
414337817Scy	for (i = len - 1; i < len; i--) {
415337817Scy		carry = carry + a[i] + b[i];
416337817Scy		a[i] = carry & 0xff;
417337817Scy		carry >>= 8;
418337817Scy	}
419337817Scy}
420337817Scy
421337817Scy
422337817Scystatic int pkcs12_key_gen(const u8 *pw, size_t pw_len, const u8 *salt,
423337817Scy			  size_t salt_len, u8 id, unsigned int iter,
424337817Scy			  size_t out_len, u8 *out)
425337817Scy{
426337817Scy	unsigned int u, v, S_len, P_len, i;
427337817Scy	u8 *D = NULL, *I = NULL, *B = NULL, *pos;
428337817Scy	int res = -1;
429337817Scy
430337817Scy	/* RFC 7292, B.2 */
431337817Scy	u = SHA1_MAC_LEN;
432337817Scy	v = 64;
433337817Scy
434337817Scy	/* D = copies of ID */
435337817Scy	D = os_malloc(v);
436337817Scy	if (!D)
437337817Scy		goto done;
438337817Scy	os_memset(D, id, v);
439337817Scy
440337817Scy	/* S = copies of salt; P = copies of password, I = S || P */
441337817Scy	S_len = v * ((salt_len + v - 1) / v);
442337817Scy	P_len = v * ((pw_len + v - 1) / v);
443337817Scy	I = os_malloc(S_len + P_len);
444337817Scy	if (!I)
445337817Scy		goto done;
446337817Scy	pos = I;
447337817Scy	if (salt_len) {
448337817Scy		for (i = 0; i < S_len; i++)
449337817Scy			*pos++ = salt[i % salt_len];
450337817Scy	}
451337817Scy	if (pw_len) {
452337817Scy		for (i = 0; i < P_len; i++)
453337817Scy			*pos++ = pw[i % pw_len];
454337817Scy	}
455337817Scy
456337817Scy	B = os_malloc(v);
457337817Scy	if (!B)
458337817Scy		goto done;
459337817Scy
460337817Scy	for (;;) {
461337817Scy		u8 hash[SHA1_MAC_LEN];
462337817Scy		const u8 *addr[2];
463337817Scy		size_t len[2];
464337817Scy
465337817Scy		addr[0] = D;
466337817Scy		len[0] = v;
467337817Scy		addr[1] = I;
468337817Scy		len[1] = S_len + P_len;
469337817Scy		if (sha1_vector(2, addr, len, hash) < 0)
470337817Scy			goto done;
471337817Scy
472337817Scy		addr[0] = hash;
473337817Scy		len[0] = SHA1_MAC_LEN;
474337817Scy		for (i = 1; i < iter; i++) {
475337817Scy			if (sha1_vector(1, addr, len, hash) < 0)
476337817Scy				goto done;
477337817Scy		}
478337817Scy
479337817Scy		if (out_len <= u) {
480337817Scy			os_memcpy(out, hash, out_len);
481337817Scy			res = 0;
482337817Scy			goto done;
483337817Scy		}
484337817Scy
485337817Scy		os_memcpy(out, hash, u);
486337817Scy		out += u;
487337817Scy		out_len -= u;
488337817Scy
489337817Scy		/* I_j = (I_j + B + 1) mod 2^(v*8) */
490337817Scy		/* B = copies of Ai (final hash value) */
491337817Scy		for (i = 0; i < v; i++)
492337817Scy			B[i] = hash[i % u];
493337817Scy		inc_byte_array(B, v);
494337817Scy		for (i = 0; i < S_len + P_len; i += v)
495337817Scy			add_byte_array_mod(&I[i], B, v);
496337817Scy	}
497337817Scy
498337817Scydone:
499337817Scy	os_free(B);
500337817Scy	os_free(I);
501337817Scy	os_free(D);
502337817Scy	return res;
503337817Scy}
504337817Scy
505337817Scy
506337817Scy#define PKCS12_ID_ENC 1
507337817Scy#define PKCS12_ID_IV 2
508337817Scy#define PKCS12_ID_MAC 3
509337817Scy
510337817Scystatic struct crypto_cipher *
511337817Scypkcs12_crypto_init_sha1(struct pkcs5_params *params, const char *passwd)
512337817Scy{
513337817Scy	unsigned int i;
514337817Scy	u8 *pw;
515337817Scy	size_t pw_len;
516337817Scy	u8 key[24];
517337817Scy	u8 iv[8];
518337817Scy
519337817Scy	if (params->alg != PKCS5_ALG_SHA1_3DES_CBC)
520337817Scy		return NULL;
521337817Scy
522337817Scy	pw_len = passwd ? os_strlen(passwd) : 0;
523337817Scy	pw = os_malloc(2 * (pw_len + 1));
524337817Scy	if (!pw)
525337817Scy		return NULL;
526337817Scy	if (pw_len) {
527337817Scy		for (i = 0; i <= pw_len; i++)
528337817Scy			WPA_PUT_BE16(&pw[2 * i], passwd[i]);
529337817Scy		pw_len = 2 * (pw_len + 1);
530337817Scy	}
531337817Scy
532337817Scy	if (pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len,
533337817Scy			   PKCS12_ID_ENC, params->iter_count,
534337817Scy			   sizeof(key), key) < 0 ||
535337817Scy	    pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len,
536337817Scy			   PKCS12_ID_IV, params->iter_count,
537337817Scy			   sizeof(iv), iv) < 0) {
538337817Scy		os_free(pw);
539337817Scy		return NULL;
540337817Scy	}
541337817Scy
542337817Scy	os_free(pw);
543337817Scy
544337817Scy	wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES key", key, sizeof(key));
545337817Scy	wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES IV", iv, sizeof(iv));
546337817Scy
547337817Scy	return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, iv, key, sizeof(key));
548337817Scy}
549337817Scy
550337817Scy
551214501Srpaulostatic struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
552214501Srpaulo						const char *passwd)
553214501Srpaulo{
554214501Srpaulo	unsigned int i;
555214501Srpaulo	u8 hash[MD5_MAC_LEN];
556214501Srpaulo	const u8 *addr[2];
557214501Srpaulo	size_t len[2];
558214501Srpaulo
559337817Scy	if (params->alg == PKCS5_ALG_PBES2)
560337817Scy		return pkcs5_crypto_init_pbes2(params, passwd);
561337817Scy
562337817Scy	if (params->alg == PKCS5_ALG_SHA1_3DES_CBC)
563337817Scy		return pkcs12_crypto_init_sha1(params, passwd);
564337817Scy
565214501Srpaulo	if (params->alg != PKCS5_ALG_MD5_DES_CBC)
566214501Srpaulo		return NULL;
567214501Srpaulo
568214501Srpaulo	addr[0] = (const u8 *) passwd;
569214501Srpaulo	len[0] = os_strlen(passwd);
570214501Srpaulo	addr[1] = params->salt;
571214501Srpaulo	len[1] = params->salt_len;
572214501Srpaulo	if (md5_vector(2, addr, len, hash) < 0)
573214501Srpaulo		return NULL;
574214501Srpaulo	addr[0] = hash;
575214501Srpaulo	len[0] = MD5_MAC_LEN;
576214501Srpaulo	for (i = 1; i < params->iter_count; i++) {
577214501Srpaulo		if (md5_vector(1, addr, len, hash) < 0)
578214501Srpaulo			return NULL;
579214501Srpaulo	}
580214501Srpaulo	/* TODO: DES key parity bits(?) */
581214501Srpaulo	wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8);
582214501Srpaulo	wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8);
583214501Srpaulo
584214501Srpaulo	return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8);
585214501Srpaulo}
586214501Srpaulo
587214501Srpaulo
588214501Srpaulou8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
589214501Srpaulo		   const u8 *enc_data, size_t enc_data_len,
590214501Srpaulo		   const char *passwd, size_t *data_len)
591214501Srpaulo{
592214501Srpaulo	struct crypto_cipher *ctx;
593214501Srpaulo	u8 *eb, pad;
594214501Srpaulo	struct pkcs5_params params;
595214501Srpaulo	unsigned int i;
596214501Srpaulo
597214501Srpaulo	if (pkcs5_get_params(enc_alg, enc_alg_len, &params) < 0) {
598214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters");
599214501Srpaulo		return NULL;
600214501Srpaulo	}
601214501Srpaulo
602214501Srpaulo	ctx = pkcs5_crypto_init(&params, passwd);
603214501Srpaulo	if (ctx == NULL) {
604214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto");
605214501Srpaulo		return NULL;
606214501Srpaulo	}
607214501Srpaulo
608214501Srpaulo	/* PKCS #5, Section 7 - Decryption process */
609214501Srpaulo	if (enc_data_len < 16 || enc_data_len % 8) {
610214501Srpaulo		wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext "
611214501Srpaulo			   "%d", (int) enc_data_len);
612214501Srpaulo		crypto_cipher_deinit(ctx);
613214501Srpaulo		return NULL;
614214501Srpaulo	}
615214501Srpaulo
616214501Srpaulo	eb = os_malloc(enc_data_len);
617214501Srpaulo	if (eb == NULL) {
618214501Srpaulo		crypto_cipher_deinit(ctx);
619214501Srpaulo		return NULL;
620214501Srpaulo	}
621214501Srpaulo
622214501Srpaulo	if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) {
623214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB");
624214501Srpaulo		crypto_cipher_deinit(ctx);
625214501Srpaulo		os_free(eb);
626214501Srpaulo		return NULL;
627214501Srpaulo	}
628214501Srpaulo	crypto_cipher_deinit(ctx);
629214501Srpaulo
630214501Srpaulo	pad = eb[enc_data_len - 1];
631214501Srpaulo	if (pad > 8) {
632214501Srpaulo		wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad);
633214501Srpaulo		os_free(eb);
634214501Srpaulo		return NULL;
635214501Srpaulo	}
636214501Srpaulo	for (i = enc_data_len - pad; i < enc_data_len; i++) {
637214501Srpaulo		if (eb[i] != pad) {
638214501Srpaulo			wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS",
639214501Srpaulo				    eb + enc_data_len - pad, pad);
640214501Srpaulo			os_free(eb);
641214501Srpaulo			return NULL;
642214501Srpaulo		}
643214501Srpaulo	}
644214501Srpaulo
645214501Srpaulo	wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)",
646214501Srpaulo			eb, enc_data_len - pad);
647214501Srpaulo
648214501Srpaulo	*data_len = enc_data_len - pad;
649214501Srpaulo	return eb;
650214501Srpaulo}
651