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