1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
3e5b75505Sopenharmony_ci * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "includes.h"
10e5b75505Sopenharmony_ci#include <tomcrypt.h>
11e5b75505Sopenharmony_ci
12e5b75505Sopenharmony_ci#include "common.h"
13e5b75505Sopenharmony_ci#include "crypto.h"
14e5b75505Sopenharmony_ci
15e5b75505Sopenharmony_ci#ifndef mp_init_multi
16e5b75505Sopenharmony_ci#define mp_init_multi                ltc_init_multi
17e5b75505Sopenharmony_ci#define mp_clear_multi               ltc_deinit_multi
18e5b75505Sopenharmony_ci#define mp_unsigned_bin_size(a)      ltc_mp.unsigned_size(a)
19e5b75505Sopenharmony_ci#define mp_to_unsigned_bin(a, b)     ltc_mp.unsigned_write(a, b)
20e5b75505Sopenharmony_ci#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
21e5b75505Sopenharmony_ci#define mp_exptmod(a,b,c,d)          ltc_mp.exptmod(a,b,c,d)
22e5b75505Sopenharmony_ci#endif
23e5b75505Sopenharmony_ci
24e5b75505Sopenharmony_ci
25e5b75505Sopenharmony_ciint md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
26e5b75505Sopenharmony_ci{
27e5b75505Sopenharmony_ci	hash_state md;
28e5b75505Sopenharmony_ci	size_t i;
29e5b75505Sopenharmony_ci
30e5b75505Sopenharmony_ci	md4_init(&md);
31e5b75505Sopenharmony_ci	for (i = 0; i < num_elem; i++)
32e5b75505Sopenharmony_ci		md4_process(&md, addr[i], len[i]);
33e5b75505Sopenharmony_ci	md4_done(&md, mac);
34e5b75505Sopenharmony_ci	return 0;
35e5b75505Sopenharmony_ci}
36e5b75505Sopenharmony_ci
37e5b75505Sopenharmony_ci
38e5b75505Sopenharmony_ciint des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
39e5b75505Sopenharmony_ci{
40e5b75505Sopenharmony_ci	u8 pkey[8], next, tmp;
41e5b75505Sopenharmony_ci	int i;
42e5b75505Sopenharmony_ci	symmetric_key skey;
43e5b75505Sopenharmony_ci
44e5b75505Sopenharmony_ci	/* Add parity bits to the key */
45e5b75505Sopenharmony_ci	next = 0;
46e5b75505Sopenharmony_ci	for (i = 0; i < 7; i++) {
47e5b75505Sopenharmony_ci		tmp = key[i];
48e5b75505Sopenharmony_ci		pkey[i] = (tmp >> i) | next | 1;
49e5b75505Sopenharmony_ci		next = tmp << (7 - i);
50e5b75505Sopenharmony_ci	}
51e5b75505Sopenharmony_ci	pkey[i] = next | 1;
52e5b75505Sopenharmony_ci
53e5b75505Sopenharmony_ci	des_setup(pkey, 8, 0, &skey);
54e5b75505Sopenharmony_ci	des_ecb_encrypt(clear, cypher, &skey);
55e5b75505Sopenharmony_ci	des_done(&skey);
56e5b75505Sopenharmony_ci	return 0;
57e5b75505Sopenharmony_ci}
58e5b75505Sopenharmony_ci
59e5b75505Sopenharmony_ci
60e5b75505Sopenharmony_ciint md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
61e5b75505Sopenharmony_ci{
62e5b75505Sopenharmony_ci	hash_state md;
63e5b75505Sopenharmony_ci	size_t i;
64e5b75505Sopenharmony_ci
65e5b75505Sopenharmony_ci	md5_init(&md);
66e5b75505Sopenharmony_ci	for (i = 0; i < num_elem; i++)
67e5b75505Sopenharmony_ci		md5_process(&md, addr[i], len[i]);
68e5b75505Sopenharmony_ci	md5_done(&md, mac);
69e5b75505Sopenharmony_ci	return 0;
70e5b75505Sopenharmony_ci}
71e5b75505Sopenharmony_ci
72e5b75505Sopenharmony_ci
73e5b75505Sopenharmony_ciint sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
74e5b75505Sopenharmony_ci{
75e5b75505Sopenharmony_ci	hash_state md;
76e5b75505Sopenharmony_ci	size_t i;
77e5b75505Sopenharmony_ci
78e5b75505Sopenharmony_ci	sha1_init(&md);
79e5b75505Sopenharmony_ci	for (i = 0; i < num_elem; i++)
80e5b75505Sopenharmony_ci		sha1_process(&md, addr[i], len[i]);
81e5b75505Sopenharmony_ci	sha1_done(&md, mac);
82e5b75505Sopenharmony_ci	return 0;
83e5b75505Sopenharmony_ci}
84e5b75505Sopenharmony_ci
85e5b75505Sopenharmony_ci
86e5b75505Sopenharmony_civoid * aes_encrypt_init(const u8 *key, size_t len)
87e5b75505Sopenharmony_ci{
88e5b75505Sopenharmony_ci	symmetric_key *skey;
89e5b75505Sopenharmony_ci	skey = os_malloc(sizeof(*skey));
90e5b75505Sopenharmony_ci	if (skey == NULL)
91e5b75505Sopenharmony_ci		return NULL;
92e5b75505Sopenharmony_ci	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
93e5b75505Sopenharmony_ci		os_free(skey);
94e5b75505Sopenharmony_ci		return NULL;
95e5b75505Sopenharmony_ci	}
96e5b75505Sopenharmony_ci	return skey;
97e5b75505Sopenharmony_ci}
98e5b75505Sopenharmony_ci
99e5b75505Sopenharmony_ci
100e5b75505Sopenharmony_ciint aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
101e5b75505Sopenharmony_ci{
102e5b75505Sopenharmony_ci	symmetric_key *skey = ctx;
103e5b75505Sopenharmony_ci	return aes_ecb_encrypt(plain, crypt, skey) == CRYPT_OK ? 0 : -1;
104e5b75505Sopenharmony_ci}
105e5b75505Sopenharmony_ci
106e5b75505Sopenharmony_ci
107e5b75505Sopenharmony_civoid aes_encrypt_deinit(void *ctx)
108e5b75505Sopenharmony_ci{
109e5b75505Sopenharmony_ci	symmetric_key *skey = ctx;
110e5b75505Sopenharmony_ci	aes_done(skey);
111e5b75505Sopenharmony_ci	os_free(skey);
112e5b75505Sopenharmony_ci}
113e5b75505Sopenharmony_ci
114e5b75505Sopenharmony_ci
115e5b75505Sopenharmony_civoid * aes_decrypt_init(const u8 *key, size_t len)
116e5b75505Sopenharmony_ci{
117e5b75505Sopenharmony_ci	symmetric_key *skey;
118e5b75505Sopenharmony_ci	skey = os_malloc(sizeof(*skey));
119e5b75505Sopenharmony_ci	if (skey == NULL)
120e5b75505Sopenharmony_ci		return NULL;
121e5b75505Sopenharmony_ci	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
122e5b75505Sopenharmony_ci		os_free(skey);
123e5b75505Sopenharmony_ci		return NULL;
124e5b75505Sopenharmony_ci	}
125e5b75505Sopenharmony_ci	return skey;
126e5b75505Sopenharmony_ci}
127e5b75505Sopenharmony_ci
128e5b75505Sopenharmony_ci
129e5b75505Sopenharmony_ciint aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
130e5b75505Sopenharmony_ci{
131e5b75505Sopenharmony_ci	symmetric_key *skey = ctx;
132e5b75505Sopenharmony_ci	return aes_ecb_encrypt(plain, (u8 *) crypt, skey) == CRYPT_OK ? 0 : -1;
133e5b75505Sopenharmony_ci}
134e5b75505Sopenharmony_ci
135e5b75505Sopenharmony_ci
136e5b75505Sopenharmony_civoid aes_decrypt_deinit(void *ctx)
137e5b75505Sopenharmony_ci{
138e5b75505Sopenharmony_ci	symmetric_key *skey = ctx;
139e5b75505Sopenharmony_ci	aes_done(skey);
140e5b75505Sopenharmony_ci	os_free(skey);
141e5b75505Sopenharmony_ci}
142e5b75505Sopenharmony_ci
143e5b75505Sopenharmony_ci
144e5b75505Sopenharmony_cistruct crypto_hash {
145e5b75505Sopenharmony_ci	enum crypto_hash_alg alg;
146e5b75505Sopenharmony_ci	int error;
147e5b75505Sopenharmony_ci	union {
148e5b75505Sopenharmony_ci		hash_state md;
149e5b75505Sopenharmony_ci		hmac_state hmac;
150e5b75505Sopenharmony_ci	} u;
151e5b75505Sopenharmony_ci};
152e5b75505Sopenharmony_ci
153e5b75505Sopenharmony_ci
154e5b75505Sopenharmony_cistruct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
155e5b75505Sopenharmony_ci				      size_t key_len)
156e5b75505Sopenharmony_ci{
157e5b75505Sopenharmony_ci	struct crypto_hash *ctx;
158e5b75505Sopenharmony_ci
159e5b75505Sopenharmony_ci	ctx = os_zalloc(sizeof(*ctx));
160e5b75505Sopenharmony_ci	if (ctx == NULL)
161e5b75505Sopenharmony_ci		return NULL;
162e5b75505Sopenharmony_ci
163e5b75505Sopenharmony_ci	ctx->alg = alg;
164e5b75505Sopenharmony_ci
165e5b75505Sopenharmony_ci	switch (alg) {
166e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_MD5:
167e5b75505Sopenharmony_ci		if (md5_init(&ctx->u.md) != CRYPT_OK)
168e5b75505Sopenharmony_ci			goto fail;
169e5b75505Sopenharmony_ci		break;
170e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA1:
171e5b75505Sopenharmony_ci		if (sha1_init(&ctx->u.md) != CRYPT_OK)
172e5b75505Sopenharmony_ci			goto fail;
173e5b75505Sopenharmony_ci		break;
174e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_MD5:
175e5b75505Sopenharmony_ci		if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) !=
176e5b75505Sopenharmony_ci		    CRYPT_OK)
177e5b75505Sopenharmony_ci			goto fail;
178e5b75505Sopenharmony_ci		break;
179e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_SHA1:
180e5b75505Sopenharmony_ci		if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) !=
181e5b75505Sopenharmony_ci		    CRYPT_OK)
182e5b75505Sopenharmony_ci			goto fail;
183e5b75505Sopenharmony_ci		break;
184e5b75505Sopenharmony_ci	default:
185e5b75505Sopenharmony_ci		goto fail;
186e5b75505Sopenharmony_ci	}
187e5b75505Sopenharmony_ci
188e5b75505Sopenharmony_ci	return ctx;
189e5b75505Sopenharmony_ci
190e5b75505Sopenharmony_cifail:
191e5b75505Sopenharmony_ci	os_free(ctx);
192e5b75505Sopenharmony_ci	return NULL;
193e5b75505Sopenharmony_ci}
194e5b75505Sopenharmony_ci
195e5b75505Sopenharmony_civoid crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
196e5b75505Sopenharmony_ci{
197e5b75505Sopenharmony_ci	if (ctx == NULL || ctx->error)
198e5b75505Sopenharmony_ci		return;
199e5b75505Sopenharmony_ci
200e5b75505Sopenharmony_ci	switch (ctx->alg) {
201e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_MD5:
202e5b75505Sopenharmony_ci		ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK;
203e5b75505Sopenharmony_ci		break;
204e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA1:
205e5b75505Sopenharmony_ci		ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK;
206e5b75505Sopenharmony_ci		break;
207e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_MD5:
208e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_SHA1:
209e5b75505Sopenharmony_ci		ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK;
210e5b75505Sopenharmony_ci		break;
211e5b75505Sopenharmony_ci	}
212e5b75505Sopenharmony_ci}
213e5b75505Sopenharmony_ci
214e5b75505Sopenharmony_ci
215e5b75505Sopenharmony_ciint crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
216e5b75505Sopenharmony_ci{
217e5b75505Sopenharmony_ci	int ret = 0;
218e5b75505Sopenharmony_ci	unsigned long clen;
219e5b75505Sopenharmony_ci
220e5b75505Sopenharmony_ci	if (ctx == NULL)
221e5b75505Sopenharmony_ci		return -2;
222e5b75505Sopenharmony_ci
223e5b75505Sopenharmony_ci	if (mac == NULL || len == NULL) {
224e5b75505Sopenharmony_ci		os_free(ctx);
225e5b75505Sopenharmony_ci		return 0;
226e5b75505Sopenharmony_ci	}
227e5b75505Sopenharmony_ci
228e5b75505Sopenharmony_ci	if (ctx->error) {
229e5b75505Sopenharmony_ci		os_free(ctx);
230e5b75505Sopenharmony_ci		return -2;
231e5b75505Sopenharmony_ci	}
232e5b75505Sopenharmony_ci
233e5b75505Sopenharmony_ci	switch (ctx->alg) {
234e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_MD5:
235e5b75505Sopenharmony_ci		if (*len < 16) {
236e5b75505Sopenharmony_ci			*len = 16;
237e5b75505Sopenharmony_ci			os_free(ctx);
238e5b75505Sopenharmony_ci			return -1;
239e5b75505Sopenharmony_ci		}
240e5b75505Sopenharmony_ci		*len = 16;
241e5b75505Sopenharmony_ci		if (md5_done(&ctx->u.md, mac) != CRYPT_OK)
242e5b75505Sopenharmony_ci			ret = -2;
243e5b75505Sopenharmony_ci		break;
244e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA1:
245e5b75505Sopenharmony_ci		if (*len < 20) {
246e5b75505Sopenharmony_ci			*len = 20;
247e5b75505Sopenharmony_ci			os_free(ctx);
248e5b75505Sopenharmony_ci			return -1;
249e5b75505Sopenharmony_ci		}
250e5b75505Sopenharmony_ci		*len = 20;
251e5b75505Sopenharmony_ci		if (sha1_done(&ctx->u.md, mac) != CRYPT_OK)
252e5b75505Sopenharmony_ci			ret = -2;
253e5b75505Sopenharmony_ci		break;
254e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_SHA1:
255e5b75505Sopenharmony_ci		if (*len < 20) {
256e5b75505Sopenharmony_ci			*len = 20;
257e5b75505Sopenharmony_ci			os_free(ctx);
258e5b75505Sopenharmony_ci			return -1;
259e5b75505Sopenharmony_ci		}
260e5b75505Sopenharmony_ci		/* continue */
261e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_MD5:
262e5b75505Sopenharmony_ci		if (*len < 16) {
263e5b75505Sopenharmony_ci			*len = 16;
264e5b75505Sopenharmony_ci			os_free(ctx);
265e5b75505Sopenharmony_ci			return -1;
266e5b75505Sopenharmony_ci		}
267e5b75505Sopenharmony_ci		clen = *len;
268e5b75505Sopenharmony_ci		if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) {
269e5b75505Sopenharmony_ci			os_free(ctx);
270e5b75505Sopenharmony_ci			return -1;
271e5b75505Sopenharmony_ci		}
272e5b75505Sopenharmony_ci		*len = clen;
273e5b75505Sopenharmony_ci		break;
274e5b75505Sopenharmony_ci	default:
275e5b75505Sopenharmony_ci		ret = -2;
276e5b75505Sopenharmony_ci		break;
277e5b75505Sopenharmony_ci	}
278e5b75505Sopenharmony_ci
279e5b75505Sopenharmony_ci	os_free(ctx);
280e5b75505Sopenharmony_ci
281e5b75505Sopenharmony_ci	if (TEST_FAIL())
282e5b75505Sopenharmony_ci		return -1;
283e5b75505Sopenharmony_ci
284e5b75505Sopenharmony_ci	return ret;
285e5b75505Sopenharmony_ci}
286e5b75505Sopenharmony_ci
287e5b75505Sopenharmony_ci
288e5b75505Sopenharmony_cistruct crypto_cipher {
289e5b75505Sopenharmony_ci	int rc4;
290e5b75505Sopenharmony_ci	union {
291e5b75505Sopenharmony_ci		symmetric_CBC cbc;
292e5b75505Sopenharmony_ci		struct {
293e5b75505Sopenharmony_ci			size_t used_bytes;
294e5b75505Sopenharmony_ci			u8 key[16];
295e5b75505Sopenharmony_ci			size_t keylen;
296e5b75505Sopenharmony_ci		} rc4;
297e5b75505Sopenharmony_ci	} u;
298e5b75505Sopenharmony_ci};
299e5b75505Sopenharmony_ci
300e5b75505Sopenharmony_ci
301e5b75505Sopenharmony_cistruct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
302e5b75505Sopenharmony_ci					  const u8 *iv, const u8 *key,
303e5b75505Sopenharmony_ci					  size_t key_len)
304e5b75505Sopenharmony_ci{
305e5b75505Sopenharmony_ci	struct crypto_cipher *ctx;
306e5b75505Sopenharmony_ci	int idx, res, rc4 = 0;
307e5b75505Sopenharmony_ci
308e5b75505Sopenharmony_ci	switch (alg) {
309e5b75505Sopenharmony_ci	case CRYPTO_CIPHER_ALG_AES:
310e5b75505Sopenharmony_ci		idx = find_cipher("aes");
311e5b75505Sopenharmony_ci		break;
312e5b75505Sopenharmony_ci	case CRYPTO_CIPHER_ALG_3DES:
313e5b75505Sopenharmony_ci		idx = find_cipher("3des");
314e5b75505Sopenharmony_ci		break;
315e5b75505Sopenharmony_ci	case CRYPTO_CIPHER_ALG_DES:
316e5b75505Sopenharmony_ci		idx = find_cipher("des");
317e5b75505Sopenharmony_ci		break;
318e5b75505Sopenharmony_ci	case CRYPTO_CIPHER_ALG_RC2:
319e5b75505Sopenharmony_ci		idx = find_cipher("rc2");
320e5b75505Sopenharmony_ci		break;
321e5b75505Sopenharmony_ci	case CRYPTO_CIPHER_ALG_RC4:
322e5b75505Sopenharmony_ci		idx = -1;
323e5b75505Sopenharmony_ci		rc4 = 1;
324e5b75505Sopenharmony_ci		break;
325e5b75505Sopenharmony_ci	default:
326e5b75505Sopenharmony_ci		return NULL;
327e5b75505Sopenharmony_ci	}
328e5b75505Sopenharmony_ci
329e5b75505Sopenharmony_ci	ctx = os_zalloc(sizeof(*ctx));
330e5b75505Sopenharmony_ci	if (ctx == NULL)
331e5b75505Sopenharmony_ci		return NULL;
332e5b75505Sopenharmony_ci
333e5b75505Sopenharmony_ci	if (rc4) {
334e5b75505Sopenharmony_ci		ctx->rc4 = 1;
335e5b75505Sopenharmony_ci		if (key_len > sizeof(ctx->u.rc4.key)) {
336e5b75505Sopenharmony_ci			os_free(ctx);
337e5b75505Sopenharmony_ci			return NULL;
338e5b75505Sopenharmony_ci		}
339e5b75505Sopenharmony_ci		ctx->u.rc4.keylen = key_len;
340e5b75505Sopenharmony_ci		os_memcpy(ctx->u.rc4.key, key, key_len);
341e5b75505Sopenharmony_ci	} else {
342e5b75505Sopenharmony_ci		res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc);
343e5b75505Sopenharmony_ci		if (res != CRYPT_OK) {
344e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start "
345e5b75505Sopenharmony_ci				   "failed: %s", error_to_string(res));
346e5b75505Sopenharmony_ci			os_free(ctx);
347e5b75505Sopenharmony_ci			return NULL;
348e5b75505Sopenharmony_ci		}
349e5b75505Sopenharmony_ci	}
350e5b75505Sopenharmony_ci
351e5b75505Sopenharmony_ci	return ctx;
352e5b75505Sopenharmony_ci}
353e5b75505Sopenharmony_ci
354e5b75505Sopenharmony_ciint crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
355e5b75505Sopenharmony_ci			  u8 *crypt, size_t len)
356e5b75505Sopenharmony_ci{
357e5b75505Sopenharmony_ci	int res;
358e5b75505Sopenharmony_ci
359e5b75505Sopenharmony_ci	if (ctx->rc4) {
360e5b75505Sopenharmony_ci		if (plain != crypt)
361e5b75505Sopenharmony_ci			os_memcpy(crypt, plain, len);
362e5b75505Sopenharmony_ci		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
363e5b75505Sopenharmony_ci			 ctx->u.rc4.used_bytes, crypt, len);
364e5b75505Sopenharmony_ci		ctx->u.rc4.used_bytes += len;
365e5b75505Sopenharmony_ci		return 0;
366e5b75505Sopenharmony_ci	}
367e5b75505Sopenharmony_ci
368e5b75505Sopenharmony_ci	res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc);
369e5b75505Sopenharmony_ci	if (res != CRYPT_OK) {
370e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption "
371e5b75505Sopenharmony_ci			   "failed: %s", error_to_string(res));
372e5b75505Sopenharmony_ci		return -1;
373e5b75505Sopenharmony_ci	}
374e5b75505Sopenharmony_ci	return 0;
375e5b75505Sopenharmony_ci}
376e5b75505Sopenharmony_ci
377e5b75505Sopenharmony_ci
378e5b75505Sopenharmony_ciint crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
379e5b75505Sopenharmony_ci			  u8 *plain, size_t len)
380e5b75505Sopenharmony_ci{
381e5b75505Sopenharmony_ci	int res;
382e5b75505Sopenharmony_ci
383e5b75505Sopenharmony_ci	if (ctx->rc4) {
384e5b75505Sopenharmony_ci		if (plain != crypt)
385e5b75505Sopenharmony_ci			os_memcpy(plain, crypt, len);
386e5b75505Sopenharmony_ci		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
387e5b75505Sopenharmony_ci			 ctx->u.rc4.used_bytes, plain, len);
388e5b75505Sopenharmony_ci		ctx->u.rc4.used_bytes += len;
389e5b75505Sopenharmony_ci		return 0;
390e5b75505Sopenharmony_ci	}
391e5b75505Sopenharmony_ci
392e5b75505Sopenharmony_ci	res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc);
393e5b75505Sopenharmony_ci	if (res != CRYPT_OK) {
394e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption "
395e5b75505Sopenharmony_ci			   "failed: %s", error_to_string(res));
396e5b75505Sopenharmony_ci		return -1;
397e5b75505Sopenharmony_ci	}
398e5b75505Sopenharmony_ci
399e5b75505Sopenharmony_ci	return 0;
400e5b75505Sopenharmony_ci}
401e5b75505Sopenharmony_ci
402e5b75505Sopenharmony_ci
403e5b75505Sopenharmony_civoid crypto_cipher_deinit(struct crypto_cipher *ctx)
404e5b75505Sopenharmony_ci{
405e5b75505Sopenharmony_ci	if (!ctx->rc4)
406e5b75505Sopenharmony_ci		cbc_done(&ctx->u.cbc);
407e5b75505Sopenharmony_ci	os_free(ctx);
408e5b75505Sopenharmony_ci}
409e5b75505Sopenharmony_ci
410e5b75505Sopenharmony_ci
411e5b75505Sopenharmony_cistruct crypto_public_key {
412e5b75505Sopenharmony_ci	rsa_key rsa;
413e5b75505Sopenharmony_ci};
414e5b75505Sopenharmony_ci
415e5b75505Sopenharmony_cistruct crypto_private_key {
416e5b75505Sopenharmony_ci	rsa_key rsa;
417e5b75505Sopenharmony_ci};
418e5b75505Sopenharmony_ci
419e5b75505Sopenharmony_ci
420e5b75505Sopenharmony_cistruct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
421e5b75505Sopenharmony_ci{
422e5b75505Sopenharmony_ci	int res;
423e5b75505Sopenharmony_ci	struct crypto_public_key *pk;
424e5b75505Sopenharmony_ci
425e5b75505Sopenharmony_ci	pk = os_zalloc(sizeof(*pk));
426e5b75505Sopenharmony_ci	if (pk == NULL)
427e5b75505Sopenharmony_ci		return NULL;
428e5b75505Sopenharmony_ci
429e5b75505Sopenharmony_ci	res = rsa_import(key, len, &pk->rsa);
430e5b75505Sopenharmony_ci	if (res != CRYPT_OK) {
431e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
432e5b75505Sopenharmony_ci			   "public key (res=%d '%s')",
433e5b75505Sopenharmony_ci			   res, error_to_string(res));
434e5b75505Sopenharmony_ci		os_free(pk);
435e5b75505Sopenharmony_ci		return NULL;
436e5b75505Sopenharmony_ci	}
437e5b75505Sopenharmony_ci
438e5b75505Sopenharmony_ci	if (pk->rsa.type != PK_PUBLIC) {
439e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of "
440e5b75505Sopenharmony_ci			   "correct type");
441e5b75505Sopenharmony_ci		rsa_free(&pk->rsa);
442e5b75505Sopenharmony_ci		os_free(pk);
443e5b75505Sopenharmony_ci		return NULL;
444e5b75505Sopenharmony_ci	}
445e5b75505Sopenharmony_ci
446e5b75505Sopenharmony_ci	return pk;
447e5b75505Sopenharmony_ci}
448e5b75505Sopenharmony_ci
449e5b75505Sopenharmony_ci
450e5b75505Sopenharmony_cistruct crypto_private_key * crypto_private_key_import(const u8 *key,
451e5b75505Sopenharmony_ci						      size_t len,
452e5b75505Sopenharmony_ci						      const char *passwd)
453e5b75505Sopenharmony_ci{
454e5b75505Sopenharmony_ci	int res;
455e5b75505Sopenharmony_ci	struct crypto_private_key *pk;
456e5b75505Sopenharmony_ci
457e5b75505Sopenharmony_ci	pk = os_zalloc(sizeof(*pk));
458e5b75505Sopenharmony_ci	if (pk == NULL)
459e5b75505Sopenharmony_ci		return NULL;
460e5b75505Sopenharmony_ci
461e5b75505Sopenharmony_ci	res = rsa_import(key, len, &pk->rsa);
462e5b75505Sopenharmony_ci	if (res != CRYPT_OK) {
463e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
464e5b75505Sopenharmony_ci			   "private key (res=%d '%s')",
465e5b75505Sopenharmony_ci			   res, error_to_string(res));
466e5b75505Sopenharmony_ci		os_free(pk);
467e5b75505Sopenharmony_ci		return NULL;
468e5b75505Sopenharmony_ci	}
469e5b75505Sopenharmony_ci
470e5b75505Sopenharmony_ci	if (pk->rsa.type != PK_PRIVATE) {
471e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of "
472e5b75505Sopenharmony_ci			   "correct type");
473e5b75505Sopenharmony_ci		rsa_free(&pk->rsa);
474e5b75505Sopenharmony_ci		os_free(pk);
475e5b75505Sopenharmony_ci		return NULL;
476e5b75505Sopenharmony_ci	}
477e5b75505Sopenharmony_ci
478e5b75505Sopenharmony_ci	return pk;
479e5b75505Sopenharmony_ci}
480e5b75505Sopenharmony_ci
481e5b75505Sopenharmony_ci
482e5b75505Sopenharmony_cistruct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
483e5b75505Sopenharmony_ci						       size_t len)
484e5b75505Sopenharmony_ci{
485e5b75505Sopenharmony_ci	/* No X.509 support in LibTomCrypt */
486e5b75505Sopenharmony_ci	return NULL;
487e5b75505Sopenharmony_ci}
488e5b75505Sopenharmony_ci
489e5b75505Sopenharmony_ci
490e5b75505Sopenharmony_cistatic int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
491e5b75505Sopenharmony_ci					   const u8 *in, size_t inlen,
492e5b75505Sopenharmony_ci					   u8 *out, size_t *outlen)
493e5b75505Sopenharmony_ci{
494e5b75505Sopenharmony_ci	size_t ps_len;
495e5b75505Sopenharmony_ci	u8 *pos;
496e5b75505Sopenharmony_ci
497e5b75505Sopenharmony_ci	/*
498e5b75505Sopenharmony_ci	 * PKCS #1 v1.5, 8.1:
499e5b75505Sopenharmony_ci	 *
500e5b75505Sopenharmony_ci	 * EB = 00 || BT || PS || 00 || D
501e5b75505Sopenharmony_ci	 * BT = 00 or 01 for private-key operation; 02 for public-key operation
502e5b75505Sopenharmony_ci	 * PS = k-3-||D||; at least eight octets
503e5b75505Sopenharmony_ci	 * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
504e5b75505Sopenharmony_ci	 * k = length of modulus in octets (modlen)
505e5b75505Sopenharmony_ci	 */
506e5b75505Sopenharmony_ci
507e5b75505Sopenharmony_ci	if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
508e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
509e5b75505Sopenharmony_ci			   "lengths (modlen=%lu outlen=%lu inlen=%lu)",
510e5b75505Sopenharmony_ci			   __func__, (unsigned long) modlen,
511e5b75505Sopenharmony_ci			   (unsigned long) *outlen,
512e5b75505Sopenharmony_ci			   (unsigned long) inlen);
513e5b75505Sopenharmony_ci		return -1;
514e5b75505Sopenharmony_ci	}
515e5b75505Sopenharmony_ci
516e5b75505Sopenharmony_ci	pos = out;
517e5b75505Sopenharmony_ci	*pos++ = 0x00;
518e5b75505Sopenharmony_ci	*pos++ = block_type; /* BT */
519e5b75505Sopenharmony_ci	ps_len = modlen - inlen - 3;
520e5b75505Sopenharmony_ci	switch (block_type) {
521e5b75505Sopenharmony_ci	case 0:
522e5b75505Sopenharmony_ci		os_memset(pos, 0x00, ps_len);
523e5b75505Sopenharmony_ci		pos += ps_len;
524e5b75505Sopenharmony_ci		break;
525e5b75505Sopenharmony_ci	case 1:
526e5b75505Sopenharmony_ci		os_memset(pos, 0xff, ps_len);
527e5b75505Sopenharmony_ci		pos += ps_len;
528e5b75505Sopenharmony_ci		break;
529e5b75505Sopenharmony_ci	case 2:
530e5b75505Sopenharmony_ci		if (os_get_random(pos, ps_len) < 0) {
531e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
532e5b75505Sopenharmony_ci				   "random data for PS", __func__);
533e5b75505Sopenharmony_ci			return -1;
534e5b75505Sopenharmony_ci		}
535e5b75505Sopenharmony_ci		while (ps_len--) {
536e5b75505Sopenharmony_ci			if (*pos == 0x00)
537e5b75505Sopenharmony_ci				*pos = 0x01;
538e5b75505Sopenharmony_ci			pos++;
539e5b75505Sopenharmony_ci		}
540e5b75505Sopenharmony_ci		break;
541e5b75505Sopenharmony_ci	default:
542e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
543e5b75505Sopenharmony_ci			   "%d", __func__, block_type);
544e5b75505Sopenharmony_ci		return -1;
545e5b75505Sopenharmony_ci	}
546e5b75505Sopenharmony_ci	*pos++ = 0x00;
547e5b75505Sopenharmony_ci	os_memcpy(pos, in, inlen); /* D */
548e5b75505Sopenharmony_ci
549e5b75505Sopenharmony_ci	return 0;
550e5b75505Sopenharmony_ci}
551e5b75505Sopenharmony_ci
552e5b75505Sopenharmony_ci
553e5b75505Sopenharmony_cistatic int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type,
554e5b75505Sopenharmony_ci				    const u8 *in, size_t inlen,
555e5b75505Sopenharmony_ci				    u8 *out, size_t *outlen)
556e5b75505Sopenharmony_ci{
557e5b75505Sopenharmony_ci	unsigned long len, modlen;
558e5b75505Sopenharmony_ci	int res;
559e5b75505Sopenharmony_ci
560e5b75505Sopenharmony_ci	modlen = mp_unsigned_bin_size(key->N);
561e5b75505Sopenharmony_ci
562e5b75505Sopenharmony_ci	if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
563e5b75505Sopenharmony_ci					    out, outlen) < 0)
564e5b75505Sopenharmony_ci		return -1;
565e5b75505Sopenharmony_ci
566e5b75505Sopenharmony_ci	len = *outlen;
567e5b75505Sopenharmony_ci	res = rsa_exptmod(out, modlen, out, &len, key_type, key);
568e5b75505Sopenharmony_ci	if (res != CRYPT_OK) {
569e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
570e5b75505Sopenharmony_ci			   error_to_string(res));
571e5b75505Sopenharmony_ci		return -1;
572e5b75505Sopenharmony_ci	}
573e5b75505Sopenharmony_ci	*outlen = len;
574e5b75505Sopenharmony_ci
575e5b75505Sopenharmony_ci	return 0;
576e5b75505Sopenharmony_ci}
577e5b75505Sopenharmony_ci
578e5b75505Sopenharmony_ci
579e5b75505Sopenharmony_ciint crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
580e5b75505Sopenharmony_ci					const u8 *in, size_t inlen,
581e5b75505Sopenharmony_ci					u8 *out, size_t *outlen)
582e5b75505Sopenharmony_ci{
583e5b75505Sopenharmony_ci	return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen,
584e5b75505Sopenharmony_ci					out, outlen);
585e5b75505Sopenharmony_ci}
586e5b75505Sopenharmony_ci
587e5b75505Sopenharmony_ci
588e5b75505Sopenharmony_ciint crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
589e5b75505Sopenharmony_ci				  const u8 *in, size_t inlen,
590e5b75505Sopenharmony_ci				  u8 *out, size_t *outlen)
591e5b75505Sopenharmony_ci{
592e5b75505Sopenharmony_ci	return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen,
593e5b75505Sopenharmony_ci					out, outlen);
594e5b75505Sopenharmony_ci}
595e5b75505Sopenharmony_ci
596e5b75505Sopenharmony_ci
597e5b75505Sopenharmony_civoid crypto_public_key_free(struct crypto_public_key *key)
598e5b75505Sopenharmony_ci{
599e5b75505Sopenharmony_ci	if (key) {
600e5b75505Sopenharmony_ci		rsa_free(&key->rsa);
601e5b75505Sopenharmony_ci		os_free(key);
602e5b75505Sopenharmony_ci	}
603e5b75505Sopenharmony_ci}
604e5b75505Sopenharmony_ci
605e5b75505Sopenharmony_ci
606e5b75505Sopenharmony_civoid crypto_private_key_free(struct crypto_private_key *key)
607e5b75505Sopenharmony_ci{
608e5b75505Sopenharmony_ci	if (key) {
609e5b75505Sopenharmony_ci		rsa_free(&key->rsa);
610e5b75505Sopenharmony_ci		os_free(key);
611e5b75505Sopenharmony_ci	}
612e5b75505Sopenharmony_ci}
613e5b75505Sopenharmony_ci
614e5b75505Sopenharmony_ci
615e5b75505Sopenharmony_ciint crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
616e5b75505Sopenharmony_ci				    const u8 *crypt, size_t crypt_len,
617e5b75505Sopenharmony_ci				    u8 *plain, size_t *plain_len)
618e5b75505Sopenharmony_ci{
619e5b75505Sopenharmony_ci	int res;
620e5b75505Sopenharmony_ci	unsigned long len;
621e5b75505Sopenharmony_ci	u8 *pos;
622e5b75505Sopenharmony_ci
623e5b75505Sopenharmony_ci	len = *plain_len;
624e5b75505Sopenharmony_ci	res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC,
625e5b75505Sopenharmony_ci			  &key->rsa);
626e5b75505Sopenharmony_ci	if (res != CRYPT_OK) {
627e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
628e5b75505Sopenharmony_ci			   error_to_string(res));
629e5b75505Sopenharmony_ci		return -1;
630e5b75505Sopenharmony_ci	}
631e5b75505Sopenharmony_ci
632e5b75505Sopenharmony_ci	/*
633e5b75505Sopenharmony_ci	 * PKCS #1 v1.5, 8.1:
634e5b75505Sopenharmony_ci	 *
635e5b75505Sopenharmony_ci	 * EB = 00 || BT || PS || 00 || D
636e5b75505Sopenharmony_ci	 * BT = 01
637e5b75505Sopenharmony_ci	 * PS = k-3-||D|| times FF
638e5b75505Sopenharmony_ci	 * k = length of modulus in octets
639e5b75505Sopenharmony_ci	 */
640e5b75505Sopenharmony_ci
641e5b75505Sopenharmony_ci	if (len < 3 + 8 + 16 /* min hash len */ ||
642e5b75505Sopenharmony_ci	    plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
643e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
644e5b75505Sopenharmony_ci			   "structure");
645e5b75505Sopenharmony_ci		return -1;
646e5b75505Sopenharmony_ci	}
647e5b75505Sopenharmony_ci
648e5b75505Sopenharmony_ci	pos = plain + 3;
649e5b75505Sopenharmony_ci	while (pos < plain + len && *pos == 0xff)
650e5b75505Sopenharmony_ci		pos++;
651e5b75505Sopenharmony_ci	if (pos - plain - 2 < 8) {
652e5b75505Sopenharmony_ci		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
653e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
654e5b75505Sopenharmony_ci			   "padding");
655e5b75505Sopenharmony_ci		return -1;
656e5b75505Sopenharmony_ci	}
657e5b75505Sopenharmony_ci
658e5b75505Sopenharmony_ci	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
659e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
660e5b75505Sopenharmony_ci			   "structure (2)");
661e5b75505Sopenharmony_ci		return -1;
662e5b75505Sopenharmony_ci	}
663e5b75505Sopenharmony_ci	pos++;
664e5b75505Sopenharmony_ci	len -= pos - plain;
665e5b75505Sopenharmony_ci
666e5b75505Sopenharmony_ci	/* Strip PKCS #1 header */
667e5b75505Sopenharmony_ci	os_memmove(plain, pos, len);
668e5b75505Sopenharmony_ci	*plain_len = len;
669e5b75505Sopenharmony_ci
670e5b75505Sopenharmony_ci	return 0;
671e5b75505Sopenharmony_ci}
672e5b75505Sopenharmony_ci
673e5b75505Sopenharmony_ci
674e5b75505Sopenharmony_ciint crypto_global_init(void)
675e5b75505Sopenharmony_ci{
676e5b75505Sopenharmony_ci	ltc_mp = tfm_desc;
677e5b75505Sopenharmony_ci	/* TODO: only register algorithms that are really needed */
678e5b75505Sopenharmony_ci	if (register_hash(&md4_desc) < 0 ||
679e5b75505Sopenharmony_ci	    register_hash(&md5_desc) < 0 ||
680e5b75505Sopenharmony_ci	    register_hash(&sha1_desc) < 0 ||
681e5b75505Sopenharmony_ci	    register_cipher(&aes_desc) < 0 ||
682e5b75505Sopenharmony_ci	    register_cipher(&des_desc) < 0 ||
683e5b75505Sopenharmony_ci	    register_cipher(&des3_desc) < 0) {
684e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TLSv1: Failed to register "
685e5b75505Sopenharmony_ci			   "hash/cipher functions");
686e5b75505Sopenharmony_ci		return -1;
687e5b75505Sopenharmony_ci	}
688e5b75505Sopenharmony_ci
689e5b75505Sopenharmony_ci	return 0;
690e5b75505Sopenharmony_ci}
691e5b75505Sopenharmony_ci
692e5b75505Sopenharmony_ci
693e5b75505Sopenharmony_civoid crypto_global_deinit(void)
694e5b75505Sopenharmony_ci{
695e5b75505Sopenharmony_ci}
696e5b75505Sopenharmony_ci
697e5b75505Sopenharmony_ci
698e5b75505Sopenharmony_ci#ifdef CONFIG_MODEXP
699e5b75505Sopenharmony_ci
700e5b75505Sopenharmony_ciint crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
701e5b75505Sopenharmony_ci		   u8 *pubkey)
702e5b75505Sopenharmony_ci{
703e5b75505Sopenharmony_ci	size_t pubkey_len, pad;
704e5b75505Sopenharmony_ci
705e5b75505Sopenharmony_ci	if (os_get_random(privkey, prime_len) < 0)
706e5b75505Sopenharmony_ci		return -1;
707e5b75505Sopenharmony_ci	if (os_memcmp(privkey, prime, prime_len) > 0) {
708e5b75505Sopenharmony_ci		/* Make sure private value is smaller than prime */
709e5b75505Sopenharmony_ci		privkey[0] = 0;
710e5b75505Sopenharmony_ci	}
711e5b75505Sopenharmony_ci
712e5b75505Sopenharmony_ci	pubkey_len = prime_len;
713e5b75505Sopenharmony_ci	if (crypto_mod_exp(&generator, 1, privkey, prime_len, prime, prime_len,
714e5b75505Sopenharmony_ci			   pubkey, &pubkey_len) < 0)
715e5b75505Sopenharmony_ci		return -1;
716e5b75505Sopenharmony_ci	if (pubkey_len < prime_len) {
717e5b75505Sopenharmony_ci		pad = prime_len - pubkey_len;
718e5b75505Sopenharmony_ci		os_memmove(pubkey + pad, pubkey, pubkey_len);
719e5b75505Sopenharmony_ci		os_memset(pubkey, 0, pad);
720e5b75505Sopenharmony_ci	}
721e5b75505Sopenharmony_ci
722e5b75505Sopenharmony_ci	return 0;
723e5b75505Sopenharmony_ci}
724e5b75505Sopenharmony_ci
725e5b75505Sopenharmony_ci
726e5b75505Sopenharmony_ciint crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
727e5b75505Sopenharmony_ci			    const u8 *order, size_t order_len,
728e5b75505Sopenharmony_ci			    const u8 *privkey, size_t privkey_len,
729e5b75505Sopenharmony_ci			    const u8 *pubkey, size_t pubkey_len,
730e5b75505Sopenharmony_ci			    u8 *secret, size_t *len)
731e5b75505Sopenharmony_ci{
732e5b75505Sopenharmony_ci	/* TODO: check pubkey */
733e5b75505Sopenharmony_ci	return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
734e5b75505Sopenharmony_ci			      prime, prime_len, secret, len);
735e5b75505Sopenharmony_ci}
736e5b75505Sopenharmony_ci
737e5b75505Sopenharmony_ci
738e5b75505Sopenharmony_ciint crypto_mod_exp(const u8 *base, size_t base_len,
739e5b75505Sopenharmony_ci		   const u8 *power, size_t power_len,
740e5b75505Sopenharmony_ci		   const u8 *modulus, size_t modulus_len,
741e5b75505Sopenharmony_ci		   u8 *result, size_t *result_len)
742e5b75505Sopenharmony_ci{
743e5b75505Sopenharmony_ci	void *b, *p, *m, *r;
744e5b75505Sopenharmony_ci
745e5b75505Sopenharmony_ci	if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK)
746e5b75505Sopenharmony_ci		return -1;
747e5b75505Sopenharmony_ci
748e5b75505Sopenharmony_ci	if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK ||
749e5b75505Sopenharmony_ci	    mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK ||
750e5b75505Sopenharmony_ci	    mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK)
751e5b75505Sopenharmony_ci		goto fail;
752e5b75505Sopenharmony_ci
753e5b75505Sopenharmony_ci	if (mp_exptmod(b, p, m, r) != CRYPT_OK)
754e5b75505Sopenharmony_ci		goto fail;
755e5b75505Sopenharmony_ci
756e5b75505Sopenharmony_ci	*result_len = mp_unsigned_bin_size(r);
757e5b75505Sopenharmony_ci	if (mp_to_unsigned_bin(r, result) != CRYPT_OK)
758e5b75505Sopenharmony_ci		goto fail;
759e5b75505Sopenharmony_ci
760e5b75505Sopenharmony_ci	mp_clear_multi(b, p, m, r, NULL);
761e5b75505Sopenharmony_ci	return 0;
762e5b75505Sopenharmony_ci
763e5b75505Sopenharmony_cifail:
764e5b75505Sopenharmony_ci	mp_clear_multi(b, p, m, r, NULL);
765e5b75505Sopenharmony_ci	return -1;
766e5b75505Sopenharmony_ci}
767e5b75505Sopenharmony_ci
768e5b75505Sopenharmony_ci#endif /* CONFIG_MODEXP */
769