crypto_internal.c revision 225736
1239478Sadrian/*
2239478Sadrian * Crypto wrapper for internal crypto implementation
3239478Sadrian * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
4239478Sadrian *
5239478Sadrian * This program is free software; you can redistribute it and/or modify
6239478Sadrian * it under the terms of the GNU General Public License version 2 as
7239478Sadrian * published by the Free Software Foundation.
8239478Sadrian *
9239478Sadrian * Alternatively, this software may be distributed under the terms of BSD
10239478Sadrian * license.
11239478Sadrian *
12239478Sadrian * See README and COPYING for more details.
13239478Sadrian */
14239478Sadrian
15239478Sadrian#include "includes.h"
16239478Sadrian
17239478Sadrian#include "common.h"
18239478Sadrian#include "crypto.h"
19239478Sadrian#include "sha1_i.h"
20239478Sadrian#include "md5_i.h"
21239478Sadrian
22239478Sadrianstruct crypto_hash {
23239478Sadrian	enum crypto_hash_alg alg;
24239478Sadrian	union {
25239478Sadrian		struct MD5Context md5;
26239478Sadrian		struct SHA1Context sha1;
27239478Sadrian	} u;
28239478Sadrian	u8 key[64];
29239478Sadrian	size_t key_len;
30239478Sadrian};
31239478Sadrian
32239478Sadrian
33239478Sadrianstruct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
34239478Sadrian				      size_t key_len)
35239478Sadrian{
36239478Sadrian	struct crypto_hash *ctx;
37239478Sadrian	u8 k_pad[64];
38239478Sadrian	u8 tk[20];
39239478Sadrian	size_t i;
40239478Sadrian
41239478Sadrian	ctx = os_zalloc(sizeof(*ctx));
42239478Sadrian	if (ctx == NULL)
43239478Sadrian		return NULL;
44239478Sadrian
45239478Sadrian	ctx->alg = alg;
46239478Sadrian
47239478Sadrian	switch (alg) {
48239478Sadrian	case CRYPTO_HASH_ALG_MD5:
49239478Sadrian		MD5Init(&ctx->u.md5);
50239478Sadrian		break;
51239478Sadrian	case CRYPTO_HASH_ALG_SHA1:
52239478Sadrian		SHA1Init(&ctx->u.sha1);
53239478Sadrian		break;
54239478Sadrian	case CRYPTO_HASH_ALG_HMAC_MD5:
55239478Sadrian		if (key_len > sizeof(k_pad)) {
56239478Sadrian			MD5Init(&ctx->u.md5);
57239478Sadrian			MD5Update(&ctx->u.md5, key, key_len);
58239478Sadrian			MD5Final(tk, &ctx->u.md5);
59239478Sadrian			key = tk;
60239478Sadrian			key_len = 16;
61239478Sadrian		}
62239478Sadrian		os_memcpy(ctx->key, key, key_len);
63239478Sadrian		ctx->key_len = key_len;
64239478Sadrian
65239478Sadrian		os_memcpy(k_pad, key, key_len);
66239478Sadrian		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
67239478Sadrian		for (i = 0; i < sizeof(k_pad); i++)
68239478Sadrian			k_pad[i] ^= 0x36;
69239478Sadrian		MD5Init(&ctx->u.md5);
70239478Sadrian		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
71239478Sadrian		break;
72239478Sadrian	case CRYPTO_HASH_ALG_HMAC_SHA1:
73239478Sadrian		if (key_len > sizeof(k_pad)) {
74239478Sadrian			SHA1Init(&ctx->u.sha1);
75239478Sadrian			SHA1Update(&ctx->u.sha1, key, key_len);
76239478Sadrian			SHA1Final(tk, &ctx->u.sha1);
77239478Sadrian			key = tk;
78239478Sadrian			key_len = 20;
79239478Sadrian		}
80239478Sadrian		os_memcpy(ctx->key, key, key_len);
81239478Sadrian		ctx->key_len = key_len;
82239478Sadrian
83239478Sadrian		os_memcpy(k_pad, key, key_len);
84239478Sadrian		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
85239478Sadrian		for (i = 0; i < sizeof(k_pad); i++)
86239478Sadrian			k_pad[i] ^= 0x36;
87239478Sadrian		SHA1Init(&ctx->u.sha1);
88239478Sadrian		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
89239478Sadrian		break;
90239478Sadrian	default:
91239478Sadrian		os_free(ctx);
92239478Sadrian		return NULL;
93239478Sadrian	}
94239478Sadrian
95239478Sadrian	return ctx;
96239478Sadrian}
97239478Sadrian
98239478Sadrian
99239478Sadrianvoid crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
100239478Sadrian{
101239478Sadrian	if (ctx == NULL)
102239478Sadrian		return;
103239478Sadrian
104239478Sadrian	switch (ctx->alg) {
105239478Sadrian	case CRYPTO_HASH_ALG_MD5:
106239478Sadrian	case CRYPTO_HASH_ALG_HMAC_MD5:
107239478Sadrian		MD5Update(&ctx->u.md5, data, len);
108239478Sadrian		break;
109239478Sadrian	case CRYPTO_HASH_ALG_SHA1:
110239478Sadrian	case CRYPTO_HASH_ALG_HMAC_SHA1:
111239478Sadrian		SHA1Update(&ctx->u.sha1, data, len);
112239478Sadrian		break;
113239478Sadrian	}
114239478Sadrian}
115239478Sadrian
116239478Sadrian
117239478Sadrianint crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
118239478Sadrian{
119239478Sadrian	u8 k_pad[64];
120239478Sadrian	size_t i;
121239478Sadrian
122239478Sadrian	if (ctx == NULL)
123239478Sadrian		return -2;
124239478Sadrian
125239478Sadrian	if (mac == NULL || len == NULL) {
126239478Sadrian		os_free(ctx);
127239478Sadrian		return 0;
128239478Sadrian	}
129239478Sadrian
130239478Sadrian	switch (ctx->alg) {
131239478Sadrian	case CRYPTO_HASH_ALG_MD5:
132239478Sadrian		if (*len < 16) {
133239478Sadrian			*len = 16;
134239478Sadrian			os_free(ctx);
135239478Sadrian			return -1;
136239478Sadrian		}
137239478Sadrian		*len = 16;
138239478Sadrian		MD5Final(mac, &ctx->u.md5);
139239478Sadrian		break;
140239478Sadrian	case CRYPTO_HASH_ALG_SHA1:
141239478Sadrian		if (*len < 20) {
142239478Sadrian			*len = 20;
143239478Sadrian			os_free(ctx);
144239478Sadrian			return -1;
145239478Sadrian		}
146239478Sadrian		*len = 20;
147239478Sadrian		SHA1Final(mac, &ctx->u.sha1);
148239478Sadrian		break;
149239478Sadrian	case CRYPTO_HASH_ALG_HMAC_MD5:
150239478Sadrian		if (*len < 16) {
151239478Sadrian			*len = 16;
152239478Sadrian			os_free(ctx);
153239478Sadrian			return -1;
154239478Sadrian		}
155239478Sadrian		*len = 16;
156239478Sadrian
157239478Sadrian		MD5Final(mac, &ctx->u.md5);
158239478Sadrian
159239478Sadrian		os_memcpy(k_pad, ctx->key, ctx->key_len);
160239478Sadrian		os_memset(k_pad + ctx->key_len, 0,
161239478Sadrian			  sizeof(k_pad) - ctx->key_len);
162239478Sadrian		for (i = 0; i < sizeof(k_pad); i++)
163239478Sadrian			k_pad[i] ^= 0x5c;
164239478Sadrian		MD5Init(&ctx->u.md5);
165239478Sadrian		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
166239478Sadrian		MD5Update(&ctx->u.md5, mac, 16);
167239478Sadrian		MD5Final(mac, &ctx->u.md5);
168239478Sadrian		break;
169239478Sadrian	case CRYPTO_HASH_ALG_HMAC_SHA1:
170239478Sadrian		if (*len < 20) {
171239478Sadrian			*len = 20;
172239478Sadrian			os_free(ctx);
173239478Sadrian			return -1;
174239478Sadrian		}
175239478Sadrian		*len = 20;
176239478Sadrian
177239478Sadrian		SHA1Final(mac, &ctx->u.sha1);
178239478Sadrian
179239478Sadrian		os_memcpy(k_pad, ctx->key, ctx->key_len);
180239478Sadrian		os_memset(k_pad + ctx->key_len, 0,
181239478Sadrian			  sizeof(k_pad) - ctx->key_len);
182239478Sadrian		for (i = 0; i < sizeof(k_pad); i++)
183239478Sadrian			k_pad[i] ^= 0x5c;
184239478Sadrian		SHA1Init(&ctx->u.sha1);
185239478Sadrian		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
186239478Sadrian		SHA1Update(&ctx->u.sha1, mac, 20);
187239478Sadrian		SHA1Final(mac, &ctx->u.sha1);
188239478Sadrian		break;
189239478Sadrian	}
190239478Sadrian
191239478Sadrian	os_free(ctx);
192239478Sadrian
193239478Sadrian	return 0;
194239478Sadrian}
195239478Sadrian
196239478Sadrian
197239478Sadrianint crypto_global_init(void)
198239478Sadrian{
199239478Sadrian	return 0;
200239478Sadrian}
201239478Sadrian
202239478Sadrian
203239478Sadrianvoid crypto_global_deinit(void)
204239478Sadrian{
205239478Sadrian}
206239478Sadrian