1189251Ssam/*
2189251Ssam * WPA Supplicant / wrapper functions for libcrypto
3252726Srpaulo * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#include "includes.h"
10189251Ssam#include <openssl/opensslv.h>
11214734Srpaulo#include <openssl/err.h>
12189251Ssam#include <openssl/des.h>
13189251Ssam#include <openssl/aes.h>
14189251Ssam#include <openssl/bn.h>
15189251Ssam#include <openssl/evp.h>
16214734Srpaulo#include <openssl/dh.h>
17252726Srpaulo#include <openssl/hmac.h>
18252726Srpaulo#include <openssl/rand.h>
19252726Srpaulo#ifdef CONFIG_OPENSSL_CMAC
20252726Srpaulo#include <openssl/cmac.h>
21252726Srpaulo#endif /* CONFIG_OPENSSL_CMAC */
22189251Ssam
23189251Ssam#include "common.h"
24214734Srpaulo#include "wpabuf.h"
25214734Srpaulo#include "dh_group5.h"
26189251Ssam#include "crypto.h"
27189251Ssam
28189251Ssam#if OPENSSL_VERSION_NUMBER < 0x00907000
29189251Ssam#define DES_key_schedule des_key_schedule
30189251Ssam#define DES_cblock des_cblock
31189251Ssam#define DES_set_key(key, schedule) des_set_key((key), *(schedule))
32189251Ssam#define DES_ecb_encrypt(input, output, ks, enc) \
33189251Ssam	des_ecb_encrypt((input), (output), *(ks), (enc))
34189251Ssam#endif /* openssl < 0.9.7 */
35189251Ssam
36214734Srpaulostatic BIGNUM * get_group5_prime(void)
37214734Srpaulo{
38214734Srpaulo#if OPENSSL_VERSION_NUMBER < 0x00908000
39214734Srpaulo	static const unsigned char RFC3526_PRIME_1536[] = {
40214734Srpaulo		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
41214734Srpaulo		0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
42214734Srpaulo		0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
43214734Srpaulo		0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
44214734Srpaulo		0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
45214734Srpaulo		0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
46214734Srpaulo		0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
47214734Srpaulo		0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
48214734Srpaulo		0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
49214734Srpaulo		0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
50214734Srpaulo		0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
51214734Srpaulo		0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
52214734Srpaulo		0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
53214734Srpaulo		0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
54214734Srpaulo		0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
55214734Srpaulo		0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
56214734Srpaulo	};
57214734Srpaulo        return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
58214734Srpaulo#else /* openssl < 0.9.8 */
59214734Srpaulo	return get_rfc3526_prime_1536(NULL);
60214734Srpaulo#endif /* openssl < 0.9.8 */
61214734Srpaulo}
62189251Ssam
63214734Srpaulo#if OPENSSL_VERSION_NUMBER < 0x00908000
64214734Srpaulo#ifndef OPENSSL_NO_SHA256
65214734Srpaulo#ifndef OPENSSL_FIPS
66214734Srpaulo#define NO_SHA256_WRAPPER
67214734Srpaulo#endif
68214734Srpaulo#endif
69214734Srpaulo
70214734Srpaulo#endif /* openssl < 0.9.8 */
71214734Srpaulo
72214734Srpaulo#ifdef OPENSSL_NO_SHA256
73214734Srpaulo#define NO_SHA256_WRAPPER
74214734Srpaulo#endif
75214734Srpaulo
76252726Srpaulostatic int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
77252726Srpaulo				 const u8 *addr[], const size_t *len, u8 *mac)
78189251Ssam{
79214734Srpaulo	EVP_MD_CTX ctx;
80189251Ssam	size_t i;
81214734Srpaulo	unsigned int mac_len;
82189251Ssam
83214734Srpaulo	EVP_MD_CTX_init(&ctx);
84214734Srpaulo	if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
85214734Srpaulo		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
86214734Srpaulo			   ERR_error_string(ERR_get_error(), NULL));
87214734Srpaulo		return -1;
88214734Srpaulo	}
89214734Srpaulo	for (i = 0; i < num_elem; i++) {
90214734Srpaulo		if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) {
91214734Srpaulo			wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate "
92214734Srpaulo				   "failed: %s",
93214734Srpaulo				   ERR_error_string(ERR_get_error(), NULL));
94214734Srpaulo			return -1;
95214734Srpaulo		}
96214734Srpaulo	}
97214734Srpaulo	if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
98214734Srpaulo		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
99214734Srpaulo			   ERR_error_string(ERR_get_error(), NULL));
100214734Srpaulo		return -1;
101214734Srpaulo	}
102214734Srpaulo
103214734Srpaulo	return 0;
104189251Ssam}
105189251Ssam
106189251Ssam
107214734Srpauloint md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
108214734Srpaulo{
109252726Srpaulo	return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
110214734Srpaulo}
111214734Srpaulo
112214734Srpaulo
113189251Ssamvoid des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
114189251Ssam{
115189251Ssam	u8 pkey[8], next, tmp;
116189251Ssam	int i;
117189251Ssam	DES_key_schedule ks;
118189251Ssam
119189251Ssam	/* Add parity bits to the key */
120189251Ssam	next = 0;
121189251Ssam	for (i = 0; i < 7; i++) {
122189251Ssam		tmp = key[i];
123189251Ssam		pkey[i] = (tmp >> i) | next | 1;
124189251Ssam		next = tmp << (7 - i);
125189251Ssam	}
126189251Ssam	pkey[i] = next | 1;
127189251Ssam
128189251Ssam	DES_set_key(&pkey, &ks);
129189251Ssam	DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
130189251Ssam			DES_ENCRYPT);
131189251Ssam}
132189251Ssam
133189251Ssam
134214734Srpauloint rc4_skip(const u8 *key, size_t keylen, size_t skip,
135214734Srpaulo	     u8 *data, size_t data_len)
136189251Ssam{
137214734Srpaulo#ifdef OPENSSL_NO_RC4
138214734Srpaulo	return -1;
139214734Srpaulo#else /* OPENSSL_NO_RC4 */
140214734Srpaulo	EVP_CIPHER_CTX ctx;
141214734Srpaulo	int outl;
142214734Srpaulo	int res = -1;
143214734Srpaulo	unsigned char skip_buf[16];
144189251Ssam
145214734Srpaulo	EVP_CIPHER_CTX_init(&ctx);
146214734Srpaulo	if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) ||
147214734Srpaulo	    !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
148214734Srpaulo	    !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) ||
149214734Srpaulo	    !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1))
150214734Srpaulo		goto out;
151189251Ssam
152214734Srpaulo	while (skip >= sizeof(skip_buf)) {
153214734Srpaulo		size_t len = skip;
154214734Srpaulo		if (len > sizeof(skip_buf))
155214734Srpaulo			len = sizeof(skip_buf);
156214734Srpaulo		if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len))
157214734Srpaulo			goto out;
158214734Srpaulo		skip -= len;
159214734Srpaulo	}
160189251Ssam
161214734Srpaulo	if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
162214734Srpaulo		res = 0;
163189251Ssam
164214734Srpauloout:
165214734Srpaulo	EVP_CIPHER_CTX_cleanup(&ctx);
166214734Srpaulo	return res;
167214734Srpaulo#endif /* OPENSSL_NO_RC4 */
168189251Ssam}
169189251Ssam
170189251Ssam
171214734Srpauloint md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
172189251Ssam{
173252726Srpaulo	return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
174189251Ssam}
175189251Ssam
176189251Ssam
177214734Srpauloint sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
178214734Srpaulo{
179252726Srpaulo	return openssl_digest_vector(EVP_sha1(), num_elem, addr, len, mac);
180214734Srpaulo}
181189251Ssam
182189251Ssam
183214734Srpaulo#ifndef NO_SHA256_WRAPPER
184214734Srpauloint sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
185214734Srpaulo		  u8 *mac)
186214734Srpaulo{
187252726Srpaulo	return openssl_digest_vector(EVP_sha256(), num_elem, addr, len, mac);
188189251Ssam}
189214734Srpaulo#endif /* NO_SHA256_WRAPPER */
190189251Ssam
191189251Ssam
192252726Srpaulostatic const EVP_CIPHER * aes_get_evp_cipher(size_t keylen)
193252726Srpaulo{
194252726Srpaulo	switch (keylen) {
195252726Srpaulo	case 16:
196252726Srpaulo		return EVP_aes_128_ecb();
197252726Srpaulo	case 24:
198252726Srpaulo		return EVP_aes_192_ecb();
199252726Srpaulo	case 32:
200252726Srpaulo		return EVP_aes_256_ecb();
201252726Srpaulo	}
202252726Srpaulo
203252726Srpaulo	return NULL;
204252726Srpaulo}
205252726Srpaulo
206252726Srpaulo
207189251Ssamvoid * aes_encrypt_init(const u8 *key, size_t len)
208189251Ssam{
209252726Srpaulo	EVP_CIPHER_CTX *ctx;
210252726Srpaulo	const EVP_CIPHER *type;
211252726Srpaulo
212252726Srpaulo	type = aes_get_evp_cipher(len);
213252726Srpaulo	if (type == NULL)
214189251Ssam		return NULL;
215252726Srpaulo
216252726Srpaulo	ctx = os_malloc(sizeof(*ctx));
217252726Srpaulo	if (ctx == NULL)
218189251Ssam		return NULL;
219252726Srpaulo	EVP_CIPHER_CTX_init(ctx);
220252726Srpaulo	if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
221252726Srpaulo		os_free(ctx);
222252726Srpaulo		return NULL;
223189251Ssam	}
224252726Srpaulo	EVP_CIPHER_CTX_set_padding(ctx, 0);
225252726Srpaulo	return ctx;
226189251Ssam}
227189251Ssam
228189251Ssam
229189251Ssamvoid aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
230189251Ssam{
231252726Srpaulo	EVP_CIPHER_CTX *c = ctx;
232252726Srpaulo	int clen = 16;
233252726Srpaulo	if (EVP_EncryptUpdate(c, crypt, &clen, plain, 16) != 1) {
234252726Srpaulo		wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptUpdate failed: %s",
235252726Srpaulo			   ERR_error_string(ERR_get_error(), NULL));
236252726Srpaulo	}
237189251Ssam}
238189251Ssam
239189251Ssam
240189251Ssamvoid aes_encrypt_deinit(void *ctx)
241189251Ssam{
242252726Srpaulo	EVP_CIPHER_CTX *c = ctx;
243252726Srpaulo	u8 buf[16];
244252726Srpaulo	int len = sizeof(buf);
245252726Srpaulo	if (EVP_EncryptFinal_ex(c, buf, &len) != 1) {
246252726Srpaulo		wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptFinal_ex failed: "
247252726Srpaulo			   "%s", ERR_error_string(ERR_get_error(), NULL));
248252726Srpaulo	}
249252726Srpaulo	if (len != 0) {
250252726Srpaulo		wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
251252726Srpaulo			   "in AES encrypt", len);
252252726Srpaulo	}
253252726Srpaulo	EVP_CIPHER_CTX_cleanup(c);
254252726Srpaulo	os_free(c);
255189251Ssam}
256189251Ssam
257189251Ssam
258189251Ssamvoid * aes_decrypt_init(const u8 *key, size_t len)
259189251Ssam{
260252726Srpaulo	EVP_CIPHER_CTX *ctx;
261252726Srpaulo	const EVP_CIPHER *type;
262252726Srpaulo
263252726Srpaulo	type = aes_get_evp_cipher(len);
264252726Srpaulo	if (type == NULL)
265189251Ssam		return NULL;
266252726Srpaulo
267252726Srpaulo	ctx = os_malloc(sizeof(*ctx));
268252726Srpaulo	if (ctx == NULL)
269189251Ssam		return NULL;
270252726Srpaulo	EVP_CIPHER_CTX_init(ctx);
271252726Srpaulo	if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
272252726Srpaulo		os_free(ctx);
273252726Srpaulo		return NULL;
274189251Ssam	}
275252726Srpaulo	EVP_CIPHER_CTX_set_padding(ctx, 0);
276252726Srpaulo	return ctx;
277189251Ssam}
278189251Ssam
279189251Ssam
280189251Ssamvoid aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
281189251Ssam{
282252726Srpaulo	EVP_CIPHER_CTX *c = ctx;
283252726Srpaulo	int plen = 16;
284252726Srpaulo	if (EVP_DecryptUpdate(c, plain, &plen, crypt, 16) != 1) {
285252726Srpaulo		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptUpdate failed: %s",
286252726Srpaulo			   ERR_error_string(ERR_get_error(), NULL));
287252726Srpaulo	}
288189251Ssam}
289189251Ssam
290189251Ssam
291189251Ssamvoid aes_decrypt_deinit(void *ctx)
292189251Ssam{
293252726Srpaulo	EVP_CIPHER_CTX *c = ctx;
294252726Srpaulo	u8 buf[16];
295252726Srpaulo	int len = sizeof(buf);
296252726Srpaulo	if (EVP_DecryptFinal_ex(c, buf, &len) != 1) {
297252726Srpaulo		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptFinal_ex failed: "
298252726Srpaulo			   "%s", ERR_error_string(ERR_get_error(), NULL));
299252726Srpaulo	}
300252726Srpaulo	if (len != 0) {
301252726Srpaulo		wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
302252726Srpaulo			   "in AES decrypt", len);
303252726Srpaulo	}
304252726Srpaulo	EVP_CIPHER_CTX_cleanup(c);
305189251Ssam	os_free(ctx);
306189251Ssam}
307189251Ssam
308189251Ssam
309189251Ssamint crypto_mod_exp(const u8 *base, size_t base_len,
310189251Ssam		   const u8 *power, size_t power_len,
311189251Ssam		   const u8 *modulus, size_t modulus_len,
312189251Ssam		   u8 *result, size_t *result_len)
313189251Ssam{
314189251Ssam	BIGNUM *bn_base, *bn_exp, *bn_modulus, *bn_result;
315189251Ssam	int ret = -1;
316189251Ssam	BN_CTX *ctx;
317189251Ssam
318189251Ssam	ctx = BN_CTX_new();
319189251Ssam	if (ctx == NULL)
320189251Ssam		return -1;
321189251Ssam
322189251Ssam	bn_base = BN_bin2bn(base, base_len, NULL);
323189251Ssam	bn_exp = BN_bin2bn(power, power_len, NULL);
324189251Ssam	bn_modulus = BN_bin2bn(modulus, modulus_len, NULL);
325189251Ssam	bn_result = BN_new();
326189251Ssam
327189251Ssam	if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
328189251Ssam	    bn_result == NULL)
329189251Ssam		goto error;
330189251Ssam
331189251Ssam	if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
332189251Ssam		goto error;
333189251Ssam
334189251Ssam	*result_len = BN_bn2bin(bn_result, result);
335189251Ssam	ret = 0;
336189251Ssam
337189251Ssamerror:
338189251Ssam	BN_free(bn_base);
339189251Ssam	BN_free(bn_exp);
340189251Ssam	BN_free(bn_modulus);
341189251Ssam	BN_free(bn_result);
342189251Ssam	BN_CTX_free(ctx);
343189251Ssam	return ret;
344189251Ssam}
345189251Ssam
346189251Ssam
347189251Ssamstruct crypto_cipher {
348189251Ssam	EVP_CIPHER_CTX enc;
349189251Ssam	EVP_CIPHER_CTX dec;
350189251Ssam};
351189251Ssam
352189251Ssam
353189251Ssamstruct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
354189251Ssam					  const u8 *iv, const u8 *key,
355189251Ssam					  size_t key_len)
356189251Ssam{
357189251Ssam	struct crypto_cipher *ctx;
358189251Ssam	const EVP_CIPHER *cipher;
359189251Ssam
360189251Ssam	ctx = os_zalloc(sizeof(*ctx));
361189251Ssam	if (ctx == NULL)
362189251Ssam		return NULL;
363189251Ssam
364189251Ssam	switch (alg) {
365189251Ssam#ifndef OPENSSL_NO_RC4
366189251Ssam	case CRYPTO_CIPHER_ALG_RC4:
367189251Ssam		cipher = EVP_rc4();
368189251Ssam		break;
369189251Ssam#endif /* OPENSSL_NO_RC4 */
370189251Ssam#ifndef OPENSSL_NO_AES
371189251Ssam	case CRYPTO_CIPHER_ALG_AES:
372189251Ssam		switch (key_len) {
373189251Ssam		case 16:
374189251Ssam			cipher = EVP_aes_128_cbc();
375189251Ssam			break;
376189251Ssam		case 24:
377189251Ssam			cipher = EVP_aes_192_cbc();
378189251Ssam			break;
379189251Ssam		case 32:
380189251Ssam			cipher = EVP_aes_256_cbc();
381189251Ssam			break;
382189251Ssam		default:
383189251Ssam			os_free(ctx);
384189251Ssam			return NULL;
385189251Ssam		}
386189251Ssam		break;
387189251Ssam#endif /* OPENSSL_NO_AES */
388189251Ssam#ifndef OPENSSL_NO_DES
389189251Ssam	case CRYPTO_CIPHER_ALG_3DES:
390189251Ssam		cipher = EVP_des_ede3_cbc();
391189251Ssam		break;
392189251Ssam	case CRYPTO_CIPHER_ALG_DES:
393189251Ssam		cipher = EVP_des_cbc();
394189251Ssam		break;
395189251Ssam#endif /* OPENSSL_NO_DES */
396189251Ssam#ifndef OPENSSL_NO_RC2
397189251Ssam	case CRYPTO_CIPHER_ALG_RC2:
398189251Ssam		cipher = EVP_rc2_ecb();
399189251Ssam		break;
400189251Ssam#endif /* OPENSSL_NO_RC2 */
401189251Ssam	default:
402189251Ssam		os_free(ctx);
403189251Ssam		return NULL;
404189251Ssam	}
405189251Ssam
406189251Ssam	EVP_CIPHER_CTX_init(&ctx->enc);
407189251Ssam	EVP_CIPHER_CTX_set_padding(&ctx->enc, 0);
408189251Ssam	if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) ||
409189251Ssam	    !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) ||
410214734Srpaulo	    !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) {
411189251Ssam		EVP_CIPHER_CTX_cleanup(&ctx->enc);
412189251Ssam		os_free(ctx);
413189251Ssam		return NULL;
414189251Ssam	}
415189251Ssam
416189251Ssam	EVP_CIPHER_CTX_init(&ctx->dec);
417189251Ssam	EVP_CIPHER_CTX_set_padding(&ctx->dec, 0);
418189251Ssam	if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) ||
419189251Ssam	    !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) ||
420214734Srpaulo	    !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) {
421189251Ssam		EVP_CIPHER_CTX_cleanup(&ctx->enc);
422189251Ssam		EVP_CIPHER_CTX_cleanup(&ctx->dec);
423189251Ssam		os_free(ctx);
424189251Ssam		return NULL;
425189251Ssam	}
426189251Ssam
427189251Ssam	return ctx;
428189251Ssam}
429189251Ssam
430189251Ssam
431189251Ssamint crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
432189251Ssam			  u8 *crypt, size_t len)
433189251Ssam{
434189251Ssam	int outl;
435189251Ssam	if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
436189251Ssam		return -1;
437189251Ssam	return 0;
438189251Ssam}
439189251Ssam
440189251Ssam
441189251Ssamint crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
442189251Ssam			  u8 *plain, size_t len)
443189251Ssam{
444189251Ssam	int outl;
445189251Ssam	outl = len;
446189251Ssam	if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len))
447189251Ssam		return -1;
448189251Ssam	return 0;
449189251Ssam}
450189251Ssam
451189251Ssam
452189251Ssamvoid crypto_cipher_deinit(struct crypto_cipher *ctx)
453189251Ssam{
454189251Ssam	EVP_CIPHER_CTX_cleanup(&ctx->enc);
455189251Ssam	EVP_CIPHER_CTX_cleanup(&ctx->dec);
456189251Ssam	os_free(ctx);
457189251Ssam}
458214734Srpaulo
459214734Srpaulo
460214734Srpaulovoid * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
461214734Srpaulo{
462214734Srpaulo	DH *dh;
463214734Srpaulo	struct wpabuf *pubkey = NULL, *privkey = NULL;
464214734Srpaulo	size_t publen, privlen;
465214734Srpaulo
466214734Srpaulo	*priv = NULL;
467214734Srpaulo	*publ = NULL;
468214734Srpaulo
469214734Srpaulo	dh = DH_new();
470214734Srpaulo	if (dh == NULL)
471214734Srpaulo		return NULL;
472214734Srpaulo
473214734Srpaulo	dh->g = BN_new();
474214734Srpaulo	if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
475214734Srpaulo		goto err;
476214734Srpaulo
477214734Srpaulo	dh->p = get_group5_prime();
478214734Srpaulo	if (dh->p == NULL)
479214734Srpaulo		goto err;
480214734Srpaulo
481214734Srpaulo	if (DH_generate_key(dh) != 1)
482214734Srpaulo		goto err;
483214734Srpaulo
484214734Srpaulo	publen = BN_num_bytes(dh->pub_key);
485214734Srpaulo	pubkey = wpabuf_alloc(publen);
486214734Srpaulo	if (pubkey == NULL)
487214734Srpaulo		goto err;
488214734Srpaulo	privlen = BN_num_bytes(dh->priv_key);
489214734Srpaulo	privkey = wpabuf_alloc(privlen);
490214734Srpaulo	if (privkey == NULL)
491214734Srpaulo		goto err;
492214734Srpaulo
493214734Srpaulo	BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen));
494214734Srpaulo	BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen));
495214734Srpaulo
496214734Srpaulo	*priv = privkey;
497214734Srpaulo	*publ = pubkey;
498214734Srpaulo	return dh;
499214734Srpaulo
500214734Srpauloerr:
501214734Srpaulo	wpabuf_free(pubkey);
502214734Srpaulo	wpabuf_free(privkey);
503214734Srpaulo	DH_free(dh);
504214734Srpaulo	return NULL;
505214734Srpaulo}
506214734Srpaulo
507214734Srpaulo
508252726Srpaulovoid * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
509252726Srpaulo{
510252726Srpaulo	DH *dh;
511252726Srpaulo
512252726Srpaulo	dh = DH_new();
513252726Srpaulo	if (dh == NULL)
514252726Srpaulo		return NULL;
515252726Srpaulo
516252726Srpaulo	dh->g = BN_new();
517252726Srpaulo	if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
518252726Srpaulo		goto err;
519252726Srpaulo
520252726Srpaulo	dh->p = get_group5_prime();
521252726Srpaulo	if (dh->p == NULL)
522252726Srpaulo		goto err;
523252726Srpaulo
524252726Srpaulo	dh->priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
525252726Srpaulo	if (dh->priv_key == NULL)
526252726Srpaulo		goto err;
527252726Srpaulo
528252726Srpaulo	dh->pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
529252726Srpaulo	if (dh->pub_key == NULL)
530252726Srpaulo		goto err;
531252726Srpaulo
532252726Srpaulo	if (DH_generate_key(dh) != 1)
533252726Srpaulo		goto err;
534252726Srpaulo
535252726Srpaulo	return dh;
536252726Srpaulo
537252726Srpauloerr:
538252726Srpaulo	DH_free(dh);
539252726Srpaulo	return NULL;
540252726Srpaulo}
541252726Srpaulo
542252726Srpaulo
543214734Srpaulostruct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
544214734Srpaulo				  const struct wpabuf *own_private)
545214734Srpaulo{
546214734Srpaulo	BIGNUM *pub_key;
547214734Srpaulo	struct wpabuf *res = NULL;
548214734Srpaulo	size_t rlen;
549214734Srpaulo	DH *dh = ctx;
550214734Srpaulo	int keylen;
551214734Srpaulo
552214734Srpaulo	if (ctx == NULL)
553214734Srpaulo		return NULL;
554214734Srpaulo
555214734Srpaulo	pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public),
556214734Srpaulo			    NULL);
557214734Srpaulo	if (pub_key == NULL)
558214734Srpaulo		return NULL;
559214734Srpaulo
560214734Srpaulo	rlen = DH_size(dh);
561214734Srpaulo	res = wpabuf_alloc(rlen);
562214734Srpaulo	if (res == NULL)
563214734Srpaulo		goto err;
564214734Srpaulo
565214734Srpaulo	keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh);
566214734Srpaulo	if (keylen < 0)
567214734Srpaulo		goto err;
568214734Srpaulo	wpabuf_put(res, keylen);
569214734Srpaulo	BN_free(pub_key);
570214734Srpaulo
571214734Srpaulo	return res;
572214734Srpaulo
573214734Srpauloerr:
574214734Srpaulo	BN_free(pub_key);
575214734Srpaulo	wpabuf_free(res);
576214734Srpaulo	return NULL;
577214734Srpaulo}
578214734Srpaulo
579214734Srpaulo
580214734Srpaulovoid dh5_free(void *ctx)
581214734Srpaulo{
582214734Srpaulo	DH *dh;
583214734Srpaulo	if (ctx == NULL)
584214734Srpaulo		return;
585214734Srpaulo	dh = ctx;
586214734Srpaulo	DH_free(dh);
587214734Srpaulo}
588252726Srpaulo
589252726Srpaulo
590252726Srpaulostruct crypto_hash {
591252726Srpaulo	HMAC_CTX ctx;
592252726Srpaulo};
593252726Srpaulo
594252726Srpaulo
595252726Srpaulostruct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
596252726Srpaulo				      size_t key_len)
597252726Srpaulo{
598252726Srpaulo	struct crypto_hash *ctx;
599252726Srpaulo	const EVP_MD *md;
600252726Srpaulo
601252726Srpaulo	switch (alg) {
602252726Srpaulo#ifndef OPENSSL_NO_MD5
603252726Srpaulo	case CRYPTO_HASH_ALG_HMAC_MD5:
604252726Srpaulo		md = EVP_md5();
605252726Srpaulo		break;
606252726Srpaulo#endif /* OPENSSL_NO_MD5 */
607252726Srpaulo#ifndef OPENSSL_NO_SHA
608252726Srpaulo	case CRYPTO_HASH_ALG_HMAC_SHA1:
609252726Srpaulo		md = EVP_sha1();
610252726Srpaulo		break;
611252726Srpaulo#endif /* OPENSSL_NO_SHA */
612252726Srpaulo#ifndef OPENSSL_NO_SHA256
613252726Srpaulo#ifdef CONFIG_SHA256
614252726Srpaulo	case CRYPTO_HASH_ALG_HMAC_SHA256:
615252726Srpaulo		md = EVP_sha256();
616252726Srpaulo		break;
617252726Srpaulo#endif /* CONFIG_SHA256 */
618252726Srpaulo#endif /* OPENSSL_NO_SHA256 */
619252726Srpaulo	default:
620252726Srpaulo		return NULL;
621252726Srpaulo	}
622252726Srpaulo
623252726Srpaulo	ctx = os_zalloc(sizeof(*ctx));
624252726Srpaulo	if (ctx == NULL)
625252726Srpaulo		return NULL;
626252726Srpaulo	HMAC_CTX_init(&ctx->ctx);
627252726Srpaulo
628252726Srpaulo#if OPENSSL_VERSION_NUMBER < 0x00909000
629252726Srpaulo	HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
630252726Srpaulo#else /* openssl < 0.9.9 */
631252726Srpaulo	if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
632252726Srpaulo		os_free(ctx);
633252726Srpaulo		return NULL;
634252726Srpaulo	}
635252726Srpaulo#endif /* openssl < 0.9.9 */
636252726Srpaulo
637252726Srpaulo	return ctx;
638252726Srpaulo}
639252726Srpaulo
640252726Srpaulo
641252726Srpaulovoid crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
642252726Srpaulo{
643252726Srpaulo	if (ctx == NULL)
644252726Srpaulo		return;
645252726Srpaulo	HMAC_Update(&ctx->ctx, data, len);
646252726Srpaulo}
647252726Srpaulo
648252726Srpaulo
649252726Srpauloint crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
650252726Srpaulo{
651252726Srpaulo	unsigned int mdlen;
652252726Srpaulo	int res;
653252726Srpaulo
654252726Srpaulo	if (ctx == NULL)
655252726Srpaulo		return -2;
656252726Srpaulo
657252726Srpaulo	if (mac == NULL || len == NULL) {
658252726Srpaulo		os_free(ctx);
659252726Srpaulo		return 0;
660252726Srpaulo	}
661252726Srpaulo
662252726Srpaulo	mdlen = *len;
663252726Srpaulo#if OPENSSL_VERSION_NUMBER < 0x00909000
664252726Srpaulo	HMAC_Final(&ctx->ctx, mac, &mdlen);
665252726Srpaulo	res = 1;
666252726Srpaulo#else /* openssl < 0.9.9 */
667252726Srpaulo	res = HMAC_Final(&ctx->ctx, mac, &mdlen);
668252726Srpaulo#endif /* openssl < 0.9.9 */
669252726Srpaulo	HMAC_CTX_cleanup(&ctx->ctx);
670252726Srpaulo	os_free(ctx);
671252726Srpaulo
672252726Srpaulo	if (res == 1) {
673252726Srpaulo		*len = mdlen;
674252726Srpaulo		return 0;
675252726Srpaulo	}
676252726Srpaulo
677252726Srpaulo	return -1;
678252726Srpaulo}
679252726Srpaulo
680252726Srpaulo
681252726Srpauloint pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
682252726Srpaulo		int iterations, u8 *buf, size_t buflen)
683252726Srpaulo{
684252726Srpaulo#if OPENSSL_VERSION_NUMBER < 0x00908000
685252726Srpaulo	if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase),
686252726Srpaulo				   (unsigned char *) ssid,
687252726Srpaulo				   ssid_len, 4096, buflen, buf) != 1)
688252726Srpaulo		return -1;
689252726Srpaulo#else /* openssl < 0.9.8 */
690252726Srpaulo	if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
691252726Srpaulo				   ssid_len, 4096, buflen, buf) != 1)
692252726Srpaulo		return -1;
693252726Srpaulo#endif /* openssl < 0.9.8 */
694252726Srpaulo	return 0;
695252726Srpaulo}
696252726Srpaulo
697252726Srpaulo
698252726Srpauloint hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
699252726Srpaulo		     const u8 *addr[], const size_t *len, u8 *mac)
700252726Srpaulo{
701252726Srpaulo	HMAC_CTX ctx;
702252726Srpaulo	size_t i;
703252726Srpaulo	unsigned int mdlen;
704252726Srpaulo	int res;
705252726Srpaulo
706252726Srpaulo	HMAC_CTX_init(&ctx);
707252726Srpaulo#if OPENSSL_VERSION_NUMBER < 0x00909000
708252726Srpaulo	HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL);
709252726Srpaulo#else /* openssl < 0.9.9 */
710252726Srpaulo	if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL) != 1)
711252726Srpaulo		return -1;
712252726Srpaulo#endif /* openssl < 0.9.9 */
713252726Srpaulo
714252726Srpaulo	for (i = 0; i < num_elem; i++)
715252726Srpaulo		HMAC_Update(&ctx, addr[i], len[i]);
716252726Srpaulo
717252726Srpaulo	mdlen = 20;
718252726Srpaulo#if OPENSSL_VERSION_NUMBER < 0x00909000
719252726Srpaulo	HMAC_Final(&ctx, mac, &mdlen);
720252726Srpaulo	res = 1;
721252726Srpaulo#else /* openssl < 0.9.9 */
722252726Srpaulo	res = HMAC_Final(&ctx, mac, &mdlen);
723252726Srpaulo#endif /* openssl < 0.9.9 */
724252726Srpaulo	HMAC_CTX_cleanup(&ctx);
725252726Srpaulo
726252726Srpaulo	return res == 1 ? 0 : -1;
727252726Srpaulo}
728252726Srpaulo
729252726Srpaulo
730252726Srpauloint hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
731252726Srpaulo	       u8 *mac)
732252726Srpaulo{
733252726Srpaulo	return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
734252726Srpaulo}
735252726Srpaulo
736252726Srpaulo
737252726Srpaulo#ifdef CONFIG_SHA256
738252726Srpaulo
739252726Srpauloint hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
740252726Srpaulo		       const u8 *addr[], const size_t *len, u8 *mac)
741252726Srpaulo{
742252726Srpaulo	HMAC_CTX ctx;
743252726Srpaulo	size_t i;
744252726Srpaulo	unsigned int mdlen;
745252726Srpaulo	int res;
746252726Srpaulo
747252726Srpaulo	HMAC_CTX_init(&ctx);
748252726Srpaulo#if OPENSSL_VERSION_NUMBER < 0x00909000
749252726Srpaulo	HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL);
750252726Srpaulo#else /* openssl < 0.9.9 */
751252726Srpaulo	if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL) != 1)
752252726Srpaulo		return -1;
753252726Srpaulo#endif /* openssl < 0.9.9 */
754252726Srpaulo
755252726Srpaulo	for (i = 0; i < num_elem; i++)
756252726Srpaulo		HMAC_Update(&ctx, addr[i], len[i]);
757252726Srpaulo
758252726Srpaulo	mdlen = 32;
759252726Srpaulo#if OPENSSL_VERSION_NUMBER < 0x00909000
760252726Srpaulo	HMAC_Final(&ctx, mac, &mdlen);
761252726Srpaulo	res = 1;
762252726Srpaulo#else /* openssl < 0.9.9 */
763252726Srpaulo	res = HMAC_Final(&ctx, mac, &mdlen);
764252726Srpaulo#endif /* openssl < 0.9.9 */
765252726Srpaulo	HMAC_CTX_cleanup(&ctx);
766252726Srpaulo
767252726Srpaulo	return res == 1 ? 0 : -1;
768252726Srpaulo}
769252726Srpaulo
770252726Srpaulo
771252726Srpauloint hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
772252726Srpaulo		size_t data_len, u8 *mac)
773252726Srpaulo{
774252726Srpaulo	return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
775252726Srpaulo}
776252726Srpaulo
777252726Srpaulo#endif /* CONFIG_SHA256 */
778252726Srpaulo
779252726Srpaulo
780252726Srpauloint crypto_get_random(void *buf, size_t len)
781252726Srpaulo{
782252726Srpaulo	if (RAND_bytes(buf, len) != 1)
783252726Srpaulo		return -1;
784252726Srpaulo	return 0;
785252726Srpaulo}
786252726Srpaulo
787252726Srpaulo
788252726Srpaulo#ifdef CONFIG_OPENSSL_CMAC
789252726Srpauloint omac1_aes_128_vector(const u8 *key, size_t num_elem,
790252726Srpaulo			 const u8 *addr[], const size_t *len, u8 *mac)
791252726Srpaulo{
792252726Srpaulo	CMAC_CTX *ctx;
793252726Srpaulo	int ret = -1;
794252726Srpaulo	size_t outlen, i;
795252726Srpaulo
796252726Srpaulo	ctx = CMAC_CTX_new();
797252726Srpaulo	if (ctx == NULL)
798252726Srpaulo		return -1;
799252726Srpaulo
800252726Srpaulo	if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
801252726Srpaulo		goto fail;
802252726Srpaulo	for (i = 0; i < num_elem; i++) {
803252726Srpaulo		if (!CMAC_Update(ctx, addr[i], len[i]))
804252726Srpaulo			goto fail;
805252726Srpaulo	}
806252726Srpaulo	if (!CMAC_Final(ctx, mac, &outlen) || outlen != 16)
807252726Srpaulo		goto fail;
808252726Srpaulo
809252726Srpaulo	ret = 0;
810252726Srpaulofail:
811252726Srpaulo	CMAC_CTX_free(ctx);
812252726Srpaulo	return ret;
813252726Srpaulo}
814252726Srpaulo
815252726Srpaulo
816252726Srpauloint omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
817252726Srpaulo{
818252726Srpaulo	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
819252726Srpaulo}
820252726Srpaulo#endif /* CONFIG_OPENSSL_CMAC */
821