1189251Ssam/*
2189251Ssam * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
3189251Ssam * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
4189251Ssam *
5189251Ssam * This program is free software; you can redistribute it and/or modify
6189251Ssam * it under the terms of the GNU General Public License version 2 as
7189251Ssam * published by the Free Software Foundation.
8189251Ssam *
9189251Ssam * Alternatively, this software may be distributed under the terms of BSD
10189251Ssam * license.
11189251Ssam *
12189251Ssam * See README and COPYING for more details.
13189251Ssam */
14189251Ssam
15189251Ssam#include "includes.h"
16189251Ssam#include <tomcrypt.h>
17189251Ssam
18189251Ssam#include "common.h"
19189251Ssam#include "crypto.h"
20189251Ssam
21189251Ssam#ifndef mp_init_multi
22189251Ssam#define mp_init_multi                ltc_init_multi
23189251Ssam#define mp_clear_multi               ltc_deinit_multi
24189251Ssam#define mp_unsigned_bin_size(a)      ltc_mp.unsigned_size(a)
25189251Ssam#define mp_to_unsigned_bin(a, b)     ltc_mp.unsigned_write(a, b)
26189251Ssam#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
27189251Ssam#define mp_exptmod(a,b,c,d)          ltc_mp.exptmod(a,b,c,d)
28189251Ssam#endif
29189251Ssam
30189251Ssam
31214734Srpauloint md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
32189251Ssam{
33189251Ssam	hash_state md;
34189251Ssam	size_t i;
35189251Ssam
36189251Ssam	md4_init(&md);
37189251Ssam	for (i = 0; i < num_elem; i++)
38189251Ssam		md4_process(&md, addr[i], len[i]);
39189251Ssam	md4_done(&md, mac);
40214734Srpaulo	return 0;
41189251Ssam}
42189251Ssam
43189251Ssam
44189251Ssamvoid des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
45189251Ssam{
46189251Ssam	u8 pkey[8], next, tmp;
47189251Ssam	int i;
48189251Ssam	symmetric_key skey;
49189251Ssam
50189251Ssam	/* Add parity bits to the key */
51189251Ssam	next = 0;
52189251Ssam	for (i = 0; i < 7; i++) {
53189251Ssam		tmp = key[i];
54189251Ssam		pkey[i] = (tmp >> i) | next | 1;
55189251Ssam		next = tmp << (7 - i);
56189251Ssam	}
57189251Ssam	pkey[i] = next | 1;
58189251Ssam
59189251Ssam	des_setup(pkey, 8, 0, &skey);
60189251Ssam	des_ecb_encrypt(clear, cypher, &skey);
61189251Ssam	des_done(&skey);
62189251Ssam}
63189251Ssam
64189251Ssam
65214734Srpauloint md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
66189251Ssam{
67189251Ssam	hash_state md;
68189251Ssam	size_t i;
69189251Ssam
70189251Ssam	md5_init(&md);
71189251Ssam	for (i = 0; i < num_elem; i++)
72189251Ssam		md5_process(&md, addr[i], len[i]);
73189251Ssam	md5_done(&md, mac);
74214734Srpaulo	return 0;
75189251Ssam}
76189251Ssam
77189251Ssam
78214734Srpauloint sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
79189251Ssam{
80189251Ssam	hash_state md;
81189251Ssam	size_t i;
82189251Ssam
83189251Ssam	sha1_init(&md);
84189251Ssam	for (i = 0; i < num_elem; i++)
85189251Ssam		sha1_process(&md, addr[i], len[i]);
86189251Ssam	sha1_done(&md, mac);
87214734Srpaulo	return 0;
88189251Ssam}
89189251Ssam
90189251Ssam
91189251Ssamvoid * aes_encrypt_init(const u8 *key, size_t len)
92189251Ssam{
93189251Ssam	symmetric_key *skey;
94189251Ssam	skey = os_malloc(sizeof(*skey));
95189251Ssam	if (skey == NULL)
96189251Ssam		return NULL;
97189251Ssam	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
98189251Ssam		os_free(skey);
99189251Ssam		return NULL;
100189251Ssam	}
101189251Ssam	return skey;
102189251Ssam}
103189251Ssam
104189251Ssam
105189251Ssamvoid aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
106189251Ssam{
107189251Ssam	symmetric_key *skey = ctx;
108189251Ssam	aes_ecb_encrypt(plain, crypt, skey);
109189251Ssam}
110189251Ssam
111189251Ssam
112189251Ssamvoid aes_encrypt_deinit(void *ctx)
113189251Ssam{
114189251Ssam	symmetric_key *skey = ctx;
115189251Ssam	aes_done(skey);
116189251Ssam	os_free(skey);
117189251Ssam}
118189251Ssam
119189251Ssam
120189251Ssamvoid * aes_decrypt_init(const u8 *key, size_t len)
121189251Ssam{
122189251Ssam	symmetric_key *skey;
123189251Ssam	skey = os_malloc(sizeof(*skey));
124189251Ssam	if (skey == NULL)
125189251Ssam		return NULL;
126189251Ssam	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
127189251Ssam		os_free(skey);
128189251Ssam		return NULL;
129189251Ssam	}
130189251Ssam	return skey;
131189251Ssam}
132189251Ssam
133189251Ssam
134189251Ssamvoid aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
135189251Ssam{
136189251Ssam	symmetric_key *skey = ctx;
137189251Ssam	aes_ecb_encrypt(plain, (u8 *) crypt, skey);
138189251Ssam}
139189251Ssam
140189251Ssam
141189251Ssamvoid aes_decrypt_deinit(void *ctx)
142189251Ssam{
143189251Ssam	symmetric_key *skey = ctx;
144189251Ssam	aes_done(skey);
145189251Ssam	os_free(skey);
146189251Ssam}
147189251Ssam
148189251Ssam
149189251Ssamstruct crypto_hash {
150189251Ssam	enum crypto_hash_alg alg;
151189251Ssam	int error;
152189251Ssam	union {
153189251Ssam		hash_state md;
154189251Ssam		hmac_state hmac;
155189251Ssam	} u;
156189251Ssam};
157189251Ssam
158189251Ssam
159189251Ssamstruct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
160189251Ssam				      size_t key_len)
161189251Ssam{
162189251Ssam	struct crypto_hash *ctx;
163189251Ssam
164189251Ssam	ctx = os_zalloc(sizeof(*ctx));
165189251Ssam	if (ctx == NULL)
166189251Ssam		return NULL;
167189251Ssam
168189251Ssam	ctx->alg = alg;
169189251Ssam
170189251Ssam	switch (alg) {
171189251Ssam	case CRYPTO_HASH_ALG_MD5:
172189251Ssam		if (md5_init(&ctx->u.md) != CRYPT_OK)
173189251Ssam			goto fail;
174189251Ssam		break;
175189251Ssam	case CRYPTO_HASH_ALG_SHA1:
176189251Ssam		if (sha1_init(&ctx->u.md) != CRYPT_OK)
177189251Ssam			goto fail;
178189251Ssam		break;
179189251Ssam	case CRYPTO_HASH_ALG_HMAC_MD5:
180189251Ssam		if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) !=
181189251Ssam		    CRYPT_OK)
182189251Ssam			goto fail;
183189251Ssam		break;
184189251Ssam	case CRYPTO_HASH_ALG_HMAC_SHA1:
185189251Ssam		if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) !=
186189251Ssam		    CRYPT_OK)
187189251Ssam			goto fail;
188189251Ssam		break;
189189251Ssam	default:
190189251Ssam		goto fail;
191189251Ssam	}
192189251Ssam
193189251Ssam	return ctx;
194189251Ssam
195189251Ssamfail:
196189251Ssam	os_free(ctx);
197189251Ssam	return NULL;
198189251Ssam}
199189251Ssam
200189251Ssamvoid crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
201189251Ssam{
202189251Ssam	if (ctx == NULL || ctx->error)
203189251Ssam		return;
204189251Ssam
205189251Ssam	switch (ctx->alg) {
206189251Ssam	case CRYPTO_HASH_ALG_MD5:
207189251Ssam		ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK;
208189251Ssam		break;
209189251Ssam	case CRYPTO_HASH_ALG_SHA1:
210189251Ssam		ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK;
211189251Ssam		break;
212189251Ssam	case CRYPTO_HASH_ALG_HMAC_MD5:
213189251Ssam	case CRYPTO_HASH_ALG_HMAC_SHA1:
214189251Ssam		ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK;
215189251Ssam		break;
216189251Ssam	}
217189251Ssam}
218189251Ssam
219189251Ssam
220189251Ssamint crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
221189251Ssam{
222189251Ssam	int ret = 0;
223189251Ssam	unsigned long clen;
224189251Ssam
225189251Ssam	if (ctx == NULL)
226189251Ssam		return -2;
227189251Ssam
228189251Ssam	if (mac == NULL || len == NULL) {
229189251Ssam		os_free(ctx);
230189251Ssam		return 0;
231189251Ssam	}
232189251Ssam
233189251Ssam	if (ctx->error) {
234189251Ssam		os_free(ctx);
235189251Ssam		return -2;
236189251Ssam	}
237189251Ssam
238189251Ssam	switch (ctx->alg) {
239189251Ssam	case CRYPTO_HASH_ALG_MD5:
240189251Ssam		if (*len < 16) {
241189251Ssam			*len = 16;
242189251Ssam			os_free(ctx);
243189251Ssam			return -1;
244189251Ssam		}
245189251Ssam		*len = 16;
246189251Ssam		if (md5_done(&ctx->u.md, mac) != CRYPT_OK)
247189251Ssam			ret = -2;
248189251Ssam		break;
249189251Ssam	case CRYPTO_HASH_ALG_SHA1:
250189251Ssam		if (*len < 20) {
251189251Ssam			*len = 20;
252189251Ssam			os_free(ctx);
253189251Ssam			return -1;
254189251Ssam		}
255189251Ssam		*len = 20;
256189251Ssam		if (sha1_done(&ctx->u.md, mac) != CRYPT_OK)
257189251Ssam			ret = -2;
258189251Ssam		break;
259189251Ssam	case CRYPTO_HASH_ALG_HMAC_SHA1:
260189251Ssam		if (*len < 20) {
261189251Ssam			*len = 20;
262189251Ssam			os_free(ctx);
263189251Ssam			return -1;
264189251Ssam		}
265189251Ssam		/* continue */
266189251Ssam	case CRYPTO_HASH_ALG_HMAC_MD5:
267189251Ssam		if (*len < 16) {
268189251Ssam			*len = 16;
269189251Ssam			os_free(ctx);
270189251Ssam			return -1;
271189251Ssam		}
272189251Ssam		clen = *len;
273189251Ssam		if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) {
274189251Ssam			os_free(ctx);
275189251Ssam			return -1;
276189251Ssam		}
277189251Ssam		*len = clen;
278189251Ssam		break;
279189251Ssam	default:
280189251Ssam		ret = -2;
281189251Ssam		break;
282189251Ssam	}
283189251Ssam
284189251Ssam	os_free(ctx);
285189251Ssam
286189251Ssam	return ret;
287189251Ssam}
288189251Ssam
289189251Ssam
290189251Ssamstruct crypto_cipher {
291189251Ssam	int rc4;
292189251Ssam	union {
293189251Ssam		symmetric_CBC cbc;
294189251Ssam		struct {
295189251Ssam			size_t used_bytes;
296189251Ssam			u8 key[16];
297189251Ssam			size_t keylen;
298189251Ssam		} rc4;
299189251Ssam	} u;
300189251Ssam};
301189251Ssam
302189251Ssam
303189251Ssamstruct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
304189251Ssam					  const u8 *iv, const u8 *key,
305189251Ssam					  size_t key_len)
306189251Ssam{
307189251Ssam	struct crypto_cipher *ctx;
308189251Ssam	int idx, res, rc4 = 0;
309189251Ssam
310189251Ssam	switch (alg) {
311189251Ssam	case CRYPTO_CIPHER_ALG_AES:
312189251Ssam		idx = find_cipher("aes");
313189251Ssam		break;
314189251Ssam	case CRYPTO_CIPHER_ALG_3DES:
315189251Ssam		idx = find_cipher("3des");
316189251Ssam		break;
317189251Ssam	case CRYPTO_CIPHER_ALG_DES:
318189251Ssam		idx = find_cipher("des");
319189251Ssam		break;
320189251Ssam	case CRYPTO_CIPHER_ALG_RC2:
321189251Ssam		idx = find_cipher("rc2");
322189251Ssam		break;
323189251Ssam	case CRYPTO_CIPHER_ALG_RC4:
324189251Ssam		idx = -1;
325189251Ssam		rc4 = 1;
326189251Ssam		break;
327189251Ssam	default:
328189251Ssam		return NULL;
329189251Ssam	}
330189251Ssam
331189251Ssam	ctx = os_zalloc(sizeof(*ctx));
332189251Ssam	if (ctx == NULL)
333189251Ssam		return NULL;
334189251Ssam
335189251Ssam	if (rc4) {
336189251Ssam		ctx->rc4 = 1;
337189251Ssam		if (key_len > sizeof(ctx->u.rc4.key)) {
338189251Ssam			os_free(ctx);
339189251Ssam			return NULL;
340189251Ssam		}
341189251Ssam		ctx->u.rc4.keylen = key_len;
342189251Ssam		os_memcpy(ctx->u.rc4.key, key, key_len);
343189251Ssam	} else {
344189251Ssam		res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc);
345189251Ssam		if (res != CRYPT_OK) {
346189251Ssam			wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start "
347189251Ssam				   "failed: %s", error_to_string(res));
348189251Ssam			os_free(ctx);
349189251Ssam			return NULL;
350189251Ssam		}
351189251Ssam	}
352189251Ssam
353189251Ssam	return ctx;
354189251Ssam}
355189251Ssam
356189251Ssamint crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
357189251Ssam			  u8 *crypt, size_t len)
358189251Ssam{
359189251Ssam	int res;
360189251Ssam
361189251Ssam	if (ctx->rc4) {
362189251Ssam		if (plain != crypt)
363189251Ssam			os_memcpy(crypt, plain, len);
364189251Ssam		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
365189251Ssam			 ctx->u.rc4.used_bytes, crypt, len);
366189251Ssam		ctx->u.rc4.used_bytes += len;
367189251Ssam		return 0;
368189251Ssam	}
369189251Ssam
370189251Ssam	res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc);
371189251Ssam	if (res != CRYPT_OK) {
372189251Ssam		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption "
373189251Ssam			   "failed: %s", error_to_string(res));
374189251Ssam		return -1;
375189251Ssam	}
376189251Ssam	return 0;
377189251Ssam}
378189251Ssam
379189251Ssam
380189251Ssamint crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
381189251Ssam			  u8 *plain, size_t len)
382189251Ssam{
383189251Ssam	int res;
384189251Ssam
385189251Ssam	if (ctx->rc4) {
386189251Ssam		if (plain != crypt)
387189251Ssam			os_memcpy(plain, crypt, len);
388189251Ssam		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
389189251Ssam			 ctx->u.rc4.used_bytes, plain, len);
390189251Ssam		ctx->u.rc4.used_bytes += len;
391189251Ssam		return 0;
392189251Ssam	}
393189251Ssam
394189251Ssam	res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc);
395189251Ssam	if (res != CRYPT_OK) {
396189251Ssam		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption "
397189251Ssam			   "failed: %s", error_to_string(res));
398189251Ssam		return -1;
399189251Ssam	}
400189251Ssam
401189251Ssam	return 0;
402189251Ssam}
403189251Ssam
404189251Ssam
405189251Ssamvoid crypto_cipher_deinit(struct crypto_cipher *ctx)
406189251Ssam{
407189251Ssam	if (!ctx->rc4)
408189251Ssam		cbc_done(&ctx->u.cbc);
409189251Ssam	os_free(ctx);
410189251Ssam}
411189251Ssam
412189251Ssam
413189251Ssamstruct crypto_public_key {
414189251Ssam	rsa_key rsa;
415189251Ssam};
416189251Ssam
417189251Ssamstruct crypto_private_key {
418189251Ssam	rsa_key rsa;
419189251Ssam};
420189251Ssam
421189251Ssam
422189251Ssamstruct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
423189251Ssam{
424189251Ssam	int res;
425189251Ssam	struct crypto_public_key *pk;
426189251Ssam
427189251Ssam	pk = os_zalloc(sizeof(*pk));
428189251Ssam	if (pk == NULL)
429189251Ssam		return NULL;
430189251Ssam
431189251Ssam	res = rsa_import(key, len, &pk->rsa);
432189251Ssam	if (res != CRYPT_OK) {
433189251Ssam		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
434189251Ssam			   "public key (res=%d '%s')",
435189251Ssam			   res, error_to_string(res));
436189251Ssam		os_free(pk);
437189251Ssam		return NULL;
438189251Ssam	}
439189251Ssam
440189251Ssam	if (pk->rsa.type != PK_PUBLIC) {
441189251Ssam		wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of "
442189251Ssam			   "correct type");
443189251Ssam		rsa_free(&pk->rsa);
444189251Ssam		os_free(pk);
445189251Ssam		return NULL;
446189251Ssam	}
447189251Ssam
448189251Ssam	return pk;
449189251Ssam}
450189251Ssam
451189251Ssam
452189251Ssamstruct crypto_private_key * crypto_private_key_import(const u8 *key,
453214734Srpaulo						      size_t len,
454214734Srpaulo						      const char *passwd)
455189251Ssam{
456189251Ssam	int res;
457189251Ssam	struct crypto_private_key *pk;
458189251Ssam
459189251Ssam	pk = os_zalloc(sizeof(*pk));
460189251Ssam	if (pk == NULL)
461189251Ssam		return NULL;
462189251Ssam
463189251Ssam	res = rsa_import(key, len, &pk->rsa);
464189251Ssam	if (res != CRYPT_OK) {
465189251Ssam		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
466189251Ssam			   "private key (res=%d '%s')",
467189251Ssam			   res, error_to_string(res));
468189251Ssam		os_free(pk);
469189251Ssam		return NULL;
470189251Ssam	}
471189251Ssam
472189251Ssam	if (pk->rsa.type != PK_PRIVATE) {
473189251Ssam		wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of "
474189251Ssam			   "correct type");
475189251Ssam		rsa_free(&pk->rsa);
476189251Ssam		os_free(pk);
477189251Ssam		return NULL;
478189251Ssam	}
479189251Ssam
480189251Ssam	return pk;
481189251Ssam}
482189251Ssam
483189251Ssam
484189251Ssamstruct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
485189251Ssam						       size_t len)
486189251Ssam{
487189251Ssam	/* No X.509 support in LibTomCrypt */
488189251Ssam	return NULL;
489189251Ssam}
490189251Ssam
491189251Ssam
492189251Ssamstatic int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
493189251Ssam					   const u8 *in, size_t inlen,
494189251Ssam					   u8 *out, size_t *outlen)
495189251Ssam{
496189251Ssam	size_t ps_len;
497189251Ssam	u8 *pos;
498189251Ssam
499189251Ssam	/*
500189251Ssam	 * PKCS #1 v1.5, 8.1:
501189251Ssam	 *
502189251Ssam	 * EB = 00 || BT || PS || 00 || D
503189251Ssam	 * BT = 00 or 01 for private-key operation; 02 for public-key operation
504189251Ssam	 * PS = k-3-||D||; at least eight octets
505189251Ssam	 * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
506189251Ssam	 * k = length of modulus in octets (modlen)
507189251Ssam	 */
508189251Ssam
509189251Ssam	if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
510189251Ssam		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
511189251Ssam			   "lengths (modlen=%lu outlen=%lu inlen=%lu)",
512189251Ssam			   __func__, (unsigned long) modlen,
513189251Ssam			   (unsigned long) *outlen,
514189251Ssam			   (unsigned long) inlen);
515189251Ssam		return -1;
516189251Ssam	}
517189251Ssam
518189251Ssam	pos = out;
519189251Ssam	*pos++ = 0x00;
520189251Ssam	*pos++ = block_type; /* BT */
521189251Ssam	ps_len = modlen - inlen - 3;
522189251Ssam	switch (block_type) {
523189251Ssam	case 0:
524189251Ssam		os_memset(pos, 0x00, ps_len);
525189251Ssam		pos += ps_len;
526189251Ssam		break;
527189251Ssam	case 1:
528189251Ssam		os_memset(pos, 0xff, ps_len);
529189251Ssam		pos += ps_len;
530189251Ssam		break;
531189251Ssam	case 2:
532189251Ssam		if (os_get_random(pos, ps_len) < 0) {
533189251Ssam			wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
534189251Ssam				   "random data for PS", __func__);
535189251Ssam			return -1;
536189251Ssam		}
537189251Ssam		while (ps_len--) {
538189251Ssam			if (*pos == 0x00)
539189251Ssam				*pos = 0x01;
540189251Ssam			pos++;
541189251Ssam		}
542189251Ssam		break;
543189251Ssam	default:
544189251Ssam		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
545189251Ssam			   "%d", __func__, block_type);
546189251Ssam		return -1;
547189251Ssam	}
548189251Ssam	*pos++ = 0x00;
549189251Ssam	os_memcpy(pos, in, inlen); /* D */
550189251Ssam
551189251Ssam	return 0;
552189251Ssam}
553189251Ssam
554189251Ssam
555189251Ssamstatic int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type,
556189251Ssam				    const u8 *in, size_t inlen,
557189251Ssam				    u8 *out, size_t *outlen)
558189251Ssam{
559189251Ssam	unsigned long len, modlen;
560189251Ssam	int res;
561189251Ssam
562189251Ssam	modlen = mp_unsigned_bin_size(key->N);
563189251Ssam
564189251Ssam	if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
565189251Ssam					    out, outlen) < 0)
566189251Ssam		return -1;
567189251Ssam
568189251Ssam	len = *outlen;
569189251Ssam	res = rsa_exptmod(out, modlen, out, &len, key_type, key);
570189251Ssam	if (res != CRYPT_OK) {
571189251Ssam		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
572189251Ssam			   error_to_string(res));
573189251Ssam		return -1;
574189251Ssam	}
575189251Ssam	*outlen = len;
576189251Ssam
577189251Ssam	return 0;
578189251Ssam}
579189251Ssam
580189251Ssam
581189251Ssamint crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
582189251Ssam					const u8 *in, size_t inlen,
583189251Ssam					u8 *out, size_t *outlen)
584189251Ssam{
585189251Ssam	return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen,
586189251Ssam					out, outlen);
587189251Ssam}
588189251Ssam
589189251Ssam
590189251Ssamint crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
591189251Ssam				  const u8 *in, size_t inlen,
592189251Ssam				  u8 *out, size_t *outlen)
593189251Ssam{
594189251Ssam	return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen,
595189251Ssam					out, outlen);
596189251Ssam}
597189251Ssam
598189251Ssam
599189251Ssamvoid crypto_public_key_free(struct crypto_public_key *key)
600189251Ssam{
601189251Ssam	if (key) {
602189251Ssam		rsa_free(&key->rsa);
603189251Ssam		os_free(key);
604189251Ssam	}
605189251Ssam}
606189251Ssam
607189251Ssam
608189251Ssamvoid crypto_private_key_free(struct crypto_private_key *key)
609189251Ssam{
610189251Ssam	if (key) {
611189251Ssam		rsa_free(&key->rsa);
612189251Ssam		os_free(key);
613189251Ssam	}
614189251Ssam}
615189251Ssam
616189251Ssam
617189251Ssamint crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
618189251Ssam				    const u8 *crypt, size_t crypt_len,
619189251Ssam				    u8 *plain, size_t *plain_len)
620189251Ssam{
621189251Ssam	int res;
622189251Ssam	unsigned long len;
623189251Ssam	u8 *pos;
624189251Ssam
625189251Ssam	len = *plain_len;
626189251Ssam	res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC,
627189251Ssam			  &key->rsa);
628189251Ssam	if (res != CRYPT_OK) {
629189251Ssam		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
630189251Ssam			   error_to_string(res));
631189251Ssam		return -1;
632189251Ssam	}
633189251Ssam
634189251Ssam	/*
635189251Ssam	 * PKCS #1 v1.5, 8.1:
636189251Ssam	 *
637189251Ssam	 * EB = 00 || BT || PS || 00 || D
638189251Ssam	 * BT = 01
639189251Ssam	 * PS = k-3-||D|| times FF
640189251Ssam	 * k = length of modulus in octets
641189251Ssam	 */
642189251Ssam
643189251Ssam	if (len < 3 + 8 + 16 /* min hash len */ ||
644189251Ssam	    plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
645189251Ssam		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
646189251Ssam			   "structure");
647189251Ssam		return -1;
648189251Ssam	}
649189251Ssam
650189251Ssam	pos = plain + 3;
651189251Ssam	while (pos < plain + len && *pos == 0xff)
652189251Ssam		pos++;
653189251Ssam	if (pos - plain - 2 < 8) {
654189251Ssam		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
655189251Ssam		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
656189251Ssam			   "padding");
657189251Ssam		return -1;
658189251Ssam	}
659189251Ssam
660189251Ssam	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
661189251Ssam		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
662189251Ssam			   "structure (2)");
663189251Ssam		return -1;
664189251Ssam	}
665189251Ssam	pos++;
666189251Ssam	len -= pos - plain;
667189251Ssam
668189251Ssam	/* Strip PKCS #1 header */
669189251Ssam	os_memmove(plain, pos, len);
670189251Ssam	*plain_len = len;
671189251Ssam
672189251Ssam	return 0;
673189251Ssam}
674189251Ssam
675189251Ssam
676189251Ssamint crypto_global_init(void)
677189251Ssam{
678189251Ssam	ltc_mp = tfm_desc;
679189251Ssam	/* TODO: only register algorithms that are really needed */
680189251Ssam	if (register_hash(&md4_desc) < 0 ||
681189251Ssam	    register_hash(&md5_desc) < 0 ||
682189251Ssam	    register_hash(&sha1_desc) < 0 ||
683189251Ssam	    register_cipher(&aes_desc) < 0 ||
684189251Ssam	    register_cipher(&des_desc) < 0 ||
685189251Ssam	    register_cipher(&des3_desc) < 0) {
686189251Ssam		wpa_printf(MSG_ERROR, "TLSv1: Failed to register "
687189251Ssam			   "hash/cipher functions");
688189251Ssam		return -1;
689189251Ssam	}
690189251Ssam
691189251Ssam	return 0;
692189251Ssam}
693189251Ssam
694189251Ssam
695189251Ssamvoid crypto_global_deinit(void)
696189251Ssam{
697189251Ssam}
698189251Ssam
699189251Ssam
700214734Srpaulo#ifdef CONFIG_MODEXP
701189251Ssam
702189251Ssamint crypto_mod_exp(const u8 *base, size_t base_len,
703189251Ssam		   const u8 *power, size_t power_len,
704189251Ssam		   const u8 *modulus, size_t modulus_len,
705189251Ssam		   u8 *result, size_t *result_len)
706189251Ssam{
707189251Ssam	void *b, *p, *m, *r;
708189251Ssam
709189251Ssam	if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK)
710189251Ssam		return -1;
711189251Ssam
712189251Ssam	if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK ||
713189251Ssam	    mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK ||
714189251Ssam	    mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK)
715189251Ssam		goto fail;
716189251Ssam
717189251Ssam	if (mp_exptmod(b, p, m, r) != CRYPT_OK)
718189251Ssam		goto fail;
719189251Ssam
720189251Ssam	*result_len = mp_unsigned_bin_size(r);
721189251Ssam	if (mp_to_unsigned_bin(r, result) != CRYPT_OK)
722189251Ssam		goto fail;
723189251Ssam
724189251Ssam	mp_clear_multi(b, p, m, r, NULL);
725189251Ssam	return 0;
726189251Ssam
727189251Ssamfail:
728189251Ssam	mp_clear_multi(b, p, m, r, NULL);
729189251Ssam	return -1;
730189251Ssam}
731189251Ssam
732214734Srpaulo#endif /* CONFIG_MODEXP */
733