| /* |
| * Crypto wrapper for internal crypto implementation |
| * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * Alternatively, this software may be distributed under the terms of BSD |
| * license. |
| * |
| * See README and COPYING for more details. |
| */ |
| |
| #include "includes.h" |
| |
| #include "common.h" |
| #include "crypto.h" |
| #include "sha1_i.h" |
| #include "md5_i.h" |
| |
| struct crypto_hash { |
| enum crypto_hash_alg alg; |
| union { |
| struct MD5Context md5; |
| struct SHA1Context sha1; |
| } u; |
| u8 key[64]; |
| size_t key_len; |
| }; |
| |
| |
| struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, |
| size_t key_len) |
| { |
| struct crypto_hash *ctx; |
| u8 k_pad[64]; |
| u8 tk[20]; |
| size_t i; |
| |
| ctx = os_zalloc(sizeof(*ctx)); |
| if (ctx == NULL) |
| return NULL; |
| |
| ctx->alg = alg; |
| |
| switch (alg) { |
| case CRYPTO_HASH_ALG_MD5: |
| MD5Init(&ctx->u.md5); |
| break; |
| case CRYPTO_HASH_ALG_SHA1: |
| SHA1Init(&ctx->u.sha1); |
| break; |
| case CRYPTO_HASH_ALG_HMAC_MD5: |
| if (key_len > sizeof(k_pad)) { |
| MD5Init(&ctx->u.md5); |
| MD5Update(&ctx->u.md5, key, key_len); |
| MD5Final(tk, &ctx->u.md5); |
| key = tk; |
| key_len = 16; |
| } |
| os_memcpy(ctx->key, key, key_len); |
| ctx->key_len = key_len; |
| |
| os_memcpy(k_pad, key, key_len); |
| os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); |
| for (i = 0; i < sizeof(k_pad); i++) |
| k_pad[i] ^= 0x36; |
| MD5Init(&ctx->u.md5); |
| MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); |
| break; |
| case CRYPTO_HASH_ALG_HMAC_SHA1: |
| if (key_len > sizeof(k_pad)) { |
| SHA1Init(&ctx->u.sha1); |
| SHA1Update(&ctx->u.sha1, key, key_len); |
| SHA1Final(tk, &ctx->u.sha1); |
| key = tk; |
| key_len = 20; |
| } |
| os_memcpy(ctx->key, key, key_len); |
| ctx->key_len = key_len; |
| |
| os_memcpy(k_pad, key, key_len); |
| os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); |
| for (i = 0; i < sizeof(k_pad); i++) |
| k_pad[i] ^= 0x36; |
| SHA1Init(&ctx->u.sha1); |
| SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); |
| break; |
| default: |
| os_free(ctx); |
| return NULL; |
| } |
| |
| return ctx; |
| } |
| |
| |
| void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) |
| { |
| if (ctx == NULL) |
| return; |
| |
| switch (ctx->alg) { |
| case CRYPTO_HASH_ALG_MD5: |
| case CRYPTO_HASH_ALG_HMAC_MD5: |
| MD5Update(&ctx->u.md5, data, len); |
| break; |
| case CRYPTO_HASH_ALG_SHA1: |
| case CRYPTO_HASH_ALG_HMAC_SHA1: |
| SHA1Update(&ctx->u.sha1, data, len); |
| break; |
| } |
| } |
| |
| |
| int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) |
| { |
| u8 k_pad[64]; |
| size_t i; |
| |
| if (ctx == NULL) |
| return -2; |
| |
| if (mac == NULL || len == NULL) { |
| os_free(ctx); |
| return 0; |
| } |
| |
| switch (ctx->alg) { |
| case CRYPTO_HASH_ALG_MD5: |
| if (*len < 16) { |
| *len = 16; |
| os_free(ctx); |
| return -1; |
| } |
| *len = 16; |
| MD5Final(mac, &ctx->u.md5); |
| break; |
| case CRYPTO_HASH_ALG_SHA1: |
| if (*len < 20) { |
| *len = 20; |
| os_free(ctx); |
| return -1; |
| } |
| *len = 20; |
| SHA1Final(mac, &ctx->u.sha1); |
| break; |
| case CRYPTO_HASH_ALG_HMAC_MD5: |
| if (*len < 16) { |
| *len = 16; |
| os_free(ctx); |
| return -1; |
| } |
| *len = 16; |
| |
| MD5Final(mac, &ctx->u.md5); |
| |
| os_memcpy(k_pad, ctx->key, ctx->key_len); |
| os_memset(k_pad + ctx->key_len, 0, |
| sizeof(k_pad) - ctx->key_len); |
| for (i = 0; i < sizeof(k_pad); i++) |
| k_pad[i] ^= 0x5c; |
| MD5Init(&ctx->u.md5); |
| MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); |
| MD5Update(&ctx->u.md5, mac, 16); |
| MD5Final(mac, &ctx->u.md5); |
| break; |
| case CRYPTO_HASH_ALG_HMAC_SHA1: |
| if (*len < 20) { |
| *len = 20; |
| os_free(ctx); |
| return -1; |
| } |
| *len = 20; |
| |
| SHA1Final(mac, &ctx->u.sha1); |
| |
| os_memcpy(k_pad, ctx->key, ctx->key_len); |
| os_memset(k_pad + ctx->key_len, 0, |
| sizeof(k_pad) - ctx->key_len); |
| for (i = 0; i < sizeof(k_pad); i++) |
| k_pad[i] ^= 0x5c; |
| SHA1Init(&ctx->u.sha1); |
| SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); |
| SHA1Update(&ctx->u.sha1, mac, 20); |
| SHA1Final(mac, &ctx->u.sha1); |
| break; |
| } |
| |
| os_free(ctx); |
| |
| return 0; |
| } |
| |
| |
| int crypto_global_init(void) |
| { |
| return 0; |
| } |
| |
| |
| void crypto_global_deinit(void) |
| { |
| } |