diff options
author | Martin Willi <martin@strongswan.org> | 2008-03-19 14:02:52 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2008-03-19 14:02:52 +0000 |
commit | cfede7f6e26351e9edf4a10ab40c292d2f7142bc (patch) | |
tree | 6cd01db7a5b7c71fa05e4034db086ecce5afe1ab | |
parent | c912c3d382172999be8a0827180a0cabd0f982b9 (diff) | |
download | strongswan-cfede7f6e26351e9edf4a10ab40c292d2f7142bc.tar.bz2 strongswan-cfede7f6e26351e9edf4a10ab40c292d2f7142bc.tar.xz |
The introduced SHA1_NOFINAL hasher was not sufficient for EAP-AKA,
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.
-rw-r--r-- | src/charon/plugins/eap_aka/eap_aka.c | 60 | ||||
-rw-r--r-- | src/charon/plugins/unit_tester/tests/test_fips_prf.c | 3 | ||||
-rw-r--r-- | src/libstrongswan/crypto/hashers/hasher.c | 1 | ||||
-rw-r--r-- | src/libstrongswan/crypto/hashers/hasher.h | 8 | ||||
-rw-r--r-- | src/libstrongswan/crypto/prfs/prf.c | 7 | ||||
-rw-r--r-- | src/libstrongswan/crypto/prfs/prf.h | 5 | ||||
-rw-r--r-- | src/libstrongswan/plugins/fips_prf/fips_prf.c | 31 | ||||
-rw-r--r-- | src/libstrongswan/plugins/sha1/sha1_hasher.c | 146 | ||||
-rw-r--r-- | src/libstrongswan/plugins/sha1/sha1_hasher.h | 25 | ||||
-rw-r--r-- | src/libstrongswan/plugins/sha1/sha1_plugin.c | 6 |
10 files changed, 183 insertions, 109 deletions
diff --git a/src/charon/plugins/eap_aka/eap_aka.c b/src/charon/plugins/eap_aka/eap_aka.c index 3dd842b9e..a8bef728e 100644 --- a/src/charon/plugins/eap_aka/eap_aka.c +++ b/src/charon/plugins/eap_aka/eap_aka.c @@ -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; } diff --git a/src/charon/plugins/unit_tester/tests/test_fips_prf.c b/src/charon/plugins/unit_tester/tests/test_fips_prf.c index 56ba556f5..29612143e 100644 --- a/src/charon/plugins/unit_tester/tests/test_fips_prf.c +++ b/src/charon/plugins/unit_tester/tests/test_fips_prf.c @@ -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; } diff --git a/src/libstrongswan/crypto/hashers/hasher.c b/src/libstrongswan/crypto/hashers/hasher.c index ea4b4b08b..ce208a110 100644 --- a/src/libstrongswan/crypto/hashers/hasher.c +++ b/src/libstrongswan/crypto/hashers/hasher.c @@ -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" diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h index 4aa4ba357..a374da059 100644 --- a/src/libstrongswan/crypto/hashers/hasher.h +++ b/src/libstrongswan/crypto/hashers/hasher.h @@ -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 diff --git a/src/libstrongswan/crypto/prfs/prf.c b/src/libstrongswan/crypto/prfs/prf.c index c1fa1e152..638873650 100644 --- a/src/libstrongswan/crypto/prfs/prf.c +++ b/src/libstrongswan/crypto/prfs/prf.c @@ -18,11 +18,12 @@ #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", diff --git a/src/libstrongswan/crypto/prfs/prf.h b/src/libstrongswan/crypto/prfs/prf.h index 662a95938..135d7889f 100644 --- a/src/libstrongswan/crypto/prfs/prf.h +++ b/src/libstrongswan/crypto/prfs/prf.h @@ -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, }; /** diff --git a/src/libstrongswan/plugins/fips_prf/fips_prf.c b/src/libstrongswan/plugins/fips_prf/fips_prf.c index 20b752e30..11adad086 100644 --- a/src/libstrongswan/plugins/fips_prf/fips_prf.c +++ b/src/libstrongswan/plugins/fips_prf/fips_prf.c @@ -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; diff --git a/src/libstrongswan/plugins/sha1/sha1_hasher.c b/src/libstrongswan/plugins/sha1/sha1_hasher.c index 97a2f207f..8d8e56382 100644 --- a/src/libstrongswan/plugins/sha1/sha1_hasher.c +++ b/src/libstrongswan/plugins/sha1/sha1_hasher.c @@ -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); +} + diff --git a/src/libstrongswan/plugins/sha1/sha1_hasher.h b/src/libstrongswan/plugins/sha1/sha1_hasher.h index aff0eae11..2e44797d8 100644 --- a/src/libstrongswan/plugins/sha1/sha1_hasher.h +++ b/src/libstrongswan/plugins/sha1/sha1_hasher.h @@ -23,8 +23,10 @@ #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_ @}*/ diff --git a/src/libstrongswan/plugins/sha1/sha1_plugin.c b/src/libstrongswan/plugins/sha1/sha1_plugin.c index 4a69c4e76..391664f5e 100644 --- a/src/libstrongswan/plugins/sha1/sha1_plugin.c +++ b/src/libstrongswan/plugins/sha1/sha1_plugin.c @@ -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; } |