Added a simple AEAD wrapper for IKEv1 encryption/decryption.
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user