1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * Crypto wrapper for internal crypto implementation
3e5b75505Sopenharmony_ci * Copyright (c) 2006-2011, 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
11e5b75505Sopenharmony_ci#include "common.h"
12e5b75505Sopenharmony_ci#include "crypto.h"
13e5b75505Sopenharmony_ci#include "sha256_i.h"
14e5b75505Sopenharmony_ci#include "sha384_i.h"
15e5b75505Sopenharmony_ci#include "sha512_i.h"
16e5b75505Sopenharmony_ci#include "sha1_i.h"
17e5b75505Sopenharmony_ci#include "md5_i.h"
18e5b75505Sopenharmony_ci
19e5b75505Sopenharmony_cistruct crypto_hash {
20e5b75505Sopenharmony_ci	enum crypto_hash_alg alg;
21e5b75505Sopenharmony_ci	union {
22e5b75505Sopenharmony_ci		struct MD5Context md5;
23e5b75505Sopenharmony_ci		struct SHA1Context sha1;
24e5b75505Sopenharmony_ci#ifdef CONFIG_SHA256
25e5b75505Sopenharmony_ci		struct sha256_state sha256;
26e5b75505Sopenharmony_ci#endif /* CONFIG_SHA256 */
27e5b75505Sopenharmony_ci#ifdef CONFIG_INTERNAL_SHA384
28e5b75505Sopenharmony_ci		struct sha384_state sha384;
29e5b75505Sopenharmony_ci#endif /* CONFIG_INTERNAL_SHA384 */
30e5b75505Sopenharmony_ci#ifdef CONFIG_INTERNAL_SHA512
31e5b75505Sopenharmony_ci		struct sha512_state sha512;
32e5b75505Sopenharmony_ci#endif /* CONFIG_INTERNAL_SHA512 */
33e5b75505Sopenharmony_ci	} u;
34e5b75505Sopenharmony_ci	u8 key[64];
35e5b75505Sopenharmony_ci	size_t key_len;
36e5b75505Sopenharmony_ci};
37e5b75505Sopenharmony_ci
38e5b75505Sopenharmony_ci
39e5b75505Sopenharmony_cistruct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
40e5b75505Sopenharmony_ci				      size_t key_len)
41e5b75505Sopenharmony_ci{
42e5b75505Sopenharmony_ci	struct crypto_hash *ctx;
43e5b75505Sopenharmony_ci	u8 k_pad[64];
44e5b75505Sopenharmony_ci	u8 tk[32];
45e5b75505Sopenharmony_ci	size_t i;
46e5b75505Sopenharmony_ci
47e5b75505Sopenharmony_ci	ctx = os_zalloc(sizeof(*ctx));
48e5b75505Sopenharmony_ci	if (ctx == NULL)
49e5b75505Sopenharmony_ci		return NULL;
50e5b75505Sopenharmony_ci
51e5b75505Sopenharmony_ci	ctx->alg = alg;
52e5b75505Sopenharmony_ci
53e5b75505Sopenharmony_ci	switch (alg) {
54e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_MD5:
55e5b75505Sopenharmony_ci		MD5Init(&ctx->u.md5);
56e5b75505Sopenharmony_ci		break;
57e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA1:
58e5b75505Sopenharmony_ci		SHA1Init(&ctx->u.sha1);
59e5b75505Sopenharmony_ci		break;
60e5b75505Sopenharmony_ci#ifdef CONFIG_SHA256
61e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA256:
62e5b75505Sopenharmony_ci		sha256_init(&ctx->u.sha256);
63e5b75505Sopenharmony_ci		break;
64e5b75505Sopenharmony_ci#endif /* CONFIG_SHA256 */
65e5b75505Sopenharmony_ci#ifdef CONFIG_INTERNAL_SHA384
66e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA384:
67e5b75505Sopenharmony_ci		sha384_init(&ctx->u.sha384);
68e5b75505Sopenharmony_ci		break;
69e5b75505Sopenharmony_ci#endif /* CONFIG_INTERNAL_SHA384 */
70e5b75505Sopenharmony_ci#ifdef CONFIG_INTERNAL_SHA512
71e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA512:
72e5b75505Sopenharmony_ci		sha512_init(&ctx->u.sha512);
73e5b75505Sopenharmony_ci		break;
74e5b75505Sopenharmony_ci#endif /* CONFIG_INTERNAL_SHA512 */
75e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_MD5:
76e5b75505Sopenharmony_ci		if (key_len > sizeof(k_pad)) {
77e5b75505Sopenharmony_ci			MD5Init(&ctx->u.md5);
78e5b75505Sopenharmony_ci			MD5Update(&ctx->u.md5, key, key_len);
79e5b75505Sopenharmony_ci			MD5Final(tk, &ctx->u.md5);
80e5b75505Sopenharmony_ci			key = tk;
81e5b75505Sopenharmony_ci			key_len = 16;
82e5b75505Sopenharmony_ci		}
83e5b75505Sopenharmony_ci		os_memcpy(ctx->key, key, key_len);
84e5b75505Sopenharmony_ci		ctx->key_len = key_len;
85e5b75505Sopenharmony_ci
86e5b75505Sopenharmony_ci		os_memcpy(k_pad, key, key_len);
87e5b75505Sopenharmony_ci		if (key_len < sizeof(k_pad))
88e5b75505Sopenharmony_ci			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
89e5b75505Sopenharmony_ci		for (i = 0; i < sizeof(k_pad); i++)
90e5b75505Sopenharmony_ci			k_pad[i] ^= 0x36;
91e5b75505Sopenharmony_ci		MD5Init(&ctx->u.md5);
92e5b75505Sopenharmony_ci		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
93e5b75505Sopenharmony_ci		break;
94e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_SHA1:
95e5b75505Sopenharmony_ci		if (key_len > sizeof(k_pad)) {
96e5b75505Sopenharmony_ci			SHA1Init(&ctx->u.sha1);
97e5b75505Sopenharmony_ci			SHA1Update(&ctx->u.sha1, key, key_len);
98e5b75505Sopenharmony_ci			SHA1Final(tk, &ctx->u.sha1);
99e5b75505Sopenharmony_ci			key = tk;
100e5b75505Sopenharmony_ci			key_len = 20;
101e5b75505Sopenharmony_ci		}
102e5b75505Sopenharmony_ci		os_memcpy(ctx->key, key, key_len);
103e5b75505Sopenharmony_ci		ctx->key_len = key_len;
104e5b75505Sopenharmony_ci
105e5b75505Sopenharmony_ci		os_memcpy(k_pad, key, key_len);
106e5b75505Sopenharmony_ci		if (key_len < sizeof(k_pad))
107e5b75505Sopenharmony_ci			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
108e5b75505Sopenharmony_ci		for (i = 0; i < sizeof(k_pad); i++)
109e5b75505Sopenharmony_ci			k_pad[i] ^= 0x36;
110e5b75505Sopenharmony_ci		SHA1Init(&ctx->u.sha1);
111e5b75505Sopenharmony_ci		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
112e5b75505Sopenharmony_ci		break;
113e5b75505Sopenharmony_ci#ifdef CONFIG_SHA256
114e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_SHA256:
115e5b75505Sopenharmony_ci		if (key_len > sizeof(k_pad)) {
116e5b75505Sopenharmony_ci			sha256_init(&ctx->u.sha256);
117e5b75505Sopenharmony_ci			sha256_process(&ctx->u.sha256, key, key_len);
118e5b75505Sopenharmony_ci			sha256_done(&ctx->u.sha256, tk);
119e5b75505Sopenharmony_ci			key = tk;
120e5b75505Sopenharmony_ci			key_len = 32;
121e5b75505Sopenharmony_ci		}
122e5b75505Sopenharmony_ci		os_memcpy(ctx->key, key, key_len);
123e5b75505Sopenharmony_ci		ctx->key_len = key_len;
124e5b75505Sopenharmony_ci
125e5b75505Sopenharmony_ci		os_memcpy(k_pad, key, key_len);
126e5b75505Sopenharmony_ci		if (key_len < sizeof(k_pad))
127e5b75505Sopenharmony_ci			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
128e5b75505Sopenharmony_ci		for (i = 0; i < sizeof(k_pad); i++)
129e5b75505Sopenharmony_ci			k_pad[i] ^= 0x36;
130e5b75505Sopenharmony_ci		sha256_init(&ctx->u.sha256);
131e5b75505Sopenharmony_ci		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
132e5b75505Sopenharmony_ci		break;
133e5b75505Sopenharmony_ci#endif /* CONFIG_SHA256 */
134e5b75505Sopenharmony_ci	default:
135e5b75505Sopenharmony_ci		os_free(ctx);
136e5b75505Sopenharmony_ci		return NULL;
137e5b75505Sopenharmony_ci	}
138e5b75505Sopenharmony_ci
139e5b75505Sopenharmony_ci	return ctx;
140e5b75505Sopenharmony_ci}
141e5b75505Sopenharmony_ci
142e5b75505Sopenharmony_ci
143e5b75505Sopenharmony_civoid crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
144e5b75505Sopenharmony_ci{
145e5b75505Sopenharmony_ci	if (ctx == NULL)
146e5b75505Sopenharmony_ci		return;
147e5b75505Sopenharmony_ci
148e5b75505Sopenharmony_ci	switch (ctx->alg) {
149e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_MD5:
150e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_MD5:
151e5b75505Sopenharmony_ci		MD5Update(&ctx->u.md5, data, len);
152e5b75505Sopenharmony_ci		break;
153e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA1:
154e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_SHA1:
155e5b75505Sopenharmony_ci		SHA1Update(&ctx->u.sha1, data, len);
156e5b75505Sopenharmony_ci		break;
157e5b75505Sopenharmony_ci#ifdef CONFIG_SHA256
158e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA256:
159e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_SHA256:
160e5b75505Sopenharmony_ci		sha256_process(&ctx->u.sha256, data, len);
161e5b75505Sopenharmony_ci		break;
162e5b75505Sopenharmony_ci#endif /* CONFIG_SHA256 */
163e5b75505Sopenharmony_ci#ifdef CONFIG_INTERNAL_SHA384
164e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA384:
165e5b75505Sopenharmony_ci		sha384_process(&ctx->u.sha384, data, len);
166e5b75505Sopenharmony_ci		break;
167e5b75505Sopenharmony_ci#endif /* CONFIG_INTERNAL_SHA384 */
168e5b75505Sopenharmony_ci#ifdef CONFIG_INTERNAL_SHA512
169e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA512:
170e5b75505Sopenharmony_ci		sha512_process(&ctx->u.sha512, data, len);
171e5b75505Sopenharmony_ci		break;
172e5b75505Sopenharmony_ci#endif /* CONFIG_INTERNAL_SHA512 */
173e5b75505Sopenharmony_ci	default:
174e5b75505Sopenharmony_ci		break;
175e5b75505Sopenharmony_ci	}
176e5b75505Sopenharmony_ci}
177e5b75505Sopenharmony_ci
178e5b75505Sopenharmony_ci
179e5b75505Sopenharmony_ciint crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
180e5b75505Sopenharmony_ci{
181e5b75505Sopenharmony_ci	u8 k_pad[64];
182e5b75505Sopenharmony_ci	size_t i;
183e5b75505Sopenharmony_ci
184e5b75505Sopenharmony_ci	if (ctx == NULL)
185e5b75505Sopenharmony_ci		return -2;
186e5b75505Sopenharmony_ci
187e5b75505Sopenharmony_ci	if (mac == NULL || len == NULL) {
188e5b75505Sopenharmony_ci		os_free(ctx);
189e5b75505Sopenharmony_ci		return 0;
190e5b75505Sopenharmony_ci	}
191e5b75505Sopenharmony_ci
192e5b75505Sopenharmony_ci	switch (ctx->alg) {
193e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_MD5:
194e5b75505Sopenharmony_ci		if (*len < 16) {
195e5b75505Sopenharmony_ci			*len = 16;
196e5b75505Sopenharmony_ci			os_free(ctx);
197e5b75505Sopenharmony_ci			return -1;
198e5b75505Sopenharmony_ci		}
199e5b75505Sopenharmony_ci		*len = 16;
200e5b75505Sopenharmony_ci		MD5Final(mac, &ctx->u.md5);
201e5b75505Sopenharmony_ci		break;
202e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA1:
203e5b75505Sopenharmony_ci		if (*len < 20) {
204e5b75505Sopenharmony_ci			*len = 20;
205e5b75505Sopenharmony_ci			os_free(ctx);
206e5b75505Sopenharmony_ci			return -1;
207e5b75505Sopenharmony_ci		}
208e5b75505Sopenharmony_ci		*len = 20;
209e5b75505Sopenharmony_ci		SHA1Final(mac, &ctx->u.sha1);
210e5b75505Sopenharmony_ci		break;
211e5b75505Sopenharmony_ci#ifdef CONFIG_SHA256
212e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA256:
213e5b75505Sopenharmony_ci		if (*len < 32) {
214e5b75505Sopenharmony_ci			*len = 32;
215e5b75505Sopenharmony_ci			os_free(ctx);
216e5b75505Sopenharmony_ci			return -1;
217e5b75505Sopenharmony_ci		}
218e5b75505Sopenharmony_ci		*len = 32;
219e5b75505Sopenharmony_ci		sha256_done(&ctx->u.sha256, mac);
220e5b75505Sopenharmony_ci		break;
221e5b75505Sopenharmony_ci#endif /* CONFIG_SHA256 */
222e5b75505Sopenharmony_ci#ifdef CONFIG_INTERNAL_SHA384
223e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA384:
224e5b75505Sopenharmony_ci		if (*len < 48) {
225e5b75505Sopenharmony_ci			*len = 48;
226e5b75505Sopenharmony_ci			os_free(ctx);
227e5b75505Sopenharmony_ci			return -1;
228e5b75505Sopenharmony_ci		}
229e5b75505Sopenharmony_ci		*len = 48;
230e5b75505Sopenharmony_ci		sha384_done(&ctx->u.sha384, mac);
231e5b75505Sopenharmony_ci		break;
232e5b75505Sopenharmony_ci#endif /* CONFIG_INTERNAL_SHA384 */
233e5b75505Sopenharmony_ci#ifdef CONFIG_INTERNAL_SHA512
234e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_SHA512:
235e5b75505Sopenharmony_ci		if (*len < 64) {
236e5b75505Sopenharmony_ci			*len = 64;
237e5b75505Sopenharmony_ci			os_free(ctx);
238e5b75505Sopenharmony_ci			return -1;
239e5b75505Sopenharmony_ci		}
240e5b75505Sopenharmony_ci		*len = 64;
241e5b75505Sopenharmony_ci		sha512_done(&ctx->u.sha512, mac);
242e5b75505Sopenharmony_ci		break;
243e5b75505Sopenharmony_ci#endif /* CONFIG_INTERNAL_SHA512 */
244e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_MD5:
245e5b75505Sopenharmony_ci		if (*len < 16) {
246e5b75505Sopenharmony_ci			*len = 16;
247e5b75505Sopenharmony_ci			os_free(ctx);
248e5b75505Sopenharmony_ci			return -1;
249e5b75505Sopenharmony_ci		}
250e5b75505Sopenharmony_ci		*len = 16;
251e5b75505Sopenharmony_ci
252e5b75505Sopenharmony_ci		MD5Final(mac, &ctx->u.md5);
253e5b75505Sopenharmony_ci
254e5b75505Sopenharmony_ci		os_memcpy(k_pad, ctx->key, ctx->key_len);
255e5b75505Sopenharmony_ci		os_memset(k_pad + ctx->key_len, 0,
256e5b75505Sopenharmony_ci			  sizeof(k_pad) - ctx->key_len);
257e5b75505Sopenharmony_ci		for (i = 0; i < sizeof(k_pad); i++)
258e5b75505Sopenharmony_ci			k_pad[i] ^= 0x5c;
259e5b75505Sopenharmony_ci		MD5Init(&ctx->u.md5);
260e5b75505Sopenharmony_ci		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
261e5b75505Sopenharmony_ci		MD5Update(&ctx->u.md5, mac, 16);
262e5b75505Sopenharmony_ci		MD5Final(mac, &ctx->u.md5);
263e5b75505Sopenharmony_ci		break;
264e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_SHA1:
265e5b75505Sopenharmony_ci		if (*len < 20) {
266e5b75505Sopenharmony_ci			*len = 20;
267e5b75505Sopenharmony_ci			os_free(ctx);
268e5b75505Sopenharmony_ci			return -1;
269e5b75505Sopenharmony_ci		}
270e5b75505Sopenharmony_ci		*len = 20;
271e5b75505Sopenharmony_ci
272e5b75505Sopenharmony_ci		SHA1Final(mac, &ctx->u.sha1);
273e5b75505Sopenharmony_ci
274e5b75505Sopenharmony_ci		os_memcpy(k_pad, ctx->key, ctx->key_len);
275e5b75505Sopenharmony_ci		os_memset(k_pad + ctx->key_len, 0,
276e5b75505Sopenharmony_ci			  sizeof(k_pad) - ctx->key_len);
277e5b75505Sopenharmony_ci		for (i = 0; i < sizeof(k_pad); i++)
278e5b75505Sopenharmony_ci			k_pad[i] ^= 0x5c;
279e5b75505Sopenharmony_ci		SHA1Init(&ctx->u.sha1);
280e5b75505Sopenharmony_ci		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
281e5b75505Sopenharmony_ci		SHA1Update(&ctx->u.sha1, mac, 20);
282e5b75505Sopenharmony_ci		SHA1Final(mac, &ctx->u.sha1);
283e5b75505Sopenharmony_ci		break;
284e5b75505Sopenharmony_ci#ifdef CONFIG_SHA256
285e5b75505Sopenharmony_ci	case CRYPTO_HASH_ALG_HMAC_SHA256:
286e5b75505Sopenharmony_ci		if (*len < 32) {
287e5b75505Sopenharmony_ci			*len = 32;
288e5b75505Sopenharmony_ci			os_free(ctx);
289e5b75505Sopenharmony_ci			return -1;
290e5b75505Sopenharmony_ci		}
291e5b75505Sopenharmony_ci		*len = 32;
292e5b75505Sopenharmony_ci
293e5b75505Sopenharmony_ci		sha256_done(&ctx->u.sha256, mac);
294e5b75505Sopenharmony_ci
295e5b75505Sopenharmony_ci		os_memcpy(k_pad, ctx->key, ctx->key_len);
296e5b75505Sopenharmony_ci		os_memset(k_pad + ctx->key_len, 0,
297e5b75505Sopenharmony_ci			  sizeof(k_pad) - ctx->key_len);
298e5b75505Sopenharmony_ci		for (i = 0; i < sizeof(k_pad); i++)
299e5b75505Sopenharmony_ci			k_pad[i] ^= 0x5c;
300e5b75505Sopenharmony_ci		sha256_init(&ctx->u.sha256);
301e5b75505Sopenharmony_ci		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
302e5b75505Sopenharmony_ci		sha256_process(&ctx->u.sha256, mac, 32);
303e5b75505Sopenharmony_ci		sha256_done(&ctx->u.sha256, mac);
304e5b75505Sopenharmony_ci		break;
305e5b75505Sopenharmony_ci#endif /* CONFIG_SHA256 */
306e5b75505Sopenharmony_ci	default:
307e5b75505Sopenharmony_ci		os_free(ctx);
308e5b75505Sopenharmony_ci		return -1;
309e5b75505Sopenharmony_ci	}
310e5b75505Sopenharmony_ci
311e5b75505Sopenharmony_ci	os_free(ctx);
312e5b75505Sopenharmony_ci
313e5b75505Sopenharmony_ci	if (TEST_FAIL())
314e5b75505Sopenharmony_ci		return -1;
315e5b75505Sopenharmony_ci
316e5b75505Sopenharmony_ci	return 0;
317e5b75505Sopenharmony_ci}
318e5b75505Sopenharmony_ci
319e5b75505Sopenharmony_ci
320e5b75505Sopenharmony_ciint crypto_global_init(void)
321e5b75505Sopenharmony_ci{
322e5b75505Sopenharmony_ci	return 0;
323e5b75505Sopenharmony_ci}
324e5b75505Sopenharmony_ci
325e5b75505Sopenharmony_ci
326e5b75505Sopenharmony_civoid crypto_global_deinit(void)
327e5b75505Sopenharmony_ci{
328e5b75505Sopenharmony_ci}
329