diff options
author | Romain Francoise <rfrancoise@debian.org> | 2014-04-15 19:34:32 +0200 |
---|---|---|
committer | Romain Francoise <rfrancoise@debian.org> | 2014-04-15 19:34:32 +0200 |
commit | c5ebfc7b9c16551fe825dc1d79c3f7e2f096f6c9 (patch) | |
tree | d4e2118cbd411caa1a0528eac831030109bc6e65 /src/libstrongswan/plugins/ntru/ntru_public_key.c | |
parent | 15fb7904f4431a6e7c305fd08732458f7f885e7e (diff) | |
download | vyos-strongswan-c5ebfc7b9c16551fe825dc1d79c3f7e2f096f6c9.tar.gz vyos-strongswan-c5ebfc7b9c16551fe825dc1d79c3f7e2f096f6c9.zip |
Import upstream version 5.1.3
Diffstat (limited to 'src/libstrongswan/plugins/ntru/ntru_public_key.c')
-rw-r--r-- | src/libstrongswan/plugins/ntru/ntru_public_key.c | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/src/libstrongswan/plugins/ntru/ntru_public_key.c b/src/libstrongswan/plugins/ntru/ntru_public_key.c new file mode 100644 index 000000000..a2ff1b2b0 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_public_key.c @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * Copyright (C) 2009-2013 Security Innovation + * + * 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_public_key.h" +#include "ntru_trits.h" +#include "ntru_poly.h" +#include "ntru_convert.h" + +#include <utils/debug.h> +#include <utils/test.h> + +typedef struct private_ntru_public_key_t private_ntru_public_key_t; + +/** + * Private data of an ntru_public_key_t object. + */ +struct private_ntru_public_key_t { + /** + * Public ntru_public_key_t interface. + */ + ntru_public_key_t public; + + /** + * NTRU Parameter Set + */ + ntru_param_set_t *params; + + /** + * Polynomial h which is the public key + */ + uint16_t *pubkey; + + /** + * Encoding of the public key + */ + chunk_t encoding; + + /** + * Deterministic Random Bit Generator + */ + ntru_drbg_t *drbg; + +}; + +METHOD(ntru_public_key_t, get_id, ntru_param_set_id_t, + private_ntru_public_key_t *this) +{ + return this->params->id; +} + +/** + * Generate NTRU encryption public key encoding + */ +static void generate_encoding(private_ntru_public_key_t *this) +{ + size_t pubkey_len; + u_char *enc; + + /* compute public key length encoded as packed coefficients */ + pubkey_len = (this->params->N * this->params->q_bits + 7) / 8; + + /* allocate memory for public key encoding */ + this->encoding = chunk_alloc(2 + NTRU_OID_LEN + pubkey_len); + enc = this->encoding.ptr; + + /* format header and packed public key */ + *enc++ = NTRU_PUBKEY_TAG; + *enc++ = NTRU_OID_LEN; + memcpy(enc, this->params->oid, NTRU_OID_LEN); + enc += NTRU_OID_LEN; + ntru_elements_2_octets(this->params->N, this->pubkey, + this->params->q_bits, enc); +} + +METHOD(ntru_public_key_t, get_encoding, chunk_t, + private_ntru_public_key_t *this) +{ + return this->encoding; +} + +#define MAX_SEC_STRENGTH_LEN 32 /* bytes */ + +/** + * Shared with ntru_private_key.c + */ +extern bool ntru_check_min_weight(uint16_t N, uint8_t *t, uint16_t min_wt); + +METHOD(ntru_public_key_t, encrypt, bool, + private_ntru_public_key_t *this, chunk_t plaintext, chunk_t *ciphertext) +{ + hash_algorithm_t hash_algid; + size_t t_len, seed1_len, seed2_len; + uint16_t *t1, *t = NULL; + uint8_t b[MAX_SEC_STRENGTH_LEN]; + uint8_t *t2, *Mtrin, *M, *mask_trits, *ptr; + uint16_t mod_q_mask, mprime_len = 0; + int16_t m1 = 0; + chunk_t seed = chunk_empty; + ntru_trits_t *mask; + ntru_poly_t *r_poly; + bool msg_rep_good, success = FALSE; + int i; + + *ciphertext = chunk_empty; + + if (plaintext.len > this->params->m_len_max) + { + DBG1(DBG_LIB, "plaintext exceeds maximum size"); + return FALSE; + } + + if (this->params->sec_strength_len > MAX_SEC_STRENGTH_LEN) + { + DBG1(DBG_LIB, "required security strength exceeds %d bits", + MAX_SEC_STRENGTH_LEN * BITS_PER_BYTE); + return FALSE; + } + + /* allocate temporary array t */ + t_len = (sizeof(uint16_t) + 3*sizeof(uint8_t)) * this->params->N; + t = malloc(t_len); + t1 = t; + t2 = (uint8_t *)(t1 + this->params->N); + Mtrin = t2 + this->params->N; + M = Mtrin + this->params->N; + + /* set hash algorithm based on security strength */ + hash_algid = (this->params->sec_strength_len <= 20) ? HASH_SHA1 : + HASH_SHA256; + /* set constants */ + mod_q_mask = this->params->q - 1; + + /* allocate memory for the larger of the two seeds */ + seed1_len = (this->params->N + 3)/4; + seed2_len = 3 + 2*this->params->sec_strength_len + plaintext.len; + seed = chunk_alloc(max(seed1_len, seed2_len)); + + /* loop until a message representative with proper weight is achieved */ + do + { + if (!this->drbg->generate(this->drbg, + this->params->sec_strength_len * BITS_PER_BYTE, + this->params->sec_strength_len, b)) + { + goto err; + } + + /* form sData (OID || m || b || hTrunc) */ + ptr = seed.ptr; + memcpy(ptr, this->params->oid, NTRU_OID_LEN); + ptr += NTRU_OID_LEN; + memcpy(ptr, plaintext.ptr, plaintext.len); + ptr += plaintext.len; + memcpy(ptr, b, this->params->sec_strength_len); + ptr += this->params->sec_strength_len; + memcpy(ptr, this->encoding.ptr + 2 + NTRU_OID_LEN, + this->params->sec_strength_len); + ptr += this->params->sec_strength_len; + seed.len = seed2_len; + + DBG2(DBG_LIB, "generate polynomial r"); + r_poly = ntru_poly_create_from_seed(hash_algid, seed, this->params->c_bits, + this->params->N, this->params->q, + this->params->dF_r, this->params->dF_r, + this->params->is_product_form); + if (!r_poly) + { + goto err; + } + + /* form R = h * r */ + r_poly->ring_mult(r_poly, this->pubkey, t1); + r_poly->destroy(r_poly); + + /* form R mod 4 */ + ntru_coeffs_mod4_2_octets(this->params->N, t1, seed.ptr); + seed.len = seed1_len; + + /* form mask */ + mask = ntru_trits_create(this->params->N, hash_algid, seed); + if (!mask) + { + DBG1(DBG_LIB, "mask creation failed"); + goto err; + } + + /* form the padded message M */ + ptr = M; + memcpy(ptr, b, this->params->sec_strength_len); + ptr += this->params->sec_strength_len; + if (this->params->m_len_len == 2) + { + *ptr++ = (uint8_t)((plaintext.len >> 8) & 0xff); + } + *ptr++ = (uint8_t)(plaintext.len & 0xff); + memcpy(ptr, plaintext.ptr, plaintext.len); + ptr += plaintext.len; + + /* add an extra zero byte in case without it the bit string + * is not a multiple of 3 bits and therefore might not be + * able to produce enough trits + */ + memset(ptr, 0, this->params->m_len_max - plaintext.len + 2); + + /* convert M to trits (Mbin to Mtrin) */ + mprime_len = this->params->N; + if (this->params->is_product_form) + { + --mprime_len; + } + ntru_bits_2_trits(M, mprime_len, Mtrin); + mask_trits = mask->get_trits(mask); + + + /* form the msg representative m' by adding Mtrin to mask, mod p */ + if (this->params->is_product_form) + { + m1 = 0; + for (i = 0; i < mprime_len; i++) + { + t2[i] = mask_trits[i] + Mtrin[i]; + if (t2[i] >= 3) + { + t2[i] -= 3; + } + if (t2[i] == 1) + { + ++m1; + } + else if (t2[i] == 2) + { + --m1; + } + } + } + else + { + for (i = 0; i < mprime_len; i++) + { + t2[i] = mask_trits[i] + Mtrin[i]; + if (t2[i] >= 3) + { + t2[i] -= 3; + } + } + } + mask->destroy(mask); + + /* check that message representative meets minimum weight + * requirements + */ + if (this->params->is_product_form) + { + msg_rep_good = (abs(m1) <= this->params->min_msg_rep_wt); + } + else + { + msg_rep_good = ntru_check_min_weight(mprime_len, t2, + this->params->min_msg_rep_wt); + } + } + while (!msg_rep_good); + + /* form ciphertext e by adding m' to R mod q */ + for (i = 0; i < mprime_len; i++) + { + if (t2[i] == 1) + { + t1[i] = (t1[i] + 1) & mod_q_mask; + } + else if (t2[i] == 2) + { + t1[i] = (t1[i] - 1) & mod_q_mask; + } + } + if (this->params->is_product_form) + { + t1[i] = (t1[i] - m1) & mod_q_mask; + } + + /* pack ciphertext */ + *ciphertext = chunk_alloc((this->params->N * this->params->q_bits + 7) / 8); + ntru_elements_2_octets(this->params->N, t1, this->params->q_bits, + ciphertext->ptr); + + memwipe(t, t_len); + success = TRUE; + +err: + /* cleanup */ + chunk_clear(&seed); + free(t); + + return success; +} +METHOD(ntru_public_key_t, destroy, void, + private_ntru_public_key_t *this) +{ + this->drbg->destroy(this->drbg); + chunk_clear(&this->encoding); + free(this->pubkey); + free(this); +} + +/* + * Described in header. + */ +ntru_public_key_t *ntru_public_key_create(ntru_drbg_t *drbg, + ntru_param_set_t *params, + uint16_t *pubkey) +{ + private_ntru_public_key_t *this; + int i; + + INIT(this, + .public = { + .get_id = _get_id, + .get_encoding = _get_encoding, + .encrypt = _encrypt, + .destroy = _destroy, + }, + .params = params, + .pubkey = malloc(params->N * sizeof(uint16_t)), + .drbg = drbg->get_ref(drbg), + ); + + for (i = 0; i < params->N; i++) + { + this->pubkey[i] = pubkey[i]; + } + + /* generate public key encoding */ + generate_encoding(this); + + return &this->public; +} + +/* + * Described in header. + */ +ntru_public_key_t *ntru_public_key_create_from_data(ntru_drbg_t *drbg, + chunk_t data) +{ + private_ntru_public_key_t *this; + size_t header_len, pubkey_packed_len; + ntru_param_set_t *params; + + header_len = 2 + NTRU_OID_LEN; + + /* check the NTRU public key header format */ + if (data.len < header_len || + data.ptr[0] != NTRU_PUBKEY_TAG || + data.ptr[1] != NTRU_OID_LEN) + { + DBG1(DBG_LIB, "received NTRU public key with invalid header"); + return NULL; + } + params = ntru_param_set_get_by_oid(data.ptr + 2); + + if (!params) + { + DBG1(DBG_LIB, "received NTRU public key with unknown OID"); + return NULL; + } + + pubkey_packed_len = (params->N * params->q_bits + 7) / 8; + + if (data.len < header_len + pubkey_packed_len) + { + DBG1(DBG_LIB, "received NTRU public key with wrong packed key size"); + return NULL; + } + + INIT(this, + .public = { + .get_id = _get_id, + .get_encoding = _get_encoding, + .encrypt = _encrypt, + .destroy = _destroy, + }, + .params = params, + .pubkey = malloc(params->N * sizeof(uint16_t)), + .encoding = chunk_clone(data), + .drbg = drbg->get_ref(drbg), + ); + + /* unpack the encoded public key */ + ntru_octets_2_elements(pubkey_packed_len, data.ptr + header_len, + params->q_bits, this->pubkey); + + return &this->public; +} + +EXPORT_FUNCTION_FOR_TESTS(ntru, ntru_public_key_create_from_data); |