Added a simple AEAD wrapper for IKEv1 encryption/decryption.

This commit is contained in:
Tobias Brunner
2012-03-20 17:30:46 +01:00
parent b05d91edd7
commit aadb9e8355
+155 -1
View File
@@ -44,6 +44,11 @@ struct private_keymat_v1_t {
*/
pseudo_random_function_t prf_alg;
/**
* Crypter wrapped in an aead_t interface
*/
aead_t *aead;
/**
* Key used for authentication during main mode
*/
@@ -67,6 +72,148 @@ static const chunk_t octet_0 = chunk_from_chars(0x00);
static const chunk_t octet_1 = chunk_from_chars(0x01);
static const chunk_t octet_2 = chunk_from_chars(0x02);
/**
* Simple aead_t implementation without support for authentication.
*/
typedef struct {
/** implements aead_t interface */
aead_t aead;
/** crypter to be used */
crypter_t *crypter;
} private_aead_t;
METHOD(aead_t, encrypt, void,
private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
chunk_t *encrypted)
{
this->crypter->encrypt(this->crypter, plain, iv, encrypted);
}
METHOD(aead_t, decrypt, bool,
private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
chunk_t *plain)
{
this->crypter->decrypt(this->crypter, encrypted, iv, plain);
return TRUE;
}
METHOD(aead_t, get_block_size, size_t,
private_aead_t *this)
{
return this->crypter->get_block_size(this->crypter);
}
METHOD(aead_t, get_icv_size, size_t,
private_aead_t *this)
{
return 0;
}
METHOD(aead_t, get_iv_size, size_t,
private_aead_t *this)
{
/* in order to create the messages properly we return 0 here */
return 0;
}
METHOD(aead_t, get_key_size, size_t,
private_aead_t *this)
{
return this->crypter->get_key_size(this->crypter);
}
METHOD(aead_t, set_key, void,
private_aead_t *this, chunk_t key)
{
this->crypter->set_key(this->crypter, key);
}
METHOD(aead_t, aead_destroy, void,
private_aead_t *this)
{
this->crypter->destroy(this->crypter);
free(this);
}
/**
* Expand SKEYID_e according to Appendix B in RFC 2409.
* TODO-IKEv1: verify keys (e.g. for weak keys, see Appendix B)
*/
static chunk_t expand_skeyid_e(chunk_t skeyid_e, size_t key_size, prf_t *prf)
{
size_t block_size;
chunk_t seed, ka;
int i;
if (skeyid_e.len >= key_size)
{ /* no expansion required, reduce to key_size */
skeyid_e.len = key_size;
return skeyid_e;
}
block_size = prf->get_block_size(prf);
ka = chunk_alloc((key_size / block_size + 1) * block_size);
ka.len = key_size;
/* Ka = K1 | K2 | ..., K1 = prf(SKEYID_e, 0), K2 = prf(SKEYID_e, K1) ... */
prf->set_key(prf, skeyid_e);
seed = octet_0;
for (i = 0; i < key_size; i += block_size)
{
prf->get_bytes(prf, seed, ka.ptr + i);
seed = chunk_create(ka.ptr + i, block_size);
}
chunk_clear(&skeyid_e);
return ka;
}
/**
* Create a simple implementation of the aead_t interface which only encrypts
* or decrypts data.
*/
static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e)
{
private_aead_t *this;
u_int16_t alg, key_size;
crypter_t *crypter;
chunk_t ka;
if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg,
&key_size))
{
DBG1(DBG_IKE, "no %N selected",
transform_type_names, ENCRYPTION_ALGORITHM);
return NULL;
}
crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
if (!crypter)
{
DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
transform_type_names, ENCRYPTION_ALGORITHM,
encryption_algorithm_names, alg, key_size);
return NULL;
}
key_size = crypter->get_key_size(crypter);
ka = expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf);
DBG4(DBG_IKE, "encryption key Ka %B", &ka);
crypter->set_key(crypter, ka);
chunk_clear(&ka);
INIT(this,
.aead = {
.encrypt = _encrypt,
.decrypt = _decrypt,
.get_block_size = _get_block_size,
.get_icv_size = _get_icv_size,
.get_iv_size = _get_iv_size,
.get_key_size = _get_key_size,
.set_key = _set_key,
.destroy = _aead_destroy,
},
.crypter = crypter,
);
return &this->aead;
}
/**
* Converts integrity algorithm to PRF algorithm
@@ -214,6 +361,12 @@ METHOD(keymat_v1_t, derive_ike_keys, bool,
chunk_clear(&g_xy);
this->aead = create_aead(proposal, this->prf, skeyid_e);
if (!this->aead)
{
return FALSE;
}
return TRUE;
}
@@ -226,13 +379,14 @@ METHOD(keymat_t, create_dh, diffie_hellman_t*,
METHOD(keymat_t, get_aead, aead_t*,
private_keymat_v1_t *this, bool in)
{
return NULL;
return this->aead;
}
METHOD(keymat_t, destroy, void,
private_keymat_v1_t *this)
{
DESTROY_IF(this->prf);
DESTROY_IF(this->aead);
chunk_clear(&this->skeyid);
chunk_clear(&this->skeyid_d);
chunk_clear(&this->skeyid_a);