summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins/ntru/ntru_ke.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/ntru/ntru_ke.c')
-rw-r--r--src/libstrongswan/plugins/ntru/ntru_ke.c396
1 files changed, 396 insertions, 0 deletions
diff --git a/src/libstrongswan/plugins/ntru/ntru_ke.c b/src/libstrongswan/plugins/ntru/ntru_ke.c
new file mode 100644
index 000000000..39fb261cd
--- /dev/null
+++ b/src/libstrongswan/plugins/ntru/ntru_ke.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2013 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ntru_ke.h"
+#include "ntru_drbg.h"
+
+#include "ntru_crypto/ntru_crypto.h"
+
+#include <crypto/diffie_hellman.h>
+#include <utils/debug.h>
+
+typedef struct private_ntru_ke_t private_ntru_ke_t;
+typedef struct param_set_t param_set_t;
+
+/**
+ * Defines an NTRU parameter set by ID or OID
+ */
+struct param_set_t {
+ NTRU_ENCRYPT_PARAM_SET_ID id;
+ char oid[3];
+ char *name;
+};
+
+/* Best bandwidth and speed, no X9.98 compatibility */
+static param_set_t param_sets_optimum[] = {
+ { NTRU_EES401EP2, {0x00, 0x02, 0x10}, "ees401ep2" },
+ { NTRU_EES439EP1, {0x00, 0x03, 0x10}, "ees439ep1" },
+ { NTRU_EES593EP1, {0x00, 0x05, 0x10}, "ees593ep1" },
+ { NTRU_EES743EP1, {0x00, 0x06, 0x10}, "ees743ep1" }
+};
+
+/* X9.98/IEEE 1363.1 parameter sets for best speed */
+static param_set_t param_sets_x9_98_speed[] = {
+ { NTRU_EES659EP1, {0x00, 0x02, 0x06}, "ees659ep1" },
+ { NTRU_EES761EP1, {0x00, 0x03, 0x05}, "ees761ep1" },
+ { NTRU_EES1087EP1, {0x00, 0x05, 0x05}, "ees1087ep1" },
+ { NTRU_EES1499EP1, {0x00, 0x06, 0x05}, "ees1499ep1" }
+};
+
+/* X9.98/IEEE 1363.1 parameter sets for best bandwidth (smallest size) */
+static param_set_t param_sets_x9_98_bandwidth[] = {
+ { NTRU_EES401EP1, {0x00, 0x02, 0x04}, "ees401ep1" },
+ { NTRU_EES449EP1, {0x00, 0x03, 0x03}, "ees449ep1" },
+ { NTRU_EES677EP1, {0x00, 0x05, 0x03}, "ees677ep1" },
+ { NTRU_EES1087EP2, {0x00, 0x06, 0x03}, "ees1087ep2" }
+};
+
+/* X9.98/IEEE 1363.1 parameter sets balancing speed and bandwidth */
+static param_set_t param_sets_x9_98_balance[] = {
+ { NTRU_EES541EP1, {0x00, 0x02, 0x05}, "ees541ep1" },
+ { NTRU_EES613EP1, {0x00, 0x03, 0x04}, "ees613ep1" },
+ { NTRU_EES887EP1, {0x00, 0x05, 0x04}, "ees887ep1" },
+ { NTRU_EES1171EP1, {0x00, 0x06, 0x04}, "ees1171ep1" }
+};
+
+/**
+ * Private data of an ntru_ke_t object.
+ */
+struct private_ntru_ke_t {
+ /**
+ * Public ntru_ke_t interface.
+ */
+ ntru_ke_t public;
+
+ /**
+ * Diffie Hellman group number.
+ */
+ u_int16_t group;
+
+ /**
+ * NTRU Parameter Set
+ */
+ param_set_t *param_set;
+
+ /**
+ * Cryptographical strength in bits of the NTRU Parameter Set
+ */
+ u_int32_t strength;
+
+ /**
+ * NTRU Public Key
+ */
+ chunk_t pub_key;
+
+ /**
+ * NTRU Private Key
+ */
+ chunk_t priv_key;
+
+ /**
+ * NTRU encrypted shared secret
+ */
+ chunk_t ciphertext;
+
+ /**
+ * Shared secret
+ */
+ chunk_t shared_secret;
+
+ /**
+ * True if peer is responder
+ */
+ bool responder;
+
+ /**
+ * True if shared secret is computed
+ */
+ bool computed;
+
+ /**
+ * True Random Generator
+ */
+ rng_t *entropy;
+
+ /**
+ * Deterministic Random Bit Generator
+ */
+ ntru_drbg_t *drbg;
+};
+
+METHOD(diffie_hellman_t, get_my_public_value, void,
+ private_ntru_ke_t *this, chunk_t *value)
+{
+ uint16_t pub_key_len, priv_key_len;
+
+ *value = chunk_empty;
+
+ if (this->responder)
+ {
+ if (this->ciphertext.len)
+ {
+ *value = chunk_clone(this->ciphertext);
+ }
+ }
+ else
+ {
+ if (this->pub_key.len == 0)
+ {
+ /* determine the NTRU public and private key sizes */
+ if (ntru_crypto_ntru_encrypt_keygen(this->drbg, this->param_set->id,
+ &pub_key_len, NULL,
+ &priv_key_len, NULL) != NTRU_OK)
+ {
+ DBG1(DBG_LIB, "error determining NTRU public and private key "
+ "sizes");
+ return;
+ }
+ this->pub_key = chunk_alloc(pub_key_len);
+ this->priv_key = chunk_alloc(priv_key_len);
+
+ /* generate a random NTRU public/private key pair */
+ if (ntru_crypto_ntru_encrypt_keygen(this->drbg, this->param_set->id,
+ &pub_key_len, this->pub_key.ptr,
+ &priv_key_len, this->priv_key.ptr) != NTRU_OK)
+ {
+ DBG1(DBG_LIB, "NTRU keypair generation failed");
+ chunk_free(&this->priv_key);
+ chunk_free(&this->pub_key);
+ return;
+ }
+ DBG3(DBG_LIB, "NTRU public key: %B", &this->pub_key);
+ DBG4(DBG_LIB, "NTRU private key: %B", &this->priv_key);
+ }
+ *value = chunk_clone(this->pub_key);
+ }
+}
+
+METHOD(diffie_hellman_t, get_shared_secret, status_t,
+ private_ntru_ke_t *this, chunk_t *secret)
+{
+ if (!this->computed || !this->shared_secret.len)
+ {
+ *secret = chunk_empty;
+ return FAILED;
+ }
+ *secret = chunk_clone(this->shared_secret);
+
+ return SUCCESS;
+}
+
+
+METHOD(diffie_hellman_t, set_other_public_value, void,
+ private_ntru_ke_t *this, chunk_t value)
+{
+ u_int16_t plaintext_len, ciphertext_len;
+
+ if (this->priv_key.len)
+ {
+ /* initiator decrypting shared secret */
+ if (value.len == 0)
+ {
+ DBG1(DBG_LIB, "empty NTRU ciphertext");
+ return;
+ }
+ this->ciphertext = chunk_clone(value);
+ DBG3(DBG_LIB, "NTRU ciphertext: %B", &this->ciphertext);
+
+ /* determine the size of the maximum plaintext */
+ if (ntru_crypto_ntru_decrypt(this->priv_key.len, this->priv_key.ptr,
+ this->ciphertext.len, this->ciphertext.ptr,
+ &plaintext_len, NULL) != NTRU_OK)
+ {
+ DBG1(DBG_LIB, "error determining maximum plaintext size");
+ return;
+ }
+ this->shared_secret = chunk_alloc(plaintext_len);
+
+ /* decrypt the shared secret */
+ if (ntru_crypto_ntru_decrypt(this->priv_key.len, this->priv_key.ptr,
+ this->ciphertext.len, this->ciphertext.ptr,
+ &plaintext_len, this->shared_secret.ptr) != NTRU_OK)
+ {
+ DBG1(DBG_LIB, "NTRU decryption of shared secret failed");
+ chunk_free(&this->shared_secret);
+ return;
+ }
+ this->shared_secret.len = plaintext_len;
+ this->computed = TRUE;
+ }
+ else
+ {
+ /* responder generating and encrypting the shared secret */
+ this->responder = TRUE;
+
+ /* check the NTRU public key format */
+ if (value.len < 5 || value.ptr[0] != 1 || value.ptr[1] != 3)
+ {
+ DBG1(DBG_LIB, "received NTRU public key with invalid header");
+ return;
+ }
+ if (!memeq(value.ptr + 2, this->param_set->oid, 3))
+ {
+ DBG1(DBG_LIB, "received NTRU public key with wrong OID");
+ return;
+ }
+ this->pub_key = chunk_clone(value);
+
+ /* shared secret size is chosen as twice the cryptographical strength */
+ this->shared_secret = chunk_alloc(2 * this->strength / BITS_PER_BYTE);
+
+ /* generate the random shared secret */
+ if (!this->drbg->generate(this->drbg, this->strength,
+ this->shared_secret.len, this->shared_secret.ptr))
+ {
+ DBG1(DBG_LIB, "generation of shared secret failed");
+ chunk_free(&this->shared_secret);
+ return;
+ }
+ this->computed = TRUE;
+
+ /* determine the size of the ciphertext */
+ if (ntru_crypto_ntru_encrypt(this->drbg,
+ this->pub_key.len, this->pub_key.ptr,
+ this->shared_secret.len, this->shared_secret.ptr,
+ &ciphertext_len, NULL) != NTRU_OK)
+ {
+ DBG1(DBG_LIB, "error determining ciphertext size");
+ return;
+ }
+ this->ciphertext = chunk_alloc(ciphertext_len);
+
+ /* encrypt the shared secret */
+ if (ntru_crypto_ntru_encrypt(this->drbg,
+ this->pub_key.len, this->pub_key.ptr,
+ this->shared_secret.len, this->shared_secret.ptr,
+ &ciphertext_len, this->ciphertext.ptr) != NTRU_OK)
+ {
+ DBG1(DBG_LIB, "NTRU encryption of shared secret failed");
+ chunk_free(&this->ciphertext);
+ return;
+ }
+ DBG3(DBG_LIB, "NTRU ciphertext: %B", &this->ciphertext);
+ }
+}
+
+METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
+ private_ntru_ke_t *this)
+{
+ return this->group;
+}
+
+METHOD(diffie_hellman_t, destroy, void,
+ private_ntru_ke_t *this)
+{
+ this->drbg->destroy(this->drbg);
+ this->entropy->destroy(this->entropy);
+ chunk_free(&this->pub_key);
+ chunk_free(&this->ciphertext);
+ chunk_clear(&this->priv_key);
+ chunk_clear(&this->shared_secret);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ntru_ke_t *ntru_ke_create(diffie_hellman_group_t group, chunk_t g, chunk_t p)
+{
+ private_ntru_ke_t *this;
+ param_set_t *param_sets, *param_set;
+ rng_t *entropy;
+ ntru_drbg_t *drbg;
+ char *parameter_set;
+ u_int32_t strength;
+
+ parameter_set = lib->settings->get_str(lib->settings,
+ "%s.plugins.ntru.parameter_set", "optimum", lib->ns);
+
+ if (streq(parameter_set, "x9_98_speed"))
+ {
+ param_sets = param_sets_x9_98_speed;
+ }
+ else if (streq(parameter_set, "x9_98_bandwidth"))
+ {
+ param_sets = param_sets_x9_98_bandwidth;
+ }
+ else if (streq(parameter_set, "x9_98_balance"))
+ {
+ param_sets = param_sets_x9_98_balance;
+ }
+ else
+ {
+ param_sets = param_sets_optimum;
+ }
+
+ switch (group)
+ {
+ case NTRU_112_BIT:
+ strength = 112;
+ param_set = &param_sets[0];
+ break;
+ case NTRU_128_BIT:
+ strength = 128;
+ param_set = &param_sets[1];
+ break;
+ case NTRU_192_BIT:
+ strength = 192;
+ param_set = &param_sets[2];
+ break;
+ case NTRU_256_BIT:
+ strength = 256;
+ param_set = &param_sets[3];
+ break;
+ default:
+ return NULL;
+ }
+ DBG1(DBG_LIB, "%u bit %s NTRU parameter set %s selected", strength,
+ parameter_set, param_set->name);
+
+ entropy = lib->crypto->create_rng(lib->crypto, RNG_TRUE);
+ if (!entropy)
+ {
+ DBG1(DBG_LIB, "could not attach entropy source for DRBG");
+ return NULL;
+ }
+
+ drbg = ntru_drbg_create(strength, chunk_from_str("IKE NTRU-KE"), entropy);
+ if (!drbg)
+ {
+ DBG1(DBG_LIB, "could not instantiate DRBG at %u bit security", strength);
+ entropy->destroy(entropy);
+ return NULL;
+ }
+
+ INIT(this,
+ .public = {
+ .dh = {
+ .get_shared_secret = _get_shared_secret,
+ .set_other_public_value = _set_other_public_value,
+ .get_my_public_value = _get_my_public_value,
+ .get_dh_group = _get_dh_group,
+ .destroy = _destroy,
+ },
+ },
+ .group = group,
+ .param_set = param_set,
+ .strength = strength,
+ .entropy = entropy,
+ .drbg = drbg,
+ );
+
+ return &this->public;
+}
+