Home | History | Annotate | Download | only in crypto
      1 /*
      2  * Crypto wrapper for internal crypto implementation
      3  * Copyright (c) 2006-2009, Jouni Malinen <j (at) 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 "sha1_i.h"
     20 #include "md5_i.h"
     21 
     22 struct crypto_hash {
     23 	enum crypto_hash_alg alg;
     24 	union {
     25 		struct MD5Context md5;
     26 		struct SHA1Context sha1;
     27 	} u;
     28 	u8 key[64];
     29 	size_t key_len;
     30 };
     31 
     32 
     33 struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
     34 				      size_t key_len)
     35 {
     36 	struct crypto_hash *ctx;
     37 	u8 k_pad[64];
     38 	u8 tk[20];
     39 	size_t i;
     40 
     41 	ctx = os_zalloc(sizeof(*ctx));
     42 	if (ctx == NULL)
     43 		return NULL;
     44 
     45 	ctx->alg = alg;
     46 
     47 	switch (alg) {
     48 	case CRYPTO_HASH_ALG_MD5:
     49 		MD5Init(&ctx->u.md5);
     50 		break;
     51 	case CRYPTO_HASH_ALG_SHA1:
     52 		SHA1Init(&ctx->u.sha1);
     53 		break;
     54 	case CRYPTO_HASH_ALG_HMAC_MD5:
     55 		if (key_len > sizeof(k_pad)) {
     56 			MD5Init(&ctx->u.md5);
     57 			MD5Update(&ctx->u.md5, key, key_len);
     58 			MD5Final(tk, &ctx->u.md5);
     59 			key = tk;
     60 			key_len = 16;
     61 		}
     62 		os_memcpy(ctx->key, key, key_len);
     63 		ctx->key_len = key_len;
     64 
     65 		os_memcpy(k_pad, key, key_len);
     66 		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
     67 		for (i = 0; i < sizeof(k_pad); i++)
     68 			k_pad[i] ^= 0x36;
     69 		MD5Init(&ctx->u.md5);
     70 		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
     71 		break;
     72 	case CRYPTO_HASH_ALG_HMAC_SHA1:
     73 		if (key_len > sizeof(k_pad)) {
     74 			SHA1Init(&ctx->u.sha1);
     75 			SHA1Update(&ctx->u.sha1, key, key_len);
     76 			SHA1Final(tk, &ctx->u.sha1);
     77 			key = tk;
     78 			key_len = 20;
     79 		}
     80 		os_memcpy(ctx->key, key, key_len);
     81 		ctx->key_len = key_len;
     82 
     83 		os_memcpy(k_pad, key, key_len);
     84 		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
     85 		for (i = 0; i < sizeof(k_pad); i++)
     86 			k_pad[i] ^= 0x36;
     87 		SHA1Init(&ctx->u.sha1);
     88 		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
     89 		break;
     90 	default:
     91 		os_free(ctx);
     92 		return NULL;
     93 	}
     94 
     95 	return ctx;
     96 }
     97 
     98 
     99 void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
    100 {
    101 	if (ctx == NULL)
    102 		return;
    103 
    104 	switch (ctx->alg) {
    105 	case CRYPTO_HASH_ALG_MD5:
    106 	case CRYPTO_HASH_ALG_HMAC_MD5:
    107 		MD5Update(&ctx->u.md5, data, len);
    108 		break;
    109 	case CRYPTO_HASH_ALG_SHA1:
    110 	case CRYPTO_HASH_ALG_HMAC_SHA1:
    111 		SHA1Update(&ctx->u.sha1, data, len);
    112 		break;
    113 	}
    114 }
    115 
    116 
    117 int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
    118 {
    119 	u8 k_pad[64];
    120 	size_t i;
    121 
    122 	if (ctx == NULL)
    123 		return -2;
    124 
    125 	if (mac == NULL || len == NULL) {
    126 		os_free(ctx);
    127 		return 0;
    128 	}
    129 
    130 	switch (ctx->alg) {
    131 	case CRYPTO_HASH_ALG_MD5:
    132 		if (*len < 16) {
    133 			*len = 16;
    134 			os_free(ctx);
    135 			return -1;
    136 		}
    137 		*len = 16;
    138 		MD5Final(mac, &ctx->u.md5);
    139 		break;
    140 	case CRYPTO_HASH_ALG_SHA1:
    141 		if (*len < 20) {
    142 			*len = 20;
    143 			os_free(ctx);
    144 			return -1;
    145 		}
    146 		*len = 20;
    147 		SHA1Final(mac, &ctx->u.sha1);
    148 		break;
    149 	case CRYPTO_HASH_ALG_HMAC_MD5:
    150 		if (*len < 16) {
    151 			*len = 16;
    152 			os_free(ctx);
    153 			return -1;
    154 		}
    155 		*len = 16;
    156 
    157 		MD5Final(mac, &ctx->u.md5);
    158 
    159 		os_memcpy(k_pad, ctx->key, ctx->key_len);
    160 		os_memset(k_pad + ctx->key_len, 0,
    161 			  sizeof(k_pad) - ctx->key_len);
    162 		for (i = 0; i < sizeof(k_pad); i++)
    163 			k_pad[i] ^= 0x5c;
    164 		MD5Init(&ctx->u.md5);
    165 		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
    166 		MD5Update(&ctx->u.md5, mac, 16);
    167 		MD5Final(mac, &ctx->u.md5);
    168 		break;
    169 	case CRYPTO_HASH_ALG_HMAC_SHA1:
    170 		if (*len < 20) {
    171 			*len = 20;
    172 			os_free(ctx);
    173 			return -1;
    174 		}
    175 		*len = 20;
    176 
    177 		SHA1Final(mac, &ctx->u.sha1);
    178 
    179 		os_memcpy(k_pad, ctx->key, ctx->key_len);
    180 		os_memset(k_pad + ctx->key_len, 0,
    181 			  sizeof(k_pad) - ctx->key_len);
    182 		for (i = 0; i < sizeof(k_pad); i++)
    183 			k_pad[i] ^= 0x5c;
    184 		SHA1Init(&ctx->u.sha1);
    185 		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
    186 		SHA1Update(&ctx->u.sha1, mac, 20);
    187 		SHA1Final(mac, &ctx->u.sha1);
    188 		break;
    189 	}
    190 
    191 	os_free(ctx);
    192 
    193 	return 0;
    194 }
    195 
    196 
    197 int crypto_global_init(void)
    198 {
    199 	return 0;
    200 }
    201 
    202 
    203 void crypto_global_deinit(void)
    204 {
    205 }
    206