aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2011-11-21 11:43:43 +0100
committerTobias Brunner <tobias@strongswan.org>2012-03-20 17:30:46 +0100
commitaadb9e83550ab24e393c1a0622ed117c984362a9 (patch)
treedf254beaf891dd87d0dc92152989df27f1a4aaa4
parentb05d91edd7774e3bfe99146fe9557ff6bac90469 (diff)
downloadstrongswan-aadb9e83550ab24e393c1a0622ed117c984362a9.tar.bz2
strongswan-aadb9e83550ab24e393c1a0622ed117c984362a9.tar.xz
Added a simple AEAD wrapper for IKEv1 encryption/decryption.
-rw-r--r--src/libcharon/sa/keymat_v1.c156
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);