xref: /freebsd/contrib/wpa/src/crypto/crypto_libtomcrypt.c (revision f05cddf940dbfc5b657f5e9beb9de2c31e509e5b)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
339beb93cSSam Leffler  * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5*f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6*f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler #include <tomcrypt.h>
1139beb93cSSam Leffler 
1239beb93cSSam Leffler #include "common.h"
1339beb93cSSam Leffler #include "crypto.h"
1439beb93cSSam Leffler 
1539beb93cSSam Leffler #ifndef mp_init_multi
1639beb93cSSam Leffler #define mp_init_multi                ltc_init_multi
1739beb93cSSam Leffler #define mp_clear_multi               ltc_deinit_multi
1839beb93cSSam Leffler #define mp_unsigned_bin_size(a)      ltc_mp.unsigned_size(a)
1939beb93cSSam Leffler #define mp_to_unsigned_bin(a, b)     ltc_mp.unsigned_write(a, b)
2039beb93cSSam Leffler #define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
2139beb93cSSam Leffler #define mp_exptmod(a,b,c,d)          ltc_mp.exptmod(a,b,c,d)
2239beb93cSSam Leffler #endif
2339beb93cSSam Leffler 
2439beb93cSSam Leffler 
25e28a4053SRui Paulo int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
2639beb93cSSam Leffler {
2739beb93cSSam Leffler 	hash_state md;
2839beb93cSSam Leffler 	size_t i;
2939beb93cSSam Leffler 
3039beb93cSSam Leffler 	md4_init(&md);
3139beb93cSSam Leffler 	for (i = 0; i < num_elem; i++)
3239beb93cSSam Leffler 		md4_process(&md, addr[i], len[i]);
3339beb93cSSam Leffler 	md4_done(&md, mac);
34e28a4053SRui Paulo 	return 0;
3539beb93cSSam Leffler }
3639beb93cSSam Leffler 
3739beb93cSSam Leffler 
3839beb93cSSam Leffler void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
3939beb93cSSam Leffler {
4039beb93cSSam Leffler 	u8 pkey[8], next, tmp;
4139beb93cSSam Leffler 	int i;
4239beb93cSSam Leffler 	symmetric_key skey;
4339beb93cSSam Leffler 
4439beb93cSSam Leffler 	/* Add parity bits to the key */
4539beb93cSSam Leffler 	next = 0;
4639beb93cSSam Leffler 	for (i = 0; i < 7; i++) {
4739beb93cSSam Leffler 		tmp = key[i];
4839beb93cSSam Leffler 		pkey[i] = (tmp >> i) | next | 1;
4939beb93cSSam Leffler 		next = tmp << (7 - i);
5039beb93cSSam Leffler 	}
5139beb93cSSam Leffler 	pkey[i] = next | 1;
5239beb93cSSam Leffler 
5339beb93cSSam Leffler 	des_setup(pkey, 8, 0, &skey);
5439beb93cSSam Leffler 	des_ecb_encrypt(clear, cypher, &skey);
5539beb93cSSam Leffler 	des_done(&skey);
5639beb93cSSam Leffler }
5739beb93cSSam Leffler 
5839beb93cSSam Leffler 
59e28a4053SRui Paulo int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
6039beb93cSSam Leffler {
6139beb93cSSam Leffler 	hash_state md;
6239beb93cSSam Leffler 	size_t i;
6339beb93cSSam Leffler 
6439beb93cSSam Leffler 	md5_init(&md);
6539beb93cSSam Leffler 	for (i = 0; i < num_elem; i++)
6639beb93cSSam Leffler 		md5_process(&md, addr[i], len[i]);
6739beb93cSSam Leffler 	md5_done(&md, mac);
68e28a4053SRui Paulo 	return 0;
6939beb93cSSam Leffler }
7039beb93cSSam Leffler 
7139beb93cSSam Leffler 
72e28a4053SRui Paulo int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
7339beb93cSSam Leffler {
7439beb93cSSam Leffler 	hash_state md;
7539beb93cSSam Leffler 	size_t i;
7639beb93cSSam Leffler 
7739beb93cSSam Leffler 	sha1_init(&md);
7839beb93cSSam Leffler 	for (i = 0; i < num_elem; i++)
7939beb93cSSam Leffler 		sha1_process(&md, addr[i], len[i]);
8039beb93cSSam Leffler 	sha1_done(&md, mac);
81e28a4053SRui Paulo 	return 0;
8239beb93cSSam Leffler }
8339beb93cSSam Leffler 
8439beb93cSSam Leffler 
8539beb93cSSam Leffler void * aes_encrypt_init(const u8 *key, size_t len)
8639beb93cSSam Leffler {
8739beb93cSSam Leffler 	symmetric_key *skey;
8839beb93cSSam Leffler 	skey = os_malloc(sizeof(*skey));
8939beb93cSSam Leffler 	if (skey == NULL)
9039beb93cSSam Leffler 		return NULL;
9139beb93cSSam Leffler 	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
9239beb93cSSam Leffler 		os_free(skey);
9339beb93cSSam Leffler 		return NULL;
9439beb93cSSam Leffler 	}
9539beb93cSSam Leffler 	return skey;
9639beb93cSSam Leffler }
9739beb93cSSam Leffler 
9839beb93cSSam Leffler 
9939beb93cSSam Leffler void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
10039beb93cSSam Leffler {
10139beb93cSSam Leffler 	symmetric_key *skey = ctx;
10239beb93cSSam Leffler 	aes_ecb_encrypt(plain, crypt, skey);
10339beb93cSSam Leffler }
10439beb93cSSam Leffler 
10539beb93cSSam Leffler 
10639beb93cSSam Leffler void aes_encrypt_deinit(void *ctx)
10739beb93cSSam Leffler {
10839beb93cSSam Leffler 	symmetric_key *skey = ctx;
10939beb93cSSam Leffler 	aes_done(skey);
11039beb93cSSam Leffler 	os_free(skey);
11139beb93cSSam Leffler }
11239beb93cSSam Leffler 
11339beb93cSSam Leffler 
11439beb93cSSam Leffler void * aes_decrypt_init(const u8 *key, size_t len)
11539beb93cSSam Leffler {
11639beb93cSSam Leffler 	symmetric_key *skey;
11739beb93cSSam Leffler 	skey = os_malloc(sizeof(*skey));
11839beb93cSSam Leffler 	if (skey == NULL)
11939beb93cSSam Leffler 		return NULL;
12039beb93cSSam Leffler 	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
12139beb93cSSam Leffler 		os_free(skey);
12239beb93cSSam Leffler 		return NULL;
12339beb93cSSam Leffler 	}
12439beb93cSSam Leffler 	return skey;
12539beb93cSSam Leffler }
12639beb93cSSam Leffler 
12739beb93cSSam Leffler 
12839beb93cSSam Leffler void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
12939beb93cSSam Leffler {
13039beb93cSSam Leffler 	symmetric_key *skey = ctx;
13139beb93cSSam Leffler 	aes_ecb_encrypt(plain, (u8 *) crypt, skey);
13239beb93cSSam Leffler }
13339beb93cSSam Leffler 
13439beb93cSSam Leffler 
13539beb93cSSam Leffler void aes_decrypt_deinit(void *ctx)
13639beb93cSSam Leffler {
13739beb93cSSam Leffler 	symmetric_key *skey = ctx;
13839beb93cSSam Leffler 	aes_done(skey);
13939beb93cSSam Leffler 	os_free(skey);
14039beb93cSSam Leffler }
14139beb93cSSam Leffler 
14239beb93cSSam Leffler 
14339beb93cSSam Leffler struct crypto_hash {
14439beb93cSSam Leffler 	enum crypto_hash_alg alg;
14539beb93cSSam Leffler 	int error;
14639beb93cSSam Leffler 	union {
14739beb93cSSam Leffler 		hash_state md;
14839beb93cSSam Leffler 		hmac_state hmac;
14939beb93cSSam Leffler 	} u;
15039beb93cSSam Leffler };
15139beb93cSSam Leffler 
15239beb93cSSam Leffler 
15339beb93cSSam Leffler struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
15439beb93cSSam Leffler 				      size_t key_len)
15539beb93cSSam Leffler {
15639beb93cSSam Leffler 	struct crypto_hash *ctx;
15739beb93cSSam Leffler 
15839beb93cSSam Leffler 	ctx = os_zalloc(sizeof(*ctx));
15939beb93cSSam Leffler 	if (ctx == NULL)
16039beb93cSSam Leffler 		return NULL;
16139beb93cSSam Leffler 
16239beb93cSSam Leffler 	ctx->alg = alg;
16339beb93cSSam Leffler 
16439beb93cSSam Leffler 	switch (alg) {
16539beb93cSSam Leffler 	case CRYPTO_HASH_ALG_MD5:
16639beb93cSSam Leffler 		if (md5_init(&ctx->u.md) != CRYPT_OK)
16739beb93cSSam Leffler 			goto fail;
16839beb93cSSam Leffler 		break;
16939beb93cSSam Leffler 	case CRYPTO_HASH_ALG_SHA1:
17039beb93cSSam Leffler 		if (sha1_init(&ctx->u.md) != CRYPT_OK)
17139beb93cSSam Leffler 			goto fail;
17239beb93cSSam Leffler 		break;
17339beb93cSSam Leffler 	case CRYPTO_HASH_ALG_HMAC_MD5:
17439beb93cSSam Leffler 		if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) !=
17539beb93cSSam Leffler 		    CRYPT_OK)
17639beb93cSSam Leffler 			goto fail;
17739beb93cSSam Leffler 		break;
17839beb93cSSam Leffler 	case CRYPTO_HASH_ALG_HMAC_SHA1:
17939beb93cSSam Leffler 		if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) !=
18039beb93cSSam Leffler 		    CRYPT_OK)
18139beb93cSSam Leffler 			goto fail;
18239beb93cSSam Leffler 		break;
18339beb93cSSam Leffler 	default:
18439beb93cSSam Leffler 		goto fail;
18539beb93cSSam Leffler 	}
18639beb93cSSam Leffler 
18739beb93cSSam Leffler 	return ctx;
18839beb93cSSam Leffler 
18939beb93cSSam Leffler fail:
19039beb93cSSam Leffler 	os_free(ctx);
19139beb93cSSam Leffler 	return NULL;
19239beb93cSSam Leffler }
19339beb93cSSam Leffler 
19439beb93cSSam Leffler void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
19539beb93cSSam Leffler {
19639beb93cSSam Leffler 	if (ctx == NULL || ctx->error)
19739beb93cSSam Leffler 		return;
19839beb93cSSam Leffler 
19939beb93cSSam Leffler 	switch (ctx->alg) {
20039beb93cSSam Leffler 	case CRYPTO_HASH_ALG_MD5:
20139beb93cSSam Leffler 		ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK;
20239beb93cSSam Leffler 		break;
20339beb93cSSam Leffler 	case CRYPTO_HASH_ALG_SHA1:
20439beb93cSSam Leffler 		ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK;
20539beb93cSSam Leffler 		break;
20639beb93cSSam Leffler 	case CRYPTO_HASH_ALG_HMAC_MD5:
20739beb93cSSam Leffler 	case CRYPTO_HASH_ALG_HMAC_SHA1:
20839beb93cSSam Leffler 		ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK;
20939beb93cSSam Leffler 		break;
21039beb93cSSam Leffler 	}
21139beb93cSSam Leffler }
21239beb93cSSam Leffler 
21339beb93cSSam Leffler 
21439beb93cSSam Leffler int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
21539beb93cSSam Leffler {
21639beb93cSSam Leffler 	int ret = 0;
21739beb93cSSam Leffler 	unsigned long clen;
21839beb93cSSam Leffler 
21939beb93cSSam Leffler 	if (ctx == NULL)
22039beb93cSSam Leffler 		return -2;
22139beb93cSSam Leffler 
22239beb93cSSam Leffler 	if (mac == NULL || len == NULL) {
22339beb93cSSam Leffler 		os_free(ctx);
22439beb93cSSam Leffler 		return 0;
22539beb93cSSam Leffler 	}
22639beb93cSSam Leffler 
22739beb93cSSam Leffler 	if (ctx->error) {
22839beb93cSSam Leffler 		os_free(ctx);
22939beb93cSSam Leffler 		return -2;
23039beb93cSSam Leffler 	}
23139beb93cSSam Leffler 
23239beb93cSSam Leffler 	switch (ctx->alg) {
23339beb93cSSam Leffler 	case CRYPTO_HASH_ALG_MD5:
23439beb93cSSam Leffler 		if (*len < 16) {
23539beb93cSSam Leffler 			*len = 16;
23639beb93cSSam Leffler 			os_free(ctx);
23739beb93cSSam Leffler 			return -1;
23839beb93cSSam Leffler 		}
23939beb93cSSam Leffler 		*len = 16;
24039beb93cSSam Leffler 		if (md5_done(&ctx->u.md, mac) != CRYPT_OK)
24139beb93cSSam Leffler 			ret = -2;
24239beb93cSSam Leffler 		break;
24339beb93cSSam Leffler 	case CRYPTO_HASH_ALG_SHA1:
24439beb93cSSam Leffler 		if (*len < 20) {
24539beb93cSSam Leffler 			*len = 20;
24639beb93cSSam Leffler 			os_free(ctx);
24739beb93cSSam Leffler 			return -1;
24839beb93cSSam Leffler 		}
24939beb93cSSam Leffler 		*len = 20;
25039beb93cSSam Leffler 		if (sha1_done(&ctx->u.md, mac) != CRYPT_OK)
25139beb93cSSam Leffler 			ret = -2;
25239beb93cSSam Leffler 		break;
25339beb93cSSam Leffler 	case CRYPTO_HASH_ALG_HMAC_SHA1:
25439beb93cSSam Leffler 		if (*len < 20) {
25539beb93cSSam Leffler 			*len = 20;
25639beb93cSSam Leffler 			os_free(ctx);
25739beb93cSSam Leffler 			return -1;
25839beb93cSSam Leffler 		}
25939beb93cSSam Leffler 		/* continue */
26039beb93cSSam Leffler 	case CRYPTO_HASH_ALG_HMAC_MD5:
26139beb93cSSam Leffler 		if (*len < 16) {
26239beb93cSSam Leffler 			*len = 16;
26339beb93cSSam Leffler 			os_free(ctx);
26439beb93cSSam Leffler 			return -1;
26539beb93cSSam Leffler 		}
26639beb93cSSam Leffler 		clen = *len;
26739beb93cSSam Leffler 		if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) {
26839beb93cSSam Leffler 			os_free(ctx);
26939beb93cSSam Leffler 			return -1;
27039beb93cSSam Leffler 		}
27139beb93cSSam Leffler 		*len = clen;
27239beb93cSSam Leffler 		break;
27339beb93cSSam Leffler 	default:
27439beb93cSSam Leffler 		ret = -2;
27539beb93cSSam Leffler 		break;
27639beb93cSSam Leffler 	}
27739beb93cSSam Leffler 
27839beb93cSSam Leffler 	os_free(ctx);
27939beb93cSSam Leffler 
28039beb93cSSam Leffler 	return ret;
28139beb93cSSam Leffler }
28239beb93cSSam Leffler 
28339beb93cSSam Leffler 
28439beb93cSSam Leffler struct crypto_cipher {
28539beb93cSSam Leffler 	int rc4;
28639beb93cSSam Leffler 	union {
28739beb93cSSam Leffler 		symmetric_CBC cbc;
28839beb93cSSam Leffler 		struct {
28939beb93cSSam Leffler 			size_t used_bytes;
29039beb93cSSam Leffler 			u8 key[16];
29139beb93cSSam Leffler 			size_t keylen;
29239beb93cSSam Leffler 		} rc4;
29339beb93cSSam Leffler 	} u;
29439beb93cSSam Leffler };
29539beb93cSSam Leffler 
29639beb93cSSam Leffler 
29739beb93cSSam Leffler struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
29839beb93cSSam Leffler 					  const u8 *iv, const u8 *key,
29939beb93cSSam Leffler 					  size_t key_len)
30039beb93cSSam Leffler {
30139beb93cSSam Leffler 	struct crypto_cipher *ctx;
30239beb93cSSam Leffler 	int idx, res, rc4 = 0;
30339beb93cSSam Leffler 
30439beb93cSSam Leffler 	switch (alg) {
30539beb93cSSam Leffler 	case CRYPTO_CIPHER_ALG_AES:
30639beb93cSSam Leffler 		idx = find_cipher("aes");
30739beb93cSSam Leffler 		break;
30839beb93cSSam Leffler 	case CRYPTO_CIPHER_ALG_3DES:
30939beb93cSSam Leffler 		idx = find_cipher("3des");
31039beb93cSSam Leffler 		break;
31139beb93cSSam Leffler 	case CRYPTO_CIPHER_ALG_DES:
31239beb93cSSam Leffler 		idx = find_cipher("des");
31339beb93cSSam Leffler 		break;
31439beb93cSSam Leffler 	case CRYPTO_CIPHER_ALG_RC2:
31539beb93cSSam Leffler 		idx = find_cipher("rc2");
31639beb93cSSam Leffler 		break;
31739beb93cSSam Leffler 	case CRYPTO_CIPHER_ALG_RC4:
31839beb93cSSam Leffler 		idx = -1;
31939beb93cSSam Leffler 		rc4 = 1;
32039beb93cSSam Leffler 		break;
32139beb93cSSam Leffler 	default:
32239beb93cSSam Leffler 		return NULL;
32339beb93cSSam Leffler 	}
32439beb93cSSam Leffler 
32539beb93cSSam Leffler 	ctx = os_zalloc(sizeof(*ctx));
32639beb93cSSam Leffler 	if (ctx == NULL)
32739beb93cSSam Leffler 		return NULL;
32839beb93cSSam Leffler 
32939beb93cSSam Leffler 	if (rc4) {
33039beb93cSSam Leffler 		ctx->rc4 = 1;
33139beb93cSSam Leffler 		if (key_len > sizeof(ctx->u.rc4.key)) {
33239beb93cSSam Leffler 			os_free(ctx);
33339beb93cSSam Leffler 			return NULL;
33439beb93cSSam Leffler 		}
33539beb93cSSam Leffler 		ctx->u.rc4.keylen = key_len;
33639beb93cSSam Leffler 		os_memcpy(ctx->u.rc4.key, key, key_len);
33739beb93cSSam Leffler 	} else {
33839beb93cSSam Leffler 		res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc);
33939beb93cSSam Leffler 		if (res != CRYPT_OK) {
34039beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start "
34139beb93cSSam Leffler 				   "failed: %s", error_to_string(res));
34239beb93cSSam Leffler 			os_free(ctx);
34339beb93cSSam Leffler 			return NULL;
34439beb93cSSam Leffler 		}
34539beb93cSSam Leffler 	}
34639beb93cSSam Leffler 
34739beb93cSSam Leffler 	return ctx;
34839beb93cSSam Leffler }
34939beb93cSSam Leffler 
35039beb93cSSam Leffler int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
35139beb93cSSam Leffler 			  u8 *crypt, size_t len)
35239beb93cSSam Leffler {
35339beb93cSSam Leffler 	int res;
35439beb93cSSam Leffler 
35539beb93cSSam Leffler 	if (ctx->rc4) {
35639beb93cSSam Leffler 		if (plain != crypt)
35739beb93cSSam Leffler 			os_memcpy(crypt, plain, len);
35839beb93cSSam Leffler 		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
35939beb93cSSam Leffler 			 ctx->u.rc4.used_bytes, crypt, len);
36039beb93cSSam Leffler 		ctx->u.rc4.used_bytes += len;
36139beb93cSSam Leffler 		return 0;
36239beb93cSSam Leffler 	}
36339beb93cSSam Leffler 
36439beb93cSSam Leffler 	res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc);
36539beb93cSSam Leffler 	if (res != CRYPT_OK) {
36639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption "
36739beb93cSSam Leffler 			   "failed: %s", error_to_string(res));
36839beb93cSSam Leffler 		return -1;
36939beb93cSSam Leffler 	}
37039beb93cSSam Leffler 	return 0;
37139beb93cSSam Leffler }
37239beb93cSSam Leffler 
37339beb93cSSam Leffler 
37439beb93cSSam Leffler int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
37539beb93cSSam Leffler 			  u8 *plain, size_t len)
37639beb93cSSam Leffler {
37739beb93cSSam Leffler 	int res;
37839beb93cSSam Leffler 
37939beb93cSSam Leffler 	if (ctx->rc4) {
38039beb93cSSam Leffler 		if (plain != crypt)
38139beb93cSSam Leffler 			os_memcpy(plain, crypt, len);
38239beb93cSSam Leffler 		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
38339beb93cSSam Leffler 			 ctx->u.rc4.used_bytes, plain, len);
38439beb93cSSam Leffler 		ctx->u.rc4.used_bytes += len;
38539beb93cSSam Leffler 		return 0;
38639beb93cSSam Leffler 	}
38739beb93cSSam Leffler 
38839beb93cSSam Leffler 	res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc);
38939beb93cSSam Leffler 	if (res != CRYPT_OK) {
39039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption "
39139beb93cSSam Leffler 			   "failed: %s", error_to_string(res));
39239beb93cSSam Leffler 		return -1;
39339beb93cSSam Leffler 	}
39439beb93cSSam Leffler 
39539beb93cSSam Leffler 	return 0;
39639beb93cSSam Leffler }
39739beb93cSSam Leffler 
39839beb93cSSam Leffler 
39939beb93cSSam Leffler void crypto_cipher_deinit(struct crypto_cipher *ctx)
40039beb93cSSam Leffler {
40139beb93cSSam Leffler 	if (!ctx->rc4)
40239beb93cSSam Leffler 		cbc_done(&ctx->u.cbc);
40339beb93cSSam Leffler 	os_free(ctx);
40439beb93cSSam Leffler }
40539beb93cSSam Leffler 
40639beb93cSSam Leffler 
40739beb93cSSam Leffler struct crypto_public_key {
40839beb93cSSam Leffler 	rsa_key rsa;
40939beb93cSSam Leffler };
41039beb93cSSam Leffler 
41139beb93cSSam Leffler struct crypto_private_key {
41239beb93cSSam Leffler 	rsa_key rsa;
41339beb93cSSam Leffler };
41439beb93cSSam Leffler 
41539beb93cSSam Leffler 
41639beb93cSSam Leffler struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
41739beb93cSSam Leffler {
41839beb93cSSam Leffler 	int res;
41939beb93cSSam Leffler 	struct crypto_public_key *pk;
42039beb93cSSam Leffler 
42139beb93cSSam Leffler 	pk = os_zalloc(sizeof(*pk));
42239beb93cSSam Leffler 	if (pk == NULL)
42339beb93cSSam Leffler 		return NULL;
42439beb93cSSam Leffler 
42539beb93cSSam Leffler 	res = rsa_import(key, len, &pk->rsa);
42639beb93cSSam Leffler 	if (res != CRYPT_OK) {
42739beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
42839beb93cSSam Leffler 			   "public key (res=%d '%s')",
42939beb93cSSam Leffler 			   res, error_to_string(res));
43039beb93cSSam Leffler 		os_free(pk);
43139beb93cSSam Leffler 		return NULL;
43239beb93cSSam Leffler 	}
43339beb93cSSam Leffler 
43439beb93cSSam Leffler 	if (pk->rsa.type != PK_PUBLIC) {
43539beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of "
43639beb93cSSam Leffler 			   "correct type");
43739beb93cSSam Leffler 		rsa_free(&pk->rsa);
43839beb93cSSam Leffler 		os_free(pk);
43939beb93cSSam Leffler 		return NULL;
44039beb93cSSam Leffler 	}
44139beb93cSSam Leffler 
44239beb93cSSam Leffler 	return pk;
44339beb93cSSam Leffler }
44439beb93cSSam Leffler 
44539beb93cSSam Leffler 
44639beb93cSSam Leffler struct crypto_private_key * crypto_private_key_import(const u8 *key,
447e28a4053SRui Paulo 						      size_t len,
448e28a4053SRui Paulo 						      const char *passwd)
44939beb93cSSam Leffler {
45039beb93cSSam Leffler 	int res;
45139beb93cSSam Leffler 	struct crypto_private_key *pk;
45239beb93cSSam Leffler 
45339beb93cSSam Leffler 	pk = os_zalloc(sizeof(*pk));
45439beb93cSSam Leffler 	if (pk == NULL)
45539beb93cSSam Leffler 		return NULL;
45639beb93cSSam Leffler 
45739beb93cSSam Leffler 	res = rsa_import(key, len, &pk->rsa);
45839beb93cSSam Leffler 	if (res != CRYPT_OK) {
45939beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
46039beb93cSSam Leffler 			   "private key (res=%d '%s')",
46139beb93cSSam Leffler 			   res, error_to_string(res));
46239beb93cSSam Leffler 		os_free(pk);
46339beb93cSSam Leffler 		return NULL;
46439beb93cSSam Leffler 	}
46539beb93cSSam Leffler 
46639beb93cSSam Leffler 	if (pk->rsa.type != PK_PRIVATE) {
46739beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of "
46839beb93cSSam Leffler 			   "correct type");
46939beb93cSSam Leffler 		rsa_free(&pk->rsa);
47039beb93cSSam Leffler 		os_free(pk);
47139beb93cSSam Leffler 		return NULL;
47239beb93cSSam Leffler 	}
47339beb93cSSam Leffler 
47439beb93cSSam Leffler 	return pk;
47539beb93cSSam Leffler }
47639beb93cSSam Leffler 
47739beb93cSSam Leffler 
47839beb93cSSam Leffler struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
47939beb93cSSam Leffler 						       size_t len)
48039beb93cSSam Leffler {
48139beb93cSSam Leffler 	/* No X.509 support in LibTomCrypt */
48239beb93cSSam Leffler 	return NULL;
48339beb93cSSam Leffler }
48439beb93cSSam Leffler 
48539beb93cSSam Leffler 
48639beb93cSSam Leffler static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
48739beb93cSSam Leffler 					   const u8 *in, size_t inlen,
48839beb93cSSam Leffler 					   u8 *out, size_t *outlen)
48939beb93cSSam Leffler {
49039beb93cSSam Leffler 	size_t ps_len;
49139beb93cSSam Leffler 	u8 *pos;
49239beb93cSSam Leffler 
49339beb93cSSam Leffler 	/*
49439beb93cSSam Leffler 	 * PKCS #1 v1.5, 8.1:
49539beb93cSSam Leffler 	 *
49639beb93cSSam Leffler 	 * EB = 00 || BT || PS || 00 || D
49739beb93cSSam Leffler 	 * BT = 00 or 01 for private-key operation; 02 for public-key operation
49839beb93cSSam Leffler 	 * PS = k-3-||D||; at least eight octets
49939beb93cSSam Leffler 	 * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
50039beb93cSSam Leffler 	 * k = length of modulus in octets (modlen)
50139beb93cSSam Leffler 	 */
50239beb93cSSam Leffler 
50339beb93cSSam Leffler 	if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
50439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
50539beb93cSSam Leffler 			   "lengths (modlen=%lu outlen=%lu inlen=%lu)",
50639beb93cSSam Leffler 			   __func__, (unsigned long) modlen,
50739beb93cSSam Leffler 			   (unsigned long) *outlen,
50839beb93cSSam Leffler 			   (unsigned long) inlen);
50939beb93cSSam Leffler 		return -1;
51039beb93cSSam Leffler 	}
51139beb93cSSam Leffler 
51239beb93cSSam Leffler 	pos = out;
51339beb93cSSam Leffler 	*pos++ = 0x00;
51439beb93cSSam Leffler 	*pos++ = block_type; /* BT */
51539beb93cSSam Leffler 	ps_len = modlen - inlen - 3;
51639beb93cSSam Leffler 	switch (block_type) {
51739beb93cSSam Leffler 	case 0:
51839beb93cSSam Leffler 		os_memset(pos, 0x00, ps_len);
51939beb93cSSam Leffler 		pos += ps_len;
52039beb93cSSam Leffler 		break;
52139beb93cSSam Leffler 	case 1:
52239beb93cSSam Leffler 		os_memset(pos, 0xff, ps_len);
52339beb93cSSam Leffler 		pos += ps_len;
52439beb93cSSam Leffler 		break;
52539beb93cSSam Leffler 	case 2:
52639beb93cSSam Leffler 		if (os_get_random(pos, ps_len) < 0) {
52739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
52839beb93cSSam Leffler 				   "random data for PS", __func__);
52939beb93cSSam Leffler 			return -1;
53039beb93cSSam Leffler 		}
53139beb93cSSam Leffler 		while (ps_len--) {
53239beb93cSSam Leffler 			if (*pos == 0x00)
53339beb93cSSam Leffler 				*pos = 0x01;
53439beb93cSSam Leffler 			pos++;
53539beb93cSSam Leffler 		}
53639beb93cSSam Leffler 		break;
53739beb93cSSam Leffler 	default:
53839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
53939beb93cSSam Leffler 			   "%d", __func__, block_type);
54039beb93cSSam Leffler 		return -1;
54139beb93cSSam Leffler 	}
54239beb93cSSam Leffler 	*pos++ = 0x00;
54339beb93cSSam Leffler 	os_memcpy(pos, in, inlen); /* D */
54439beb93cSSam Leffler 
54539beb93cSSam Leffler 	return 0;
54639beb93cSSam Leffler }
54739beb93cSSam Leffler 
54839beb93cSSam Leffler 
54939beb93cSSam Leffler static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type,
55039beb93cSSam Leffler 				    const u8 *in, size_t inlen,
55139beb93cSSam Leffler 				    u8 *out, size_t *outlen)
55239beb93cSSam Leffler {
55339beb93cSSam Leffler 	unsigned long len, modlen;
55439beb93cSSam Leffler 	int res;
55539beb93cSSam Leffler 
55639beb93cSSam Leffler 	modlen = mp_unsigned_bin_size(key->N);
55739beb93cSSam Leffler 
55839beb93cSSam Leffler 	if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
55939beb93cSSam Leffler 					    out, outlen) < 0)
56039beb93cSSam Leffler 		return -1;
56139beb93cSSam Leffler 
56239beb93cSSam Leffler 	len = *outlen;
56339beb93cSSam Leffler 	res = rsa_exptmod(out, modlen, out, &len, key_type, key);
56439beb93cSSam Leffler 	if (res != CRYPT_OK) {
56539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
56639beb93cSSam Leffler 			   error_to_string(res));
56739beb93cSSam Leffler 		return -1;
56839beb93cSSam Leffler 	}
56939beb93cSSam Leffler 	*outlen = len;
57039beb93cSSam Leffler 
57139beb93cSSam Leffler 	return 0;
57239beb93cSSam Leffler }
57339beb93cSSam Leffler 
57439beb93cSSam Leffler 
57539beb93cSSam Leffler int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
57639beb93cSSam Leffler 					const u8 *in, size_t inlen,
57739beb93cSSam Leffler 					u8 *out, size_t *outlen)
57839beb93cSSam Leffler {
57939beb93cSSam Leffler 	return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen,
58039beb93cSSam Leffler 					out, outlen);
58139beb93cSSam Leffler }
58239beb93cSSam Leffler 
58339beb93cSSam Leffler 
58439beb93cSSam Leffler int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
58539beb93cSSam Leffler 				  const u8 *in, size_t inlen,
58639beb93cSSam Leffler 				  u8 *out, size_t *outlen)
58739beb93cSSam Leffler {
58839beb93cSSam Leffler 	return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen,
58939beb93cSSam Leffler 					out, outlen);
59039beb93cSSam Leffler }
59139beb93cSSam Leffler 
59239beb93cSSam Leffler 
59339beb93cSSam Leffler void crypto_public_key_free(struct crypto_public_key *key)
59439beb93cSSam Leffler {
59539beb93cSSam Leffler 	if (key) {
59639beb93cSSam Leffler 		rsa_free(&key->rsa);
59739beb93cSSam Leffler 		os_free(key);
59839beb93cSSam Leffler 	}
59939beb93cSSam Leffler }
60039beb93cSSam Leffler 
60139beb93cSSam Leffler 
60239beb93cSSam Leffler void crypto_private_key_free(struct crypto_private_key *key)
60339beb93cSSam Leffler {
60439beb93cSSam Leffler 	if (key) {
60539beb93cSSam Leffler 		rsa_free(&key->rsa);
60639beb93cSSam Leffler 		os_free(key);
60739beb93cSSam Leffler 	}
60839beb93cSSam Leffler }
60939beb93cSSam Leffler 
61039beb93cSSam Leffler 
61139beb93cSSam Leffler int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
61239beb93cSSam Leffler 				    const u8 *crypt, size_t crypt_len,
61339beb93cSSam Leffler 				    u8 *plain, size_t *plain_len)
61439beb93cSSam Leffler {
61539beb93cSSam Leffler 	int res;
61639beb93cSSam Leffler 	unsigned long len;
61739beb93cSSam Leffler 	u8 *pos;
61839beb93cSSam Leffler 
61939beb93cSSam Leffler 	len = *plain_len;
62039beb93cSSam Leffler 	res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC,
62139beb93cSSam Leffler 			  &key->rsa);
62239beb93cSSam Leffler 	if (res != CRYPT_OK) {
62339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
62439beb93cSSam Leffler 			   error_to_string(res));
62539beb93cSSam Leffler 		return -1;
62639beb93cSSam Leffler 	}
62739beb93cSSam Leffler 
62839beb93cSSam Leffler 	/*
62939beb93cSSam Leffler 	 * PKCS #1 v1.5, 8.1:
63039beb93cSSam Leffler 	 *
63139beb93cSSam Leffler 	 * EB = 00 || BT || PS || 00 || D
63239beb93cSSam Leffler 	 * BT = 01
63339beb93cSSam Leffler 	 * PS = k-3-||D|| times FF
63439beb93cSSam Leffler 	 * k = length of modulus in octets
63539beb93cSSam Leffler 	 */
63639beb93cSSam Leffler 
63739beb93cSSam Leffler 	if (len < 3 + 8 + 16 /* min hash len */ ||
63839beb93cSSam Leffler 	    plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
63939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
64039beb93cSSam Leffler 			   "structure");
64139beb93cSSam Leffler 		return -1;
64239beb93cSSam Leffler 	}
64339beb93cSSam Leffler 
64439beb93cSSam Leffler 	pos = plain + 3;
64539beb93cSSam Leffler 	while (pos < plain + len && *pos == 0xff)
64639beb93cSSam Leffler 		pos++;
64739beb93cSSam Leffler 	if (pos - plain - 2 < 8) {
64839beb93cSSam Leffler 		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
64939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
65039beb93cSSam Leffler 			   "padding");
65139beb93cSSam Leffler 		return -1;
65239beb93cSSam Leffler 	}
65339beb93cSSam Leffler 
65439beb93cSSam Leffler 	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
65539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
65639beb93cSSam Leffler 			   "structure (2)");
65739beb93cSSam Leffler 		return -1;
65839beb93cSSam Leffler 	}
65939beb93cSSam Leffler 	pos++;
66039beb93cSSam Leffler 	len -= pos - plain;
66139beb93cSSam Leffler 
66239beb93cSSam Leffler 	/* Strip PKCS #1 header */
66339beb93cSSam Leffler 	os_memmove(plain, pos, len);
66439beb93cSSam Leffler 	*plain_len = len;
66539beb93cSSam Leffler 
66639beb93cSSam Leffler 	return 0;
66739beb93cSSam Leffler }
66839beb93cSSam Leffler 
66939beb93cSSam Leffler 
67039beb93cSSam Leffler int crypto_global_init(void)
67139beb93cSSam Leffler {
67239beb93cSSam Leffler 	ltc_mp = tfm_desc;
67339beb93cSSam Leffler 	/* TODO: only register algorithms that are really needed */
67439beb93cSSam Leffler 	if (register_hash(&md4_desc) < 0 ||
67539beb93cSSam Leffler 	    register_hash(&md5_desc) < 0 ||
67639beb93cSSam Leffler 	    register_hash(&sha1_desc) < 0 ||
67739beb93cSSam Leffler 	    register_cipher(&aes_desc) < 0 ||
67839beb93cSSam Leffler 	    register_cipher(&des_desc) < 0 ||
67939beb93cSSam Leffler 	    register_cipher(&des3_desc) < 0) {
68039beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TLSv1: Failed to register "
68139beb93cSSam Leffler 			   "hash/cipher functions");
68239beb93cSSam Leffler 		return -1;
68339beb93cSSam Leffler 	}
68439beb93cSSam Leffler 
68539beb93cSSam Leffler 	return 0;
68639beb93cSSam Leffler }
68739beb93cSSam Leffler 
68839beb93cSSam Leffler 
68939beb93cSSam Leffler void crypto_global_deinit(void)
69039beb93cSSam Leffler {
69139beb93cSSam Leffler }
69239beb93cSSam Leffler 
69339beb93cSSam Leffler 
694e28a4053SRui Paulo #ifdef CONFIG_MODEXP
69539beb93cSSam Leffler 
69639beb93cSSam Leffler int crypto_mod_exp(const u8 *base, size_t base_len,
69739beb93cSSam Leffler 		   const u8 *power, size_t power_len,
69839beb93cSSam Leffler 		   const u8 *modulus, size_t modulus_len,
69939beb93cSSam Leffler 		   u8 *result, size_t *result_len)
70039beb93cSSam Leffler {
70139beb93cSSam Leffler 	void *b, *p, *m, *r;
70239beb93cSSam Leffler 
70339beb93cSSam Leffler 	if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK)
70439beb93cSSam Leffler 		return -1;
70539beb93cSSam Leffler 
70639beb93cSSam Leffler 	if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK ||
70739beb93cSSam Leffler 	    mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK ||
70839beb93cSSam Leffler 	    mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK)
70939beb93cSSam Leffler 		goto fail;
71039beb93cSSam Leffler 
71139beb93cSSam Leffler 	if (mp_exptmod(b, p, m, r) != CRYPT_OK)
71239beb93cSSam Leffler 		goto fail;
71339beb93cSSam Leffler 
71439beb93cSSam Leffler 	*result_len = mp_unsigned_bin_size(r);
71539beb93cSSam Leffler 	if (mp_to_unsigned_bin(r, result) != CRYPT_OK)
71639beb93cSSam Leffler 		goto fail;
71739beb93cSSam Leffler 
71839beb93cSSam Leffler 	mp_clear_multi(b, p, m, r, NULL);
71939beb93cSSam Leffler 	return 0;
72039beb93cSSam Leffler 
72139beb93cSSam Leffler fail:
72239beb93cSSam Leffler 	mp_clear_multi(b, p, m, r, NULL);
72339beb93cSSam Leffler 	return -1;
72439beb93cSSam Leffler }
72539beb93cSSam Leffler 
726e28a4053SRui Paulo #endif /* CONFIG_MODEXP */
727