1/*
2 * Crypto wrapper for internal crypto implementation
3 * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "crypto.h"
13#include "sha256_i.h"
14#include "sha1_i.h"
15#include "md5_i.h"
16
17struct crypto_hash {
18	enum crypto_hash_alg alg;
19	union {
20		struct MD5Context md5;
21		struct SHA1Context sha1;
22#ifdef CONFIG_SHA256
23		struct sha256_state sha256;
24#endif /* CONFIG_SHA256 */
25	} u;
26	u8 key[64];
27	size_t key_len;
28};
29
30
31struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
32				      size_t key_len)
33{
34	struct crypto_hash *ctx;
35	u8 k_pad[64];
36	u8 tk[32];
37	size_t i;
38
39	ctx = os_zalloc(sizeof(*ctx));
40	if (ctx == NULL)
41		return NULL;
42
43	ctx->alg = alg;
44
45	switch (alg) {
46	case CRYPTO_HASH_ALG_MD5:
47		MD5Init(&ctx->u.md5);
48		break;
49	case CRYPTO_HASH_ALG_SHA1:
50		SHA1Init(&ctx->u.sha1);
51		break;
52#ifdef CONFIG_SHA256
53	case CRYPTO_HASH_ALG_SHA256:
54		sha256_init(&ctx->u.sha256);
55		break;
56#endif /* CONFIG_SHA256 */
57	case CRYPTO_HASH_ALG_HMAC_MD5:
58		if (key_len > sizeof(k_pad)) {
59			MD5Init(&ctx->u.md5);
60			MD5Update(&ctx->u.md5, key, key_len);
61			MD5Final(tk, &ctx->u.md5);
62			key = tk;
63			key_len = 16;
64		}
65		os_memcpy(ctx->key, key, key_len);
66		ctx->key_len = key_len;
67
68		os_memcpy(k_pad, key, key_len);
69		if (key_len < sizeof(k_pad))
70			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
71		for (i = 0; i < sizeof(k_pad); i++)
72			k_pad[i] ^= 0x36;
73		MD5Init(&ctx->u.md5);
74		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
75		break;
76	case CRYPTO_HASH_ALG_HMAC_SHA1:
77		if (key_len > sizeof(k_pad)) {
78			SHA1Init(&ctx->u.sha1);
79			SHA1Update(&ctx->u.sha1, key, key_len);
80			SHA1Final(tk, &ctx->u.sha1);
81			key = tk;
82			key_len = 20;
83		}
84		os_memcpy(ctx->key, key, key_len);
85		ctx->key_len = key_len;
86
87		os_memcpy(k_pad, key, key_len);
88		if (key_len < sizeof(k_pad))
89			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
90		for (i = 0; i < sizeof(k_pad); i++)
91			k_pad[i] ^= 0x36;
92		SHA1Init(&ctx->u.sha1);
93		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
94		break;
95#ifdef CONFIG_SHA256
96	case CRYPTO_HASH_ALG_HMAC_SHA256:
97		if (key_len > sizeof(k_pad)) {
98			sha256_init(&ctx->u.sha256);
99			sha256_process(&ctx->u.sha256, key, key_len);
100			sha256_done(&ctx->u.sha256, tk);
101			key = tk;
102			key_len = 32;
103		}
104		os_memcpy(ctx->key, key, key_len);
105		ctx->key_len = key_len;
106
107		os_memcpy(k_pad, key, key_len);
108		if (key_len < sizeof(k_pad))
109			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
110		for (i = 0; i < sizeof(k_pad); i++)
111			k_pad[i] ^= 0x36;
112		sha256_init(&ctx->u.sha256);
113		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
114		break;
115#endif /* CONFIG_SHA256 */
116	default:
117		os_free(ctx);
118		return NULL;
119	}
120
121	return ctx;
122}
123
124
125void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
126{
127	if (ctx == NULL)
128		return;
129
130	switch (ctx->alg) {
131	case CRYPTO_HASH_ALG_MD5:
132	case CRYPTO_HASH_ALG_HMAC_MD5:
133		MD5Update(&ctx->u.md5, data, len);
134		break;
135	case CRYPTO_HASH_ALG_SHA1:
136	case CRYPTO_HASH_ALG_HMAC_SHA1:
137		SHA1Update(&ctx->u.sha1, data, len);
138		break;
139#ifdef CONFIG_SHA256
140	case CRYPTO_HASH_ALG_SHA256:
141	case CRYPTO_HASH_ALG_HMAC_SHA256:
142		sha256_process(&ctx->u.sha256, data, len);
143		break;
144#endif /* CONFIG_SHA256 */
145	default:
146		break;
147	}
148}
149
150
151int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
152{
153	u8 k_pad[64];
154	size_t i;
155
156	if (ctx == NULL)
157		return -2;
158
159	if (mac == NULL || len == NULL) {
160		os_free(ctx);
161		return 0;
162	}
163
164	switch (ctx->alg) {
165	case CRYPTO_HASH_ALG_MD5:
166		if (*len < 16) {
167			*len = 16;
168			os_free(ctx);
169			return -1;
170		}
171		*len = 16;
172		MD5Final(mac, &ctx->u.md5);
173		break;
174	case CRYPTO_HASH_ALG_SHA1:
175		if (*len < 20) {
176			*len = 20;
177			os_free(ctx);
178			return -1;
179		}
180		*len = 20;
181		SHA1Final(mac, &ctx->u.sha1);
182		break;
183#ifdef CONFIG_SHA256
184	case CRYPTO_HASH_ALG_SHA256:
185		if (*len < 32) {
186			*len = 32;
187			os_free(ctx);
188			return -1;
189		}
190		*len = 32;
191		sha256_done(&ctx->u.sha256, mac);
192		break;
193#endif /* CONFIG_SHA256 */
194	case CRYPTO_HASH_ALG_HMAC_MD5:
195		if (*len < 16) {
196			*len = 16;
197			os_free(ctx);
198			return -1;
199		}
200		*len = 16;
201
202		MD5Final(mac, &ctx->u.md5);
203
204		os_memcpy(k_pad, ctx->key, ctx->key_len);
205		os_memset(k_pad + ctx->key_len, 0,
206			  sizeof(k_pad) - ctx->key_len);
207		for (i = 0; i < sizeof(k_pad); i++)
208			k_pad[i] ^= 0x5c;
209		MD5Init(&ctx->u.md5);
210		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
211		MD5Update(&ctx->u.md5, mac, 16);
212		MD5Final(mac, &ctx->u.md5);
213		break;
214	case CRYPTO_HASH_ALG_HMAC_SHA1:
215		if (*len < 20) {
216			*len = 20;
217			os_free(ctx);
218			return -1;
219		}
220		*len = 20;
221
222		SHA1Final(mac, &ctx->u.sha1);
223
224		os_memcpy(k_pad, ctx->key, ctx->key_len);
225		os_memset(k_pad + ctx->key_len, 0,
226			  sizeof(k_pad) - ctx->key_len);
227		for (i = 0; i < sizeof(k_pad); i++)
228			k_pad[i] ^= 0x5c;
229		SHA1Init(&ctx->u.sha1);
230		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
231		SHA1Update(&ctx->u.sha1, mac, 20);
232		SHA1Final(mac, &ctx->u.sha1);
233		break;
234#ifdef CONFIG_SHA256
235	case CRYPTO_HASH_ALG_HMAC_SHA256:
236		if (*len < 32) {
237			*len = 32;
238			os_free(ctx);
239			return -1;
240		}
241		*len = 32;
242
243		sha256_done(&ctx->u.sha256, mac);
244
245		os_memcpy(k_pad, ctx->key, ctx->key_len);
246		os_memset(k_pad + ctx->key_len, 0,
247			  sizeof(k_pad) - ctx->key_len);
248		for (i = 0; i < sizeof(k_pad); i++)
249			k_pad[i] ^= 0x5c;
250		sha256_init(&ctx->u.sha256);
251		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
252		sha256_process(&ctx->u.sha256, mac, 32);
253		sha256_done(&ctx->u.sha256, mac);
254		break;
255#endif /* CONFIG_SHA256 */
256	default:
257		os_free(ctx);
258		return -1;
259	}
260
261	os_free(ctx);
262
263	return 0;
264}
265
266
267int crypto_global_init(void)
268{
269	return 0;
270}
271
272
273void crypto_global_deinit(void)
274{
275}
276