diff options
-rw-r--r-- | src/libcharon/sa/keymat_v1.c | 156 |
1 files changed, 155 insertions, 1 deletions
diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 59791e27a..3592a3e22 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -45,6 +45,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 */ chunk_t skeyid; @@ -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); |