| /* |
| * Crypto wrapper for internal crypto implementation |
| * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> |
| * |
| * This software may be distributed under the terms of the BSD license. |
| * See README for more details. |
| */ |
| |
| #include "includes.h" |
| |
| #include "common.h" |
| #include "crypto.h" |
| #include "sha256_i.h" |
| #include "sha384_i.h" |
| #include "sha512_i.h" |
| #include "sha1_i.h" |
| #include "md5_i.h" |
| |
| struct crypto_hash { |
| enum crypto_hash_alg alg; |
| union { |
| struct MD5Context md5; |
| struct SHA1Context sha1; |
| #ifdef CONFIG_SHA256 |
| struct sha256_state sha256; |
| #endif /* CONFIG_SHA256 */ |
| #ifdef CONFIG_INTERNAL_SHA384 |
| struct sha384_state sha384; |
| #endif /* CONFIG_INTERNAL_SHA384 */ |
| #ifdef CONFIG_INTERNAL_SHA512 |
| struct sha512_state sha512; |
| #endif /* CONFIG_INTERNAL_SHA512 */ |
| } 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[32]; |
| 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; |
| #ifdef CONFIG_SHA256 |
| case CRYPTO_HASH_ALG_SHA256: |
| sha256_init(&ctx->u.sha256); |
| break; |
| #endif /* CONFIG_SHA256 */ |
| #ifdef CONFIG_INTERNAL_SHA384 |
| case CRYPTO_HASH_ALG_SHA384: |
| sha384_init(&ctx->u.sha384); |
| break; |
| #endif /* CONFIG_INTERNAL_SHA384 */ |
| #ifdef CONFIG_INTERNAL_SHA512 |
| case CRYPTO_HASH_ALG_SHA512: |
| sha512_init(&ctx->u.sha512); |
| break; |
| #endif /* CONFIG_INTERNAL_SHA512 */ |
| 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); |
| if (key_len < sizeof(k_pad)) |
| 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); |
| if (key_len < sizeof(k_pad)) |
| 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; |
| #ifdef CONFIG_SHA256 |
| case CRYPTO_HASH_ALG_HMAC_SHA256: |
| if (key_len > sizeof(k_pad)) { |
| sha256_init(&ctx->u.sha256); |
| sha256_process(&ctx->u.sha256, key, key_len); |
| sha256_done(&ctx->u.sha256, tk); |
| key = tk; |
| key_len = 32; |
| } |
| os_memcpy(ctx->key, key, key_len); |
| ctx->key_len = key_len; |
| |
| os_memcpy(k_pad, key, key_len); |
| if (key_len < sizeof(k_pad)) |
| os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); |
| for (i = 0; i < sizeof(k_pad); i++) |
| k_pad[i] ^= 0x36; |
| sha256_init(&ctx->u.sha256); |
| sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad)); |
| break; |
| #endif /* CONFIG_SHA256 */ |
| 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; |
| #ifdef CONFIG_SHA256 |
| case CRYPTO_HASH_ALG_SHA256: |
| case CRYPTO_HASH_ALG_HMAC_SHA256: |
| sha256_process(&ctx->u.sha256, data, len); |
| break; |
| #endif /* CONFIG_SHA256 */ |
| #ifdef CONFIG_INTERNAL_SHA384 |
| case CRYPTO_HASH_ALG_SHA384: |
| sha384_process(&ctx->u.sha384, data, len); |
| break; |
| #endif /* CONFIG_INTERNAL_SHA384 */ |
| #ifdef CONFIG_INTERNAL_SHA512 |
| case CRYPTO_HASH_ALG_SHA512: |
| sha512_process(&ctx->u.sha512, data, len); |
| break; |
| #endif /* CONFIG_INTERNAL_SHA512 */ |
| default: |
| 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; |
| #ifdef CONFIG_SHA256 |
| case CRYPTO_HASH_ALG_SHA256: |
| if (*len < 32) { |
| *len = 32; |
| os_free(ctx); |
| return -1; |
| } |
| *len = 32; |
| sha256_done(&ctx->u.sha256, mac); |
| break; |
| #endif /* CONFIG_SHA256 */ |
| #ifdef CONFIG_INTERNAL_SHA384 |
| case CRYPTO_HASH_ALG_SHA384: |
| if (*len < 48) { |
| *len = 48; |
| os_free(ctx); |
| return -1; |
| } |
| *len = 48; |
| sha384_done(&ctx->u.sha384, mac); |
| break; |
| #endif /* CONFIG_INTERNAL_SHA384 */ |
| #ifdef CONFIG_INTERNAL_SHA512 |
| case CRYPTO_HASH_ALG_SHA512: |
| if (*len < 64) { |
| *len = 64; |
| os_free(ctx); |
| return -1; |
| } |
| *len = 64; |
| sha512_done(&ctx->u.sha512, mac); |
| break; |
| #endif /* CONFIG_INTERNAL_SHA512 */ |
| 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; |
| #ifdef CONFIG_SHA256 |
| case CRYPTO_HASH_ALG_HMAC_SHA256: |
| if (*len < 32) { |
| *len = 32; |
| os_free(ctx); |
| return -1; |
| } |
| *len = 32; |
| |
| sha256_done(&ctx->u.sha256, mac); |
| |
| 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; |
| sha256_init(&ctx->u.sha256); |
| sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad)); |
| sha256_process(&ctx->u.sha256, mac, 32); |
| sha256_done(&ctx->u.sha256, mac); |
| break; |
| #endif /* CONFIG_SHA256 */ |
| default: |
| os_free(ctx); |
| return -1; |
| } |
| |
| os_free(ctx); |
| |
| return 0; |
| } |
| |
| |
| int crypto_global_init(void) |
| { |
| return 0; |
| } |
| |
| |
| void crypto_global_deinit(void) |
| { |
| } |