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.
This commit is contained in:
@@ -43,25 +43,16 @@ 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)
|
||||
*/
|
||||
@@ -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;
|
||||
|
||||
@@ -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. *
|
||||
*/
|
||||
@@ -196,19 +207,6 @@ static void reset(private_sha1_hasher_t *this)
|
||||
this->count[1] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -37,14 +39,31 @@ struct sha1_hasher_t {
|
||||
hasher_t hasher_interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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_ @}*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user