The introduced SHA1_NOFINAL hasher was not sufficient for EAP-AKA,
authorMartin Willi <martin@strongswan.org>
Wed, 19 Mar 2008 14:02:52 +0000 (14:02 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 19 Mar 2008 14:02:52 +0000 (14:02 -0000)
as it requires to XOR the key into the hashers state.
A new SHA1 based keyed hash function, implemented as PRF, enables EAP-AKA
and the FIPS-PRF function to properly use the existing SHA1 implementation.

src/charon/plugins/eap_aka/eap_aka.c
src/charon/plugins/unit_tester/tests/test_fips_prf.c
src/libstrongswan/crypto/hashers/hasher.c
src/libstrongswan/crypto/hashers/hasher.h
src/libstrongswan/crypto/prfs/prf.c
src/libstrongswan/crypto/prfs/prf.h
src/libstrongswan/plugins/fips_prf/fips_prf.c
src/libstrongswan/plugins/sha1/sha1_hasher.c
src/libstrongswan/plugins/sha1/sha1_hasher.h
src/libstrongswan/plugins/sha1/sha1_plugin.c

index 3dd842b..a8bef72 100644 (file)
@@ -204,11 +204,6 @@ struct private_eap_aka_t {
        hasher_t *sha1;
        
        /**
-        * SHA1_NOFINAL hasher for G() function
-        */
-       hasher_t *sha1_nof;
-       
-       /**
         * MAC function used in EAP-AKA
         */
        signer_t *signer;
@@ -219,6 +214,11 @@ struct private_eap_aka_t {
        prf_t *prf;
        
        /**
+        * Special keyed SHA1 hasher used in EAP-AKA, implemented as PRF
+        */
+       prf_t *keyed_prf;
+       
+       /**
         * Key for EAP MAC
         */
        chunk_t k_auth;
@@ -437,48 +437,31 @@ static void step4(private_eap_aka_t *this, u_int8_t x[])
 }
 
 /**
- * Implementation of the G() function based on SHA1
+ * Step 3 of the various fx() functions:
+ * XOR the key into the SHA1 IV
  */
-static void g_sha1(private_eap_aka_t *this,
-                                  u_int8_t t[], chunk_t c, u_int8_t res[])
+static void step3(private_eap_aka_t *this,
+                                 chunk_t k, chunk_t payload, u_int8_t h[])
 {
        u_int8_t buf[64];
        
-       if (c.len < sizeof(buf))
+       if (payload.len < sizeof(buf))
        {
                /* pad c with zeros */
                memset(buf, 0, sizeof(buf));
-               memcpy(buf, c.ptr, c.len);
-               c.ptr = buf;
-               c.len = sizeof(buf);
+               memcpy(buf, payload.ptr, payload.len);
+               payload.ptr = buf;
+               payload.len = sizeof(buf);
        }
        else
        {
                /* not more than 512 bits can be G()-ed */
-               c.len = sizeof(buf);
+               payload.len = sizeof(buf);
        }
        
-       /* calculate the special (HASH_SHA1_STATE) hash*/
-       this->sha1_nof->get_hash(this->sha1_nof, c, res);
-}
-
-/**
- * Step 3 of the various fx() functions:
- * XOR the key into the SHA1 IV
- */
-static void step3(private_eap_aka_t *this,
-                                 chunk_t k, chunk_t payload, u_int8_t h[])
-{
-       u_int8_t iv[] = {
-               0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA,
-               0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0,
-       };
-       
-       /* XOR key into IV */
-       memxor(iv, k.ptr, k.len);
-       
-       /* hash it with the G() function defined in FIPS 186-2 from fips_prf.h */
-       g_sha1(this, iv, payload, h);
+       /* use the keyed hasher to build the hash */
+       this->keyed_prf->set_key(this->keyed_prf, k);
+       this->keyed_prf->get_bytes(this->keyed_prf, payload, h);
 }
 
 /**
@@ -1282,6 +1265,7 @@ static status_t peer_process_challenge(private_eap_aka_t *this,
        /* verify EAP message MAC AT_MAC */
        DBG3(DBG_IKE, "verifying AT_MAC signature of %B", &message);
        DBG3(DBG_IKE, "using key %B", &this->k_auth);
+       this->signer->set_key(this->signer, this->k_auth);
        if (!this->signer->verify_signature(this->signer, message, at_mac))
        {
                *out = build_aka_payload(this, EAP_RESPONSE, identifier, AKA_CLIENT_ERROR,
@@ -1468,9 +1452,9 @@ static bool is_mutual(private_eap_aka_t *this)
 static void destroy(private_eap_aka_t *this)
 {
        DESTROY_IF(this->sha1);
-       DESTROY_IF(this->sha1_nof);
        DESTROY_IF(this->signer);
        DESTROY_IF(this->prf);
+       DESTROY_IF(this->keyed_prf);
        chunk_free(&this->k_encr);
        chunk_free(&this->k_auth);
        chunk_free(&this->msk);
@@ -1508,17 +1492,17 @@ static private_eap_aka_t *eap_aka_create_generic(identification_t *server,
        this->rand = chunk_empty;
        
        this->sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
-       this->sha1_nof = lib->crypto->create_hasher(lib->crypto, HASH_SHA1_NOFINAL);
        this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_SHA1_128);
        this->prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160);
+       this->keyed_prf = lib->crypto->create_prf(lib->crypto, PRF_KEYED_SHA1);
 
-       if (!this->sha1 || !this->sha1_nof || !this->signer || !this->prf)
+       if (!this->sha1 || !this->signer || !this->prf || !this->keyed_prf)
        {
                DBG1(DBG_IKE, "unable to initiate EAP-AKA, FIPS-PRF/SHA1 not supported");
                DESTROY_IF(this->sha1);
-               DESTROY_IF(this->sha1_nof);
                DESTROY_IF(this->signer);
                DESTROY_IF(this->prf);
+               DESTROY_IF(this->keyed_prf);
                destroy(this);
                return NULL;
        }
index 56ba556..2961214 100644 (file)
@@ -45,6 +45,7 @@ bool fips_prf_test()
        prf = lib->crypto->create_prf(lib->crypto, PRF_FIPS_SHA1_160);
        if (prf == NULL)
        {
+               DBG1(DBG_CFG, "FIPS PRF implementation not found");
                return FALSE;
        }
        prf->set_key(prf, key);
@@ -52,6 +53,8 @@ bool fips_prf_test()
        prf->destroy(prf);
        if (!chunk_equals(result, expected))
        {
+               DBG1(DBG_CFG, "FIPS PRF result invalid:\nexpected: %Bresult: %B",
+                        &expected, &result);
                chunk_free(&result);
                return FALSE;
        }
index ea4b4b0..ce208a1 100644 (file)
@@ -27,7 +27,6 @@ ENUM(hash_algorithm_names, HASH_UNKNOWN, HASH_SHA512,
        "HASH_MD2",
        "HASH_MD5",
        "HASH_SHA1",
-       "HASH_SHA1_NOFINAL",
        "HASH_SHA256",
        "HASH_SHA384",
        "HASH_SHA512"
index 4aa4ba3..a374da0 100644 (file)
@@ -41,11 +41,9 @@ enum hash_algorithm_t {
        HASH_MD2                        = 2,
        HASH_MD5                        = 3,
        HASH_SHA1                       = 4,
-       /** special SHA1 which does not run SHA1Final, but copies the state */
-       HASH_SHA1_NOFINAL       = 5,
-       HASH_SHA256             = 6,
-       HASH_SHA384             = 7,
-       HASH_SHA512             = 8,
+       HASH_SHA256             = 5,
+       HASH_SHA384             = 6,
+       HASH_SHA512             = 7,
 };
 
 #define HASH_SIZE_MD2          16
index c1fa1e1..6388736 100644 (file)
 
 #include "prf.h"
 
-ENUM_BEGIN(pseudo_random_function_names, PRF_UNDEFINED, PRF_FIPS_DES,
+ENUM_BEGIN(pseudo_random_function_names, PRF_UNDEFINED, PRF_KEYED_SHA1,
        "PRF_UNDEFINED",
        "PRF_FIPS_SHA1_160",
-       "PRF_FIPS_DES");
-ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_HMAC_SHA2_512, PRF_FIPS_DES,
+       "PRF_FIPS_DES",
+       "PRF_KEYED_SHA1");
+ENUM_NEXT(pseudo_random_function_names, PRF_HMAC_MD5, PRF_HMAC_SHA2_512, PRF_KEYED_SHA1,
        "PRF_HMAC_MD5",
        "PRF_HMAC_SHA1",
        "PRF_HMAC_TIGER",
index 662a959..135d788 100644 (file)
@@ -53,6 +53,11 @@ enum pseudo_random_function_t {
        PRF_FIPS_SHA1_160 = 1025,
        /** Could be implemented via fips_prf_t, uses fixed output size of 160bit */
        PRF_FIPS_DES = 1026,
+       /** 
+        * Keyed hash algorithm using SHA1, used in EAP-AKA:
+        * This PRF uses SHA1, but XORs the key into the IV. No "Final()" operation
+        * is applied to the SHA1 state. */
+       PRF_KEYED_SHA1 = 1027,
 };
 
 /**
index 20b752e..11adad0 100644 (file)
@@ -43,26 +43,17 @@ struct private_fips_prf_t {
        size_t b;
        
        /**
-        * associated hasher when using SHA1 mode
+        * Keyed SHA1 prf: It does not use SHA1Final operation
         */
-       hasher_t *hasher;
+       prf_t *keyed_prf;
        
        /**
         * G function, either SHA1 or DES
         */
-       void (*g)(private_fips_prf_t *this, u_int8_t t[], chunk_t c, u_int8_t res[]);
+       void (*g)(private_fips_prf_t *this, chunk_t c, u_int8_t res[]);
 };
 
 /**
- * t used in G(), equals to initial SHA1 value
- */
-static u_int8_t t[] = {
-       0x67,0x45,0x23,0x01,0xEF,0xCD,0xAB,0x89,0x98,0xBA,
-       0xDC,0xFE,0x10,0x32,0x54,0x76,0xC3,0xD2,0xE1,0xF0,
-};
-
-
-/**
  * sum = (a + b) mod 2 ^ (length * 8)
  */
 static void add_mod(size_t length, u_int8_t a[], u_int8_t b[], u_int8_t sum[])
@@ -140,7 +131,7 @@ static void get_bytes(private_fips_prf_t *this, chunk_t seed, u_int8_t w[])
                add_mod(this->b, xkey, xseed, xval);
                DBG3("XVAL %b", xval, this->b);
                /* b. wi = G(t, XVAL ) */
-               this->g(this, t, xval_chunk, &w[i * this->b]);
+               this->g(this, xval_chunk, &w[i * this->b]);
                DBG3("w[%d] %b", i, &w[i * this->b], this->b);
                /* c. XKEY = (1 + XKEY + wi) mod 2b */
                add_mod(this->b, xkey, &w[i * this->b], sum);
@@ -187,7 +178,7 @@ static void set_key(private_fips_prf_t *this, chunk_t key)
 /**
  * Implementation of the G() function based on SHA1
  */
-void g_sha1(private_fips_prf_t *this, u_int8_t t[], chunk_t c, u_int8_t res[])
+void g_sha1(private_fips_prf_t *this, chunk_t c, u_int8_t res[])
 {
        u_int8_t buf[64];
        
@@ -205,8 +196,9 @@ void g_sha1(private_fips_prf_t *this, u_int8_t t[], chunk_t c, u_int8_t res[])
                c.len = sizeof(buf);
        }
        
-       /* calculate the special (HASH_SHA1_STATE) hash*/
-       this->hasher->get_hash(this->hasher, c, res);
+       /* use the keyed hasher, but use an empty key to use SHA1 IV */
+       this->keyed_prf->set_key(this->keyed_prf, chunk_empty);
+       this->keyed_prf->get_bytes(this->keyed_prf, c, res);
 }
 
 /**
@@ -214,7 +206,7 @@ void g_sha1(private_fips_prf_t *this, u_int8_t t[], chunk_t c, u_int8_t res[])
  */
 static void destroy(private_fips_prf_t *this)
 {
-       this->hasher->destroy(this->hasher);
+       this->keyed_prf->destroy(this->keyed_prf);
        free(this->key);
        free(this);
 }
@@ -239,9 +231,8 @@ fips_prf_t *fips_prf_create(pseudo_random_function_t algo)
                {
                        this->g = g_sha1;
                        this->b = 20;
-                       this->hasher = lib->crypto->create_hasher(lib->crypto,
-                                                                                                         HASH_SHA1_NOFINAL);
-                       if (this->hasher == NULL)
+                       this->keyed_prf = lib->crypto->create_prf(lib->crypto, PRF_KEYED_SHA1);
+                       if (this->keyed_prf == NULL)
                        {
                                free(this);
                                return NULL;
index 97a2f20..8d8e563 100644 (file)
@@ -47,6 +47,7 @@
 
 
 typedef struct private_sha1_hasher_t private_sha1_hasher_t;
+typedef struct private_sha1_keyed_prf_t private_sha1_keyed_prf_t;
 
 /**
  * Private data structure with hasing context.
@@ -57,11 +58,6 @@ struct private_sha1_hasher_t {
         */
        sha1_hasher_t public;
        
-       /**
-        * implemented algorithm
-        */
-       hash_algorithm_t algo;
-       
        /*
         * State of the hasher.
         */
@@ -70,6 +66,21 @@ struct private_sha1_hasher_t {
     u_int8_t buffer[64];
 };
 
+/**
+ * Private data structure with keyed prf context.
+ */
+struct private_sha1_keyed_prf_t {
+       /**
+        * public prf interface
+        */
+       sha1_keyed_prf_t public;
+
+       /**
+        * internal used hasher
+        */
+       private_sha1_hasher_t *hasher;
+};
+
 /* 
  * Hash a single 512-bit block. This is the core of the algorithm. *
  */
@@ -197,19 +208,6 @@ static void reset(private_sha1_hasher_t *this)
 }
 
 /**
- * copy hasher state to buf
- */
-static void state_to_buf(private_sha1_hasher_t *this, u_int8_t *buffer)
-{
-       u_int32_t *hash = (u_int32_t*)buffer;
-       hash[0] = htonl(this->state[0]);
-       hash[1] = htonl(this->state[1]);
-       hash[2] = htonl(this->state[2]);
-       hash[3] = htonl(this->state[3]);
-       hash[4] = htonl(this->state[4]);
-}
-
-/**
  * Implementation of hasher_t.get_hash.
  */
 static void get_hash(private_sha1_hasher_t *this, chunk_t chunk, u_int8_t *buffer)
@@ -217,19 +215,11 @@ static void get_hash(private_sha1_hasher_t *this, chunk_t chunk, u_int8_t *buffe
        SHA1Update(this, chunk.ptr, chunk.len);
        if (buffer != NULL)
        {
-               if (this->algo == HASH_SHA1_NOFINAL)
-               {
-                       state_to_buf(this, buffer);
-               }
-               else
-               {
-                       SHA1Final(this, buffer);
-               }
+               SHA1Final(this, buffer);
                reset(this);
        }
 }
 
-
 /**
  * Implementation of hasher_t.allocate_hash.
  */
@@ -241,14 +231,7 @@ static void allocate_hash(private_sha1_hasher_t *this, chunk_t chunk, chunk_t *h
                hash->ptr = malloc(HASH_SIZE_SHA1);
                hash->len = HASH_SIZE_SHA1;
                
-               if (this->algo == HASH_SHA1_NOFINAL)
-               {
-                       state_to_buf(this, hash->ptr);
-               }
-               else
-               {
-                       SHA1Final(this, hash->ptr);
-               }
+               SHA1Final(this, hash->ptr);
                reset(this);
        }
 }
@@ -275,12 +258,11 @@ static void destroy(private_sha1_hasher_t *this)
 sha1_hasher_t *sha1_hasher_create(hash_algorithm_t algo)
 {
        private_sha1_hasher_t *this;
-       if (algo != HASH_SHA1 && algo != HASH_SHA1_NOFINAL)
+       if (algo != HASH_SHA1)
        {
                return NULL;
        }
        this = malloc_thing(private_sha1_hasher_t);
-       this->algo = algo;
        this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash;
        this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash;
        this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size;
@@ -292,3 +274,93 @@ sha1_hasher_t *sha1_hasher_create(hash_algorithm_t algo)
        
        return &(this->public);
 }
+
+/**
+ * Implementation of prf_t.get_bytes.
+ */
+static void get_bytes(private_sha1_keyed_prf_t *this, chunk_t seed, u_int8_t *bytes)
+{
+       u_int32_t *hash = (u_int32_t*)bytes;
+
+       SHA1Update(this->hasher, seed.ptr, seed.len);
+
+       hash[0] = htonl(this->hasher->state[0]);
+       hash[1] = htonl(this->hasher->state[1]);
+       hash[2] = htonl(this->hasher->state[2]);
+       hash[3] = htonl(this->hasher->state[3]);
+       hash[4] = htonl(this->hasher->state[4]);
+}
+
+/**
+ * Implementation of prf_t.get_block_size.
+ */
+static size_t get_block_size(private_sha1_keyed_prf_t *this)
+{
+       return HASH_SIZE_SHA1;
+}
+
+/**
+ * Implementation of prf_t.allocate_bytes.
+ */
+static void allocate_bytes(private_sha1_keyed_prf_t *this, chunk_t seed, chunk_t *chunk)
+{
+       *chunk = chunk_alloc(HASH_SIZE_SHA1);
+       get_bytes(this, seed, chunk->ptr);
+}
+
+/**
+ * Implementation of prf_t.get_key_size.
+ */
+static size_t get_key_size(private_sha1_keyed_prf_t *this)
+{
+       return sizeof(this->hasher->state);
+}
+
+/**
+ * Implementation of prf_t.set_key.
+ */
+static void set_key(private_sha1_keyed_prf_t *this, chunk_t key)
+{
+       int i, rounds;
+       u_int32_t *iv = (u_int32_t*)key.ptr;
+       
+       reset(this->hasher);
+       rounds = min(key.len/sizeof(u_int32_t), sizeof(this->hasher->state));
+       for (i = 0; i < rounds; i++)
+       {
+               this->hasher->state[i] ^= htonl(iv[i]);
+       }
+}
+
+/**
+ * Implementation of prf_t.destroy.
+ */
+static void destroy_p(private_sha1_keyed_prf_t *this)
+{
+       destroy(this->hasher);
+       free(this);
+}
+
+/**
+ * see header
+ */
+sha1_keyed_prf_t *sha1_keyed_prf_create(pseudo_random_function_t algo)
+{
+       private_sha1_keyed_prf_t *this;
+       if (algo != PRF_KEYED_SHA1)
+       {
+               return NULL;
+       }
+       this = malloc_thing(private_sha1_keyed_prf_t);
+       this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes;
+       this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes;
+       this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size;
+       this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size;
+       this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key;
+       this->public.prf_interface.destroy = (void (*) (prf_t *))destroy_p;
+       
+       this->hasher = (private_sha1_hasher_t*)sha1_hasher_create(HASH_SHA1);
+       
+       return &(this->public);
+}
+
index aff0eae..2e44797 100644 (file)
 #define SHA1_HASHER_H_
 
 typedef struct sha1_hasher_t sha1_hasher_t;
+typedef struct sha1_keyed_prf_t sha1_keyed_prf_t;
 
 #include <crypto/hashers/hasher.h>
+#include <crypto/prfs/prf.h>
 
 /**
  * Implementation of hasher_t interface using the SHA1 algorithm.
@@ -38,13 +40,30 @@ struct sha1_hasher_t {
 };
 
 /**
+ * Implementation of prf_t interface using keyed SHA1 algorithm (used for EAP-AKA).
+ */
+struct sha1_keyed_prf_t {
+       
+       /**
+        * Implements prf_t interface.
+        */
+       prf_t prf_interface;
+};
+
+/**
  * Creates a new sha1_hasher_t.
- * 
- * This implementation supports two algorithms, HASH_SHA1 and HASH_SHA1_NOFINAL
  *
- * @param algo         algorithm
+ * @param algo         algorithm, must be HASH_SHA1
  * @return                     sha1_hasher_t object
  */
 sha1_hasher_t *sha1_hasher_create(hash_algorithm_t algo);
 
+/**
+ * Creates a new sha1_keyed_prf_t.
+ *
+ * @param algo         algorithm, must be PRF_KEYED_SHA1
+ * @return                     sha1_keyed_prf_tobject
+ */
+sha1_keyed_prf_t *sha1_keyed_prf_create(pseudo_random_function_t algo);
+
 #endif /*SHA1_HASHER_H_ @}*/
index 4a69c4e..391664f 100644 (file)
@@ -40,6 +40,8 @@ static void destroy(private_sha1_plugin_t *this)
 {
        lib->crypto->remove_hasher(lib->crypto,
                                                           (hasher_constructor_t)sha1_hasher_create);
+       lib->crypto->remove_prf(lib->crypto,
+                                                          (prf_constructor_t)sha1_keyed_prf_create);
        free(this);
 }
 
@@ -54,8 +56,8 @@ plugin_t *plugin_create()
        
        lib->crypto->add_hasher(lib->crypto, HASH_SHA1,
                                                        (hasher_constructor_t)sha1_hasher_create);
-       lib->crypto->add_hasher(lib->crypto, HASH_SHA1_NOFINAL,
-                                                       (hasher_constructor_t)sha1_hasher_create);
+       lib->crypto->add_prf(lib->crypto, PRF_KEYED_SHA1,
+                                                       (prf_constructor_t)sha1_keyed_prf_create);
        
        return &this->public.plugin;
 }