Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / crypto / crypto_internal.c
index 8fdba65..f3602da 100644 (file)
@@ -1,21 +1,16 @@
 /*
  * Crypto wrapper for internal crypto implementation
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, 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.
+ * 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 "sha1_i.h"
 #include "md5_i.h"
 
@@ -24,6 +19,9 @@ struct crypto_hash {
        union {
                struct MD5Context md5;
                struct SHA1Context sha1;
+#ifdef CONFIG_SHA256
+               struct sha256_state sha256;
+#endif /* CONFIG_SHA256 */
        } u;
        u8 key[64];
        size_t key_len;
@@ -35,7 +33,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
 {
        struct crypto_hash *ctx;
        u8 k_pad[64];
-       u8 tk[20];
+       u8 tk[32];
        size_t i;
 
        ctx = os_zalloc(sizeof(*ctx));
@@ -51,6 +49,11 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
        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 */
        case CRYPTO_HASH_ALG_HMAC_MD5:
                if (key_len > sizeof(k_pad)) {
                        MD5Init(&ctx->u.md5);
@@ -63,7 +66,8 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
                ctx->key_len = key_len;
 
                os_memcpy(k_pad, key, key_len);
-               os_memset(k_pad + key_len, 0, sizeof(k_pad) - 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);
@@ -81,12 +85,34 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
                ctx->key_len = key_len;
 
                os_memcpy(k_pad, key, key_len);
-               os_memset(k_pad + key_len, 0, sizeof(k_pad) - 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;
@@ -110,6 +136,14 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
        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 */
+       default:
+               break;
        }
 }
 
@@ -146,6 +180,17 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
                *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 */
        case CRYPTO_HASH_ALG_HMAC_MD5:
                if (*len < 16) {
                        *len = 16;
@@ -186,6 +231,31 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
                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);