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