diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2013-11-18 21:11:03 +0100 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2013-11-27 20:21:40 +0100 |
commit | 146ad86be5817ec7cdd0996c3764601f94b3ef8c (patch) | |
tree | 4b5253b5f7c1ab121ed8a5d9bb5b727d1d54f349 | |
parent | e9b49d412b3f226ac4701cb1e9525b77f4693f82 (diff) | |
download | strongswan-146ad86be5817ec7cdd0996c3764601f94b3ef8c.tar.bz2 strongswan-146ad86be5817ec7cdd0996c3764601f94b3ef8c.tar.xz |
Prototype implementation of IKE key exchange via NTRU encryption
42 files changed, 9386 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac index 054870d46..a3fb71274 100644 --- a/configure.ac +++ b/configure.ac @@ -239,6 +239,7 @@ ARG_ENABL_SET([pkcs11], [enables the PKCS11 token support plugin.]) ARG_ENABL_SET([ctr], [enables the Counter Mode wrapper crypto plugin.]) ARG_ENABL_SET([ccm], [enables the CCM AEAD wrapper crypto plugin.]) ARG_ENABL_SET([gcm], [enables the GCM AEAD wrapper crypto plugin.]) +ARG_ENABL_SET([ntru], [enables the NTRU crypto plugin.]) ARG_ENABL_SET([addrblock], [enables RFC 3779 address block constraint support.]) ARG_ENABL_SET([unity], [enables Cisco Unity extension plugin.]) ARG_ENABL_SET([uci], [enable OpenWRT UCI configuration plugin.]) @@ -1033,6 +1034,7 @@ ADD_PLUGIN([hmac], [s charon scripts nm cmd]) ADD_PLUGIN([ctr], [s charon scripts nm cmd]) ADD_PLUGIN([ccm], [s charon scripts nm cmd]) ADD_PLUGIN([gcm], [s charon scripts nm cmd]) +ADD_PLUGIN([ntru], [s charon scripts nm cmd]) ADD_PLUGIN([attr], [h charon]) ADD_PLUGIN([attr-sql], [h charon]) ADD_PLUGIN([load-tester], [c charon]) @@ -1170,6 +1172,7 @@ AM_CONDITIONAL(USE_CTR, test x$ctr = xtrue) AM_CONDITIONAL(USE_CCM, test x$ccm = xtrue) AM_CONDITIONAL(USE_GCM, test x$gcm = xtrue) AM_CONDITIONAL(USE_AF_ALG, test x$af_alg = xtrue) +AM_CONDITIONAL(USE_NTRU, test x$ntru = xtrue) # charon plugins # ---------------- @@ -1375,6 +1378,7 @@ AC_CONFIG_FILES([ src/libstrongswan/plugins/ccm/Makefile src/libstrongswan/plugins/gcm/Makefile src/libstrongswan/plugins/af_alg/Makefile + src/libstrongswan/plugins/ntru/Makefile src/libstrongswan/plugins/test_vectors/Makefile src/libstrongswan/tests/Makefile src/libhydra/Makefile diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 63603bfe9..0b2bbffff 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -481,6 +481,13 @@ if MONOLITHIC endif endif +if USE_NTRU + SUBDIRS += plugins/ntru +if MONOLITHIC + libstrongswan_la_LIBADD += plugins/ntru/libstrongswan-ntru.la +endif +endif + if USE_TEST_VECTORS SUBDIRS += plugins/test_vectors if MONOLITHIC diff --git a/src/libstrongswan/asn1/oid.txt b/src/libstrongswan/asn1/oid.txt index 740dc5073..c15a1cc2a 100644 --- a/src/libstrongswan/asn1/oid.txt +++ b/src/libstrongswan/asn1/oid.txt @@ -93,6 +93,7 @@ 0x04 "md5WithRSAEncryption" OID_MD5_WITH_RSA 0x05 "sha-1WithRSAEncryption" OID_SHA1_WITH_RSA 0x07 "id-RSAES-OAEP" OID_RSAES_OAEP + 0x08 "id-mgf1" 0x09 "id-pSpecified" 0x0B "sha256WithRSAEncryption" OID_SHA256_WITH_RSA 0x0C "sha384WithRSAEncryption" OID_SHA384_WITH_RSA @@ -211,6 +212,29 @@ 0x02 "" 0x02 "" 0x4B "TCGID" OID_TCGID + 0xc1 "" + 0x16 "ntruCryptosystems" + 0x01 "eess" + 0x01 "eess1" + 0x01 "eess1-algs" + 0x01 "ntru-EESS1v1-SVES" + 0x02 "ntru-EESS1v1-SVSSA" + 0x03 "ntru-EESS1v1-NTRUSign" + 0x02 "eess1-params" + 0x01 "ees251ep1" + 0x02 "ees347ep1" + 0x03 "ees503ep1" + 0x07 "ees251sp2" + 0x0C "ees251ep4" + 0x0D "ees251ep5" + 0x0E "ees251sp3" + 0x0F "ees251sp4" + 0x10 "ees251sp5" + 0x11 "ees251sp6" + 0x12 "ees251sp7" + 0x13 "ees251sp8" + 0x14 "ees251sp9" + 0x03 "eess1-encodingMethods" 0x05 "security" 0x05 "mechanisms" 0x07 "id-pkix" diff --git a/src/libstrongswan/crypto/diffie_hellman.c b/src/libstrongswan/crypto/diffie_hellman.c index 3d319d2d4..f71ebc671 100644 --- a/src/libstrongswan/crypto/diffie_hellman.c +++ b/src/libstrongswan/crypto/diffie_hellman.c @@ -45,7 +45,12 @@ ENUM_NEXT(diffie_hellman_group_names, MODP_1024_160, ECP_512_BP, ECP_521_BIT, ENUM_NEXT(diffie_hellman_group_names, MODP_NULL, MODP_CUSTOM, ECP_512_BP, "MODP_NULL", "MODP_CUSTOM"); -ENUM_END(diffie_hellman_group_names, MODP_CUSTOM); +ENUM_NEXT(diffie_hellman_group_names, NTRU_112_BIT, NTRU_256_BIT, MODP_CUSTOM, + "NTRU_112", + "NTRU_128", + "NTRU_192", + "NTRU_256"); +ENUM_END(diffie_hellman_group_names, NTRU_256_BIT); /** diff --git a/src/libstrongswan/crypto/diffie_hellman.h b/src/libstrongswan/crypto/diffie_hellman.h index edf6bbd6d..00d700314 100644 --- a/src/libstrongswan/crypto/diffie_hellman.h +++ b/src/libstrongswan/crypto/diffie_hellman.h @@ -64,6 +64,11 @@ enum diffie_hellman_group_t { MODP_NULL = 1024, /** MODP group with custom generator/prime */ MODP_CUSTOM = 1025, + /** Parameters defined by IEEE 1363.1, in PRIVATE USE */ + NTRU_112_BIT = 1030, + NTRU_128_BIT = 1031, + NTRU_192_BIT = 1032, + NTRU_256_BIT = 1033 }; /** diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt b/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt index c484320ca..70e79157a 100644 --- a/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt +++ b/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt @@ -1,7 +1,7 @@ %{ /* - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil, Switzerland + * Copyright (C) 2009-2013 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil, Switzerland * * 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 @@ -161,5 +161,9 @@ ecp224bp, DIFFIE_HELLMAN_GROUP, ECP_224_BP, 0 ecp256bp, DIFFIE_HELLMAN_GROUP, ECP_256_BP, 0 ecp384bp, DIFFIE_HELLMAN_GROUP, ECP_384_BP, 0 ecp512bp, DIFFIE_HELLMAN_GROUP, ECP_512_BP, 0 +ntru112, DIFFIE_HELLMAN_GROUP, NTRU_112_BIT, 0 +ntru128, DIFFIE_HELLMAN_GROUP, NTRU_128_BIT, 0 +ntru192, DIFFIE_HELLMAN_GROUP, NTRU_192_BIT, 0 +ntru256, DIFFIE_HELLMAN_GROUP, NTRU_256_BIT, 0 noesn, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0 esn, EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS, 0 diff --git a/src/libstrongswan/plugins/ntru/Makefile.am b/src/libstrongswan/plugins/ntru/Makefile.am new file mode 100644 index 000000000..67f4a57ee --- /dev/null +++ b/src/libstrongswan/plugins/ntru/Makefile.am @@ -0,0 +1,39 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = \ + -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-ntru.la +else +plugin_LTLIBRARIES = libstrongswan-ntru.la +endif + +libstrongswan_ntru_la_SOURCES = \ + ntru_plugin.h ntru_plugin.c \ + ntru_ke.h ntru_ke.c \ + ntru_crypto/ntru_crypto.h ntru_crypto/ntru_crypto_error.h \ + ntru_crypto/ntru_crypto_drbg.h ntru_crypto/ntru_crypto_drbg.c \ + ntru_crypto/ntru_crypto_hash_basics.h \ + ntru_crypto/ntru_crypto_hash.h ntru_crypto/ntru_crypto_hash.c \ + ntru_crypto/ntru_crypto_hmac.h ntru_crypto/ntru_crypto_hmac.c \ + ntru_crypto/ntru_crypto_msbyte_uint32.h \ + ntru_crypto/ntru_crypto_msbyte_uint32.c \ + ntru_crypto/ntru_crypto_ntru_convert.h \ + ntru_crypto/ntru_crypto_ntru_convert.c \ + ntru_crypto/ntru_crypto_ntru_encrypt.c \ + ntru_crypto/ntru_crypto_ntru_encrypt_key.h \ + ntru_crypto/ntru_crypto_ntru_encrypt_key.c \ + ntru_crypto/ntru_crypto_ntru_encrypt_param_sets.h \ + ntru_crypto/ntru_crypto_ntru_encrypt_param_sets.c \ + ntru_crypto/ntru_crypto_ntru_mgf1.h ntru_crypto/ntru_crypto_ntru_mgf1.c \ + ntru_crypto/ntru_crypto_ntru_poly.h ntru_crypto/ntru_crypto_ntru_poly.c \ + ntru_crypto/ntru_crypto_platform.h ntru_crypto/ntru_crypto_sha.h\ + ntru_crypto/ntru_crypto_sha1.h ntru_crypto/ntru_crypto_sha1.c\ + ntru_crypto/ntru_crypto_sha2.h ntru_crypto/ntru_crypto_sha2.c\ + ntru_crypto/ntru_crypto_sha256.h ntru_crypto/ntru_crypto_sha256.c + +libstrongswan_ntru_la_LDFLAGS = -module -avoid-version + + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto.h new file mode 100644 index 000000000..bb0f4b382 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto.h @@ -0,0 +1,337 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + + +/****************************************************************************** + * + * File: ntru_crypto.h + * + * Contents: Public header file for NTRUEncrypt. + * + *****************************************************************************/ + +#ifndef NTRU_CRYPTO_H +#define NTRU_CRYPTO_H + +#include "ntru_crypto_platform.h" +#include "ntru_crypto_drbg.h" +#include "ntru_crypto_error.h" + +#if !defined( NTRUCALL ) + #if !defined(WIN32) || defined (NTRUCRYPTO_STATIC) + // Linux, or a Win32 static library + #define NTRUCALL extern uint32_t + #elif defined (NTRUCRYPTO_EXPORTS) + // Win32 DLL build + #define NTRUCALL extern __declspec(dllexport) uint32_t + #else + // Win32 DLL import + #define NTRUCALL extern __declspec(dllimport) uint32_t + #endif +#endif /* NTRUCALL */ + +#if defined ( __cplusplus ) +extern "C" { +#endif /* __cplusplus */ + + +/* parameter set ID list */ + +typedef enum _NTRU_ENCRYPT_PARAM_SET_ID { + NTRU_EES401EP1, + NTRU_EES449EP1, + NTRU_EES677EP1, + NTRU_EES1087EP2, + NTRU_EES541EP1, + NTRU_EES613EP1, + NTRU_EES887EP1, + NTRU_EES1171EP1, + NTRU_EES659EP1, + NTRU_EES761EP1, + NTRU_EES1087EP1, + NTRU_EES1499EP1, + NTRU_EES401EP2, + NTRU_EES439EP1, + NTRU_EES593EP1, + NTRU_EES743EP1, +} NTRU_ENCRYPT_PARAM_SET_ID; + + +/* error codes */ + +#define NTRU_OK 0 +#define NTRU_FAIL 1 +#define NTRU_BAD_PARAMETER 2 +#define NTRU_BAD_LENGTH 3 +#define NTRU_BUFFER_TOO_SMALL 4 +#define NTRU_INVALID_PARAMETER_SET 5 +#define NTRU_BAD_PUBLIC_KEY 6 +#define NTRU_BAD_PRIVATE_KEY 7 +#define NTRU_OUT_OF_MEMORY 8 +#define NTRU_BAD_ENCODING 9 +#define NTRU_OID_NOT_RECOGNIZED 10 + +#define NTRU_RESULT(r) ((uint32_t)((r) ? NTRU_ERROR_BASE + (r) : (r))) +#define NTRU_RET(r) return NTRU_RESULT((r)) + + +/* function declarations */ + +/* ntru_crypto_ntru_encrypt + * + * Implements NTRU encryption (SVES) for the parameter set specified in + * the public key blob. + * + * Before invoking this function, a DRBG must be instantiated using + * ntru_crypto_drbg_instantiate() to obtain a DRBG handle, and in that + * instantiation the requested security strength must be at least as large + * as the security strength of the NTRU parameter set being used. + * Failure to instantiate the DRBG with the proper security strength will + * result in this function returning DRBG_ERROR_BASE + DRBG_BAD_LENGTH. + * + * The required minimum size of the output ciphertext buffer (ct) may be + * queried by invoking this function with ct = NULL. In this case, no + * encryption is performed, NTRU_OK is returned, and the required minimum + * size for ct is returned in ct_len. + * + * When ct != NULL, at invocation *ct_len must be the size of the ct buffer. + * Upon return it is the actual size of the ciphertext. + * + * Returns NTRU_OK if successful. + * Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if the DRBG handle is invalid. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PARAMETER if an argument pointer + * (other than ct) is NULL. + * Returns NTRU_ERROR_BASE + NTRU_BAD_LENGTH if a length argument + * (pubkey_blob_len or pt_len) is zero, or if pt_len exceeds the + * maximum plaintext length for the parameter set. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PUBLIC_KEY if the public-key blob is + * invalid (unknown format, corrupt, bad length). + * Returns NTRU_ERROR_BASE + NTRU_BUFFER_TOO_SMALL if the ciphertext buffer + * is too small. + * Returns NTRU_ERROR_BASE + NTRU_NO_MEMORY if memory needed cannot be + * allocated from the heap. + */ + +NTRUCALL +ntru_crypto_ntru_encrypt( + DRBG_HANDLE drbg_handle, /* in - handle for DRBG */ + uint16_t pubkey_blob_len, /* in - no. of octets in public key + blob */ + uint8_t const *pubkey_blob, /* in - pointer to public key */ + uint16_t pt_len, /* in - no. of octets in plaintext */ + uint8_t const *pt, /* in - pointer to plaintext */ + uint16_t *ct_len, /* in/out - no. of octets in ct, addr for + no. of octets in ciphertext */ + uint8_t *ct); /* out - address for ciphertext */ + + +/* ntru_crypto_ntru_decrypt + * + * Implements NTRU decryption (SVES) for the parameter set specified in + * the private key blob. + * + * The maximum size of the output plaintext may be queried by invoking + * this function with pt = NULL. In this case, no decryption is performed, + * NTRU_OK is returned, and the maximum size the plaintext could be is + * returned in pt_len. + * Note that until the decryption is performed successfully, the actual size + * of the resulting plaintext cannot be known. + * + * When pt != NULL, at invocation *pt_len must be the size of the pt buffer. + * Upon return it is the actual size of the plaintext. + * + * Returns NTRU_OK if successful. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PARAMETER if an argument pointer + * (other than pt) is NULL. + * Returns NTRU_ERROR_BASE + NTRU_BAD_LENGTH if a length argument + * (privkey_blob) is zero, or if ct_len is invalid for the parameter set. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PRIVATE_KEY if the private-key blob is + * invalid (unknown format, corrupt, bad length). + * Returns NTRU_ERROR_BASE + NTRU_BUFFER_TOO_SMALL if the plaintext buffer + * is too small. + * Returns NTRU_ERROR_BASE + NTRU_NO_MEMORY if memory needed cannot be + * allocated from the heap. + * Returns NTRU_ERROR_BASE + NTRU_FAIL if a decryption error occurs. + */ + +NTRUCALL +ntru_crypto_ntru_decrypt( + uint16_t privkey_blob_len, /* in - no. of octets in private key + blob */ + uint8_t const *privkey_blob, /* in - pointer to private key */ + uint16_t ct_len, /* in - no. of octets in ciphertext */ + uint8_t const *ct, /* in - pointer to ciphertext */ + uint16_t *pt_len, /* in/out - no. of octets in pt, addr for + no. of octets in plaintext */ + uint8_t *pt); /* out - address for plaintext */ + + +/* ntru_crypto_ntru_encrypt_keygen + * + * Implements key generation for NTRUEncrypt for the parameter set specified. + * + * Before invoking this function, a DRBG must be instantiated using + * ntru_crypto_drbg_instantiate() to obtain a DRBG handle, and in that + * instantiation the requested security strength must be at least as large + * as the security strength of the NTRU parameter set being used. + * Failure to instantiate the DRBG with the proper security strength will + * result in this function returning DRBG_ERROR_BASE + DRBG_BAD_LENGTH. + * + * The required minimum size of the output public-key buffer (pubkey_blob) + * may be queried by invoking this function with pubkey_blob = NULL. + * In this case, no key generation is performed, NTRU_OK is returned, and + * the required minimum size for pubkey_blob is returned in pubkey_blob_len. + * + * The required minimum size of the output private-key buffer (privkey_blob) + * may be queried by invoking this function with privkey_blob = NULL. + * In this case, no key generation is performed, NTRU_OK is returned, and + * the required minimum size for privkey_blob is returned in privkey_blob_len. + * + * The required minimum sizes of both pubkey_blob and privkey_blob may be + * queried as described above, in a single invocation of this function. + * + * When pubkey_blob != NULL and privkey_blob != NULL, at invocation + * *pubkey_blob_len must be the size of the pubkey_blob buffer and + * *privkey_blob_len must be the size of the privkey_blob buffer. + * Upon return, *pubkey_blob_len is the actual size of the public-key blob + * and *privkey_blob_len is the actual size of the private-key blob. + * + * Returns NTRU_OK if successful. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PARAMETER if an argument pointer + * (other than pubkey_blob or privkey_blob) is NULL. + * Returns NTRU_ERROR_BASE + NTRU_INVALID_PARAMETER_SET if the parameter-set + * ID is invalid. + * Returns NTRU_ERROR_BASE + NTRU_BAD_LENGTH if a length argument is invalid. + * Returns NTRU_ERROR_BASE + NTRU_BUFFER_TOO_SMALL if either the pubkey_blob + * buffer or the privkey_blob buffer is too small. + * Returns NTRU_ERROR_BASE + NTRU_NO_MEMORY if memory needed cannot be + * allocated from the heap. + * Returns NTRU_ERROR_BASE + NTRU_FAIL if the polynomial generated for f is + * not invertible in (Z/qZ)[X]/(X^N - 1), which is extremely unlikely. + * Should this occur, this function should simply be invoked again. + */ + +NTRUCALL +ntru_crypto_ntru_encrypt_keygen( + DRBG_HANDLE drbg_handle, /* in - handle of DRBG */ + NTRU_ENCRYPT_PARAM_SET_ID param_set_id, /* in - parameter set ID */ + uint16_t *pubkey_blob_len, /* in/out - no. of octets in + pubkey_blob, addr + for no. of octets + in pubkey_blob */ + uint8_t *pubkey_blob, /* out - address for + public key blob */ + uint16_t *privkey_blob_len, /* in/out - no. of octets in + privkey_blob, addr + for no. of octets + in privkey_blob */ + uint8_t *privkey_blob); /* out - address for + private key blob */ + + +/* ntru_crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo + * + * DER-encodes an NTRUEncrypt public-key from a public-key blob into a + * SubjectPublicKeyInfo field for inclusion in an X.509 certificate. + * + * The required minimum size of the output SubjectPublicKeyInfo buffer + * (encoded_subjectPublicKeyInfo) may be queried by invoking this function + * with encoded_subjectPublicKeyInfo = NULL. In this case, no encoding is + * performed, NTRU_OK is returned, and the required minimum size for + * encoded_subjectPublicKeyInfo is returned in encoded_subjectPublicKeyInfo_len. + * + * When encoded_subjectPublicKeyInfo != NULL, at invocation + * *encoded_subjectPublicKeyInfo_len must be the size of the + * encoded_subjectPublicKeyInfo buffer. + * Upon return, it is the actual size of the encoded public key. + * + * Returns NTRU_OK if successful. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PARAMETER if an argument pointer + * (other than encoded_subjectPublicKeyInfo) is NULL. + * Returns NTRU_ERROR_BASE + NTRU_BAD_LENGTH if pubkey_blob_len is zero. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PUBLIC_KEY if the public-key blob is + * invalid (unknown format, corrupt, bad length). + * Returns NTRU_ERROR_BASE + NTRU_BUFFER_TOO_SMALL if the SubjectPublicKeyInfo + * buffer is too small. + */ + +NTRUCALL +ntru_crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( + uint16_t pubkey_blob_len, /* in - no. of octets in public-key + blob */ + uint8_t const *pubkey_blob, /* in - ptr to public-key blob */ + uint16_t *encoded_subjectPublicKeyInfo_len, + /* in/out - no. of octets in encoded info, + address for no. of octets in + encoded info */ + uint8_t *encoded_subjectPublicKeyInfo); + /* out - address for encoded info */ + + +/* ntru_crypto_ntru_encrypt_SubjectPublicKeyInfo2PublicKey + * + * Decodes a DER-encoded NTRUEncrypt public-key from a + * SubjectPublicKeyInfo field in an X.509 certificate and returns the + * public-key blob itself. + * + * The required minimum size of the output public-key buffer (pubkey_blob) + * may be queried by invoking this function with pubkey_blob = NULL. + * In this case, no decoding is performed, NTRU_OK is returned, and the + * required minimum size for pubkey_blob is returned in pubkey_blob_len. + * + * When pubkey_blob != NULL, at invocation *pubkey_blob_len must be the + * size of the pubkey_blob buffer. + * Upon return, it is the actual size of the public-key blob. + * + * Returns NTRU_OK if successful. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PARAMETER if an argument pointer + * (other than pubkey_blob) is NULL. + * Returns NTRU_ERROR_BASE + NTRU_BAD_ENCODING if the encoded data is + * an invalid encoding of an NTRU public key. + * Returns NTRU_ERROR_BASE + NTRU_OID_NOT_RECOGNIZED if the + * encoded data contains an OID that identifies an object other than + * an NTRU public key. + * Returns NTRU_ERROR_BASE + NTRU_BUFFER_TOO_SMALL if the pubkey_blob buffer + * is too small. + */ + +NTRUCALL +ntru_crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey( + uint8_t const *encoded_data, /* in - ptr to subjectPublicKeyInfo + in the encoded data */ + uint16_t *pubkey_blob_len, /* in/out - no. of octets in pubkey blob, + address for no. of octets in + pubkey blob */ + uint8_t *pubkey_blob, /* out - address for pubkey blob */ + uint8_t **next); /* out - address for ptr to encoded + data following the + subjectPublicKeyInfo */ + + +#if defined ( __cplusplus ) +} +#endif /* __cplusplus */ + + +#endif /* NTRU_CRYPTO_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_drbg.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_drbg.c new file mode 100644 index 000000000..7f5a7c872 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_drbg.c @@ -0,0 +1,724 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_drbg.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_drbg.c + * + * Contents: Implementation of a SHA-256 HMAC-based deterministic random byte + * generator (HMAC_DRBG) as defined in ANSI X9.82, Part 3 - 2007. + * + * This implementation: + * - allows for MAX_INSTANTIATIONS simultaneous drbg instantiations + * (may be overridden on compiler command line) + * - has a maximum security strength of 256 bits + * - automatically uses SHA-256 for all security strengths + * - allows a personalization string of up to MAX_PERS_STR_BYTES bytes + * - implments reseeding + * - does not implement additional input for reseeding or generation + * - does not implement predictive resistance + * - limits the number of bytes requested in one invocation of generate to + * MAX_BYTES_PER_REQUEST + * - uses a callback function to allow the caller to supply the + * Get_entropy_input routine (entropy function) + * - limits the number of bytes returned from the entropy function to + * MAX_ENTROPY_NONCE_BYTES + * - gets the nonce bytes along with the entropy input from the entropy + * function + * - automatically reseeds an instantitation after MAX_REQUESTS calls to + * generate + * + *****************************************************************************/ + + +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "ntru_crypto_drbg.h" +#include "ntru_crypto_hmac.h" + + +/************************ + * HMAC_DRBG parameters * + ************************/ + +/* Note: nonce size is sec_strength_bits/2 */ +#define HMAC_DRBG_MAX_MIN_ENTROPY_NONCE_BYTES \ + (DRBG_MAX_SEC_STRENGTH_BITS + DRBG_MAX_SEC_STRENGTH_BITS/2)/8 +#define HMAC_DRBG_MAX_ENTROPY_NONCE_BYTES \ + HMAC_DRBG_MAX_MIN_ENTROPY_NONCE_BYTES * DRBG_MAX_BYTES_PER_BYTE_OF_ENTROPY +#define HMAC_DRBG_MAX_REQUESTS 0xffffffff + + +/******************* + * DRBG structures * + *******************/ + +/* SHA256_HMAC_DRBG state structure */ + +typedef struct { + uint32_t sec_strength; /* security strength in bits */ + uint32_t requests_left; /* generation requests remaining + before reseeding */ + ENTROPY_FN entropy_fn; /* pointer to entropy function */ + NTRU_CRYPTO_HMAC_CTX *hmac_ctx; /* pointer to HMAC context */ + uint8_t V[33]; /* md_len size internal state + 1 */ +} SHA256_HMAC_DRBG_STATE; + + +/* DRBG state structure + * Note: this could contain a DRBG_TYPE to direct allocation, instantiation, + * and generation to multiple types of DRBGs; at present only the + * SHA256_HMAC_DRBG is implemented + */ + +typedef struct { + uint32_t handle; + void *state; +} DRBG_STATE; + + +/************* + * DRBG DATA * + *************/ + +/* array of drbg states */ + +static DRBG_STATE drbg_state[DRBG_MAX_INSTANTIATIONS]; + + +/****************************** + * SHA256 HMAC_DRBG functions * + ******************************/ + +/* sha256_hmac_drbg_update + * + * This routine is the SHA-256 HMAC_DRBG derivation function for + * instantiation, and reseeding, and it is used in generation as well. + * It updates the internal state. + * + * For instantiation, provided_data1 holds the entropy input and nonce; + * provided_data2 holds the optional personalization string. Combined, this + * is the seed material. + * + * For reseeding, provided_data1 holds the entropy input; + * provided_data2 is NULL (because this implementation does not support + * additional input). + * + * For byte generation, both provided_data1 and provided_data2 are NULL. + * + * Returns DRBG_OK if successful. + * Returns HMAC errors if they occur. + */ + +static uint32_t +sha256_hmac_drbg_update( + SHA256_HMAC_DRBG_STATE *s, + uint8_t *key, /* md_len size array */ + uint32_t md_len, + uint8_t const *provided_data1, + uint32_t provided_data1_bytes, + uint8_t const *provided_data2, + uint32_t provided_data2_bytes) +{ + uint32_t result; + + /* new key = HMAC(K, V || 0x00 [|| provided data1 [|| provided data2]] */ + + if ((result = ntru_crypto_hmac_init(s->hmac_ctx)) != NTRU_CRYPTO_HMAC_OK) + return result; + s->V[md_len] = 0x00; + if ((result = ntru_crypto_hmac_update(s->hmac_ctx, s->V, md_len + 1)) != + NTRU_CRYPTO_HMAC_OK) + return result; + if (provided_data1) { + if ((result = ntru_crypto_hmac_update(s->hmac_ctx, provided_data1, + provided_data1_bytes)) != + NTRU_CRYPTO_HMAC_OK) + return result; + if (provided_data2) { + if ((result = ntru_crypto_hmac_update(s->hmac_ctx, provided_data2, + provided_data2_bytes)) != + NTRU_CRYPTO_HMAC_OK) + return result; + } + } + if ((result = ntru_crypto_hmac_final(s->hmac_ctx, key)) != + NTRU_CRYPTO_HMAC_OK) + return result; + if ((result = ntru_crypto_hmac_set_key(s->hmac_ctx, key)) != + NTRU_CRYPTO_HMAC_OK) + return result; + + /* new V = HMAC(K, V) */ + + if ((result = ntru_crypto_hmac_init(s->hmac_ctx)) != NTRU_CRYPTO_HMAC_OK) + return result; + if ((result = ntru_crypto_hmac_update(s->hmac_ctx, s->V, md_len)) != + NTRU_CRYPTO_HMAC_OK) + return result; + if ((result = ntru_crypto_hmac_final(s->hmac_ctx, s->V)) != + NTRU_CRYPTO_HMAC_OK) + return result; + + /* if provided data exists, update K and V again */ + + if (provided_data1) { + + /* new key = HMAC(K, V || 0x01 || provided data1 [|| provided data2] */ + + if ((result = ntru_crypto_hmac_init(s->hmac_ctx)) != + NTRU_CRYPTO_HMAC_OK) + return result; + s->V[md_len] = 0x01; + if ((result = ntru_crypto_hmac_update(s->hmac_ctx, s->V, md_len + 1)) != + NTRU_CRYPTO_HMAC_OK) + return result; + if ((result = ntru_crypto_hmac_update(s->hmac_ctx, provided_data1, + provided_data1_bytes)) != + NTRU_CRYPTO_HMAC_OK) + return result; + if (provided_data2) { + if ((result = ntru_crypto_hmac_update(s->hmac_ctx, provided_data2, + provided_data2_bytes)) != + NTRU_CRYPTO_HMAC_OK) + return result; + } + if ((result = ntru_crypto_hmac_final(s->hmac_ctx, key)) != + NTRU_CRYPTO_HMAC_OK) + return result; + if ((result = ntru_crypto_hmac_set_key(s->hmac_ctx, key)) != + NTRU_CRYPTO_HMAC_OK) + return result; + + /* new V = HMAC(K, V) */ + + if ((result = ntru_crypto_hmac_init(s->hmac_ctx)) != + NTRU_CRYPTO_HMAC_OK) + return result; + if ((result = ntru_crypto_hmac_update(s->hmac_ctx, s->V, md_len)) != + NTRU_CRYPTO_HMAC_OK) + return result; + if ((result = ntru_crypto_hmac_final(s->hmac_ctx, s->V)) != + NTRU_CRYPTO_HMAC_OK) + return result; + } + + memset(key, 0, md_len); + DRBG_RET(DRBG_OK); +} + + +/* sha256_hmac_drbg_instantiate + * + * This routine allocates and initializes a SHA-256 HMAC_DRBG internal state. + * + * Returns DRBG_OK if successful. + * Returns DRBG_BAD_LENGTH if the personalization string is too long. + * Returns DRBG_OUT_OF_MEMORY if the internal state cannot be allocated. + * Returns errors from HASH or SHA256 if those errors occur. + */ + +static uint32_t +sha256_hmac_drbg_instantiate( + uint32_t sec_strength_bits, /* strength to instantiate */ + uint8_t const *pers_str, + uint32_t pers_str_bytes, + ENTROPY_FN entropy_fn, + SHA256_HMAC_DRBG_STATE **state) +{ + uint8_t entropy_nonce[HMAC_DRBG_MAX_ENTROPY_NONCE_BYTES]; + uint32_t entropy_nonce_bytes; + uint32_t min_bytes_of_entropy; + uint8_t num_bytes_per_byte_of_entropy; + uint8_t key[32]; /* array of md_len size */ + SHA256_HMAC_DRBG_STATE *s; + uint32_t result; + uint32_t i; + + /* check arguments */ + + if (pers_str_bytes > HMAC_DRBG_MAX_PERS_STR_BYTES) + DRBG_RET(DRBG_BAD_LENGTH); + + /* calculate number of bytes needed for the entropy input and nonce + * for a SHA256_HMAC_DRBG, and get them from the entropy source + */ + + if (entropy_fn(GET_NUM_BYTES_PER_BYTE_OF_ENTROPY, + &num_bytes_per_byte_of_entropy) == 0) + DRBG_RET(DRBG_ENTROPY_FAIL); + if ((num_bytes_per_byte_of_entropy == 0) || + (num_bytes_per_byte_of_entropy > + DRBG_MAX_BYTES_PER_BYTE_OF_ENTROPY)) + DRBG_RET(DRBG_ENTROPY_FAIL); + + min_bytes_of_entropy = (sec_strength_bits + sec_strength_bits/2) / 8; + entropy_nonce_bytes = min_bytes_of_entropy * num_bytes_per_byte_of_entropy; + for (i = 0; i < entropy_nonce_bytes; i++) + if (entropy_fn(GET_BYTE_OF_ENTROPY, entropy_nonce+i) == 0) + DRBG_RET(DRBG_ENTROPY_FAIL); + + /* allocate SHA256_HMAC_DRBG state */ + + s = (SHA256_HMAC_DRBG_STATE*) malloc(sizeof(SHA256_HMAC_DRBG_STATE)); + if (s == NULL) { + DRBG_RET(DRBG_OUT_OF_MEMORY); + } + + /* allocate HMAC context */ + + memset(key, 0, sizeof(key)); + if ((result = ntru_crypto_hmac_create_ctx(NTRU_CRYPTO_HASH_ALGID_SHA256, + key, sizeof(key), + &s->hmac_ctx)) != + NTRU_CRYPTO_HMAC_OK) { + free(s); + return result; + } + + /* init and update internal state */ + + memset(s->V, 0x01, sizeof(s->V)); + if ((result = sha256_hmac_drbg_update(s, key, sizeof(key), + entropy_nonce, entropy_nonce_bytes, + pers_str, pers_str_bytes)) != DRBG_OK) { + (void) ntru_crypto_hmac_destroy_ctx(s->hmac_ctx); + memset(s->V, 0, sizeof(s->V)); + free(s); + } + memset(entropy_nonce, 0, sizeof(entropy_nonce)); + + /* init instantiation parameters */ + + s->sec_strength = sec_strength_bits; + s->requests_left = HMAC_DRBG_MAX_REQUESTS; + s->entropy_fn = entropy_fn; + *state = s; + + return result; +} + + +/* sha256_hmac_drbg_free + * + * This routine frees a SHA-256 HMAC_DRBG internal state. + * + * Returns DRBG_OK if successful. + * Returns DRBG_BAD_PARAMETER if inappropriate NULL pointers are passed. + */ + +static void +sha256_hmac_drbg_free( + SHA256_HMAC_DRBG_STATE *s) +{ + if (s->hmac_ctx) { + (void) ntru_crypto_hmac_destroy_ctx(s->hmac_ctx); + } + memset(s->V, 0, sizeof(s->V)); + s->sec_strength = 0; + s->requests_left = 0; + s->entropy_fn = NULL; + free(s); +} + + +/* sha256_hmac_drbg_reseed + * + * This function reseeds an instantiated SHA256_HMAC DRBG. + * + * Returns DRBG_OK if successful. + * Returns HMAC errors if they occur. + */ + +static uint32_t +sha256_hmac_drbg_reseed( + SHA256_HMAC_DRBG_STATE *s) +{ + uint8_t entropy[HMAC_DRBG_MAX_ENTROPY_NONCE_BYTES]; + uint32_t entropy_bytes; + uint32_t min_bytes_of_entropy; + uint8_t num_bytes_per_byte_of_entropy; + uint8_t key[32]; // array of md_len size for sha256_hmac_drbg_update() + uint32_t result; + uint32_t i; + + /* calculate number of bytes needed for the entropy input + * for a SHA256_HMAC_DRBG, and get them from the entropy source + */ + + if (s->entropy_fn(GET_NUM_BYTES_PER_BYTE_OF_ENTROPY, + &num_bytes_per_byte_of_entropy) == 0) + DRBG_RET(DRBG_ENTROPY_FAIL); + if ((num_bytes_per_byte_of_entropy == 0) || + (num_bytes_per_byte_of_entropy > + DRBG_MAX_BYTES_PER_BYTE_OF_ENTROPY)) + DRBG_RET(DRBG_ENTROPY_FAIL); + + min_bytes_of_entropy = s->sec_strength / 8; + entropy_bytes = min_bytes_of_entropy * num_bytes_per_byte_of_entropy; + for (i = 0; i < entropy_bytes; i++) + if (s->entropy_fn(GET_BYTE_OF_ENTROPY, entropy+i) == 0) + DRBG_RET(DRBG_ENTROPY_FAIL); + + /* update internal state */ + + if ((result = sha256_hmac_drbg_update(s, key, sizeof(key), + entropy, entropy_bytes, NULL, 0)) != + DRBG_OK) + return result; + + /* reset request counter */ + + s->requests_left = HMAC_DRBG_MAX_REQUESTS; + DRBG_RET(DRBG_OK); +} + + +/* sha256_hmac_drbg_generate + * + * This routine generates pseudorandom bytes from a SHA256_HMAC DRBG. + * + * Returns DRBG_OK if successful. + * Returns DRBG_BAD_LENGTH if too many bytes are requested or the requested + * security strength is too large. + * Returns HMAC errors if they occur. + */ + +static uint32_t +sha256_hmac_drbg_generate( + SHA256_HMAC_DRBG_STATE *s, + uint32_t sec_strength_bits, + uint32_t num_bytes, + uint8_t *out) +{ + uint8_t key[32]; // array of md_len size for sha256_hmac_drbg_update() + uint32_t result; + + /* check if number of bytes requested exceeds the maximum allowed */ + + if (num_bytes > HMAC_DRBG_MAX_BYTES_PER_REQUEST) + DRBG_RET(DRBG_BAD_LENGTH); + + /* check if drbg has adequate security strength */ + + if (sec_strength_bits > s->sec_strength) + DRBG_RET(DRBG_BAD_LENGTH); + + /* check if max requests have been exceeded */ + + if (s->requests_left == 0) + if ((result = sha256_hmac_drbg_reseed(s)) != DRBG_OK) + return result; + + /* generate pseudorandom bytes */ + + while (num_bytes > 0) { + + /* generate md_len bytes = V = HMAC(K, V) */ + + if ((result = ntru_crypto_hmac_init(s->hmac_ctx)) != + NTRU_CRYPTO_HMAC_OK) + return result; + if ((result = ntru_crypto_hmac_update(s->hmac_ctx, s->V, + sizeof(key))) != + NTRU_CRYPTO_HMAC_OK) + return result; + if ((result = ntru_crypto_hmac_final(s->hmac_ctx, s->V)) != + NTRU_CRYPTO_HMAC_OK) + return result; + + /* copy generated bytes to output buffer */ + + if (num_bytes < sizeof(key)) { + memcpy(out, s->V, num_bytes); + num_bytes = 0; + } else { + memcpy(out, s->V, sizeof(key)); + out += sizeof(key); + num_bytes -= sizeof(key); + } + } + + /* update internal state */ + + if ((result = sha256_hmac_drbg_update(s, key, sizeof(key), + NULL, 0, NULL, 0)) != DRBG_OK) + return result; + s->requests_left--; + + DRBG_RET(DRBG_OK); +} + + +/****************** + * DRBG functions * + ******************/ + +/* drbg_get_new_drbg + * + * This routine finds an uninstantiated drbg state and returns a pointer to it. + * + * Returns a pointer to an uninstantiated drbg state if found. + * Returns NULL if all drbg states are instantiated. + */ + +static DRBG_STATE * +drbg_get_new_drbg() +{ + int i; + + for (i = 0; i < DRBG_MAX_INSTANTIATIONS; i++) { + if (drbg_state[i].state == NULL) + return drbg_state+i; + } + return NULL; +} + + +/* drbg_get_drbg + * + * This routine finds an instantiated drbg state given its handle, and returns + * a pointer to it. + * + * Returns a pointer to the drbg state if found. + * Returns NULL if the drbg state is not found. + */ + +static DRBG_STATE * +drbg_get_drbg( + DRBG_HANDLE handle) /* in/out - drbg handle */ +{ + int i; + + for (i = 0; i < DRBG_MAX_INSTANTIATIONS; i++) { + if ((drbg_state[i].handle == handle) && drbg_state[i].state) + return drbg_state+i; + } + return NULL; +} + + +/* drbg_get_new_handle + * + * This routine gets a new, unique 32-bit handle. + * + * Returns the new DRBG handle. + */ + +static DRBG_HANDLE +drbg_get_new_handle(void) +{ + DRBG_HANDLE h = 0; + + /* ensure the new handle is unique: + * if it already exists, increment it + */ + + while (drbg_get_drbg(h) != NULL) + ++h; + + return h; +} + + +/******************** + * Public functions * + ********************/ + +/* ntru_crypto_drbg_instantiate + * + * This routine instantiates a drbg with the requested security strength. + * See ANS X9.82: Part 3-2007. + * + * Returns DRBG_OK if successful. + * Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if an argument pointer is NULL. + * Returns DRBG_ERROR_BASE + DRBG_BAD_LENGTH if the security strength requested + * or the personalization string is too large. + * Returns DRBG_ERROR_BASE + DRBG_OUT_OF_MEMORY if the internal state cannot be + * allocated from the heap. + */ + +uint32_t +ntru_crypto_drbg_instantiate( + uint32_t sec_strength_bits, /* in - requested sec strength in bits */ + uint8_t const *pers_str, /* in - ptr to personalization string */ + uint32_t pers_str_bytes, /* in - no. personalization str bytes */ + ENTROPY_FN entropy_fn, /* in - pointer to entropy function */ + DRBG_HANDLE *handle) /* out - address for drbg handle */ +{ + DRBG_STATE *drbg = NULL; + SHA256_HMAC_DRBG_STATE *state = NULL; + uint32_t result; + + /* check arguments */ + + if ((!pers_str && pers_str_bytes) || !entropy_fn || !handle) + DRBG_RET(DRBG_BAD_PARAMETER); + if (sec_strength_bits > DRBG_MAX_SEC_STRENGTH_BITS) + DRBG_RET(DRBG_BAD_LENGTH); + if (pers_str && (pers_str_bytes == 0)) + pers_str = NULL; + + /* set security strength */ + + if (sec_strength_bits <= 112) { + sec_strength_bits = 112; + } else if (sec_strength_bits <= 128) { + sec_strength_bits = 128; + } else if (sec_strength_bits <= 192) { + sec_strength_bits = 192; + } else { + sec_strength_bits = 256; + } + + /* get an uninstantiated drbg */ + + if ((drbg = drbg_get_new_drbg()) == NULL) + DRBG_RET(DRBG_NOT_AVAILABLE); + + /* init entropy function */ + + if (entropy_fn(INIT, NULL) == 0) + DRBG_RET(DRBG_ENTROPY_FAIL); + + /* instantiate a SHA-256 HMAC_DRBG */ + + if ((result = sha256_hmac_drbg_instantiate(sec_strength_bits, + pers_str, pers_str_bytes, + entropy_fn, + &state)) != DRBG_OK) + return result; + + /* init drbg state */ + + drbg->handle = drbg_get_new_handle(); + drbg->state = state; + + /* return drbg handle */ + + *handle = drbg->handle; + DRBG_RET(DRBG_OK); +} + + +/* ntru_crypto_drbg_uninstantiate + * + * This routine frees a drbg given its handle. + * + * Returns DRBG_OK if successful. + * Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if handle is not valid. + */ + +uint32_t +ntru_crypto_drbg_uninstantiate( + DRBG_HANDLE handle) /* in - drbg handle */ +{ + DRBG_STATE *drbg = NULL; + + /* find the instantiated drbg */ + + if ((drbg = drbg_get_drbg(handle)) == NULL) + DRBG_RET(DRBG_BAD_PARAMETER); + + /* zero and free drbg state */ + + if (drbg->state) { + sha256_hmac_drbg_free((SHA256_HMAC_DRBG_STATE *)drbg->state); + drbg->state = NULL; + } + + drbg->handle = 0; + DRBG_RET(DRBG_OK); +} + + +/* ntru_crypto_drbg_reseed + * + * This routine reseeds an instantiated drbg. + * See ANS X9.82: Part 3-2007. + * + * Returns DRBG_OK if successful. + * Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if handle is not valid. + * Returns HMAC errors if they occur. + */ + +uint32_t +ntru_crypto_drbg_reseed( + DRBG_HANDLE handle) /* in - drbg handle */ +{ + DRBG_STATE *drbg = NULL; + + /* find the instantiated drbg */ + + if ((drbg = drbg_get_drbg(handle)) == NULL) + DRBG_RET(DRBG_BAD_PARAMETER); + + /* reseed the SHA-256 HMAC_DRBG */ + + return sha256_hmac_drbg_reseed((SHA256_HMAC_DRBG_STATE *)drbg->state); +} + + +/* ntru_crypto_drbg_generate + * + * This routine generates pseudorandom bytes using an instantiated drbg. + * If the maximum number of requests has been reached, reseeding will occur. + * See ANS X9.82: Part 3-2007. + * + * Returns DRBG_OK if successful. + * Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if handle is not valid or if + * an argument pointer is NULL. + * Returns DRBG_ERROR_BASE + DRBG_BAD_LENGTH if the security strength requested + * is too large or the number of bytes requested is zero or too large. + * Returns HMAC errors if they occur. + */ + +uint32_t +ntru_crypto_drbg_generate( + DRBG_HANDLE handle, /* in - drbg handle */ + uint32_t sec_strength_bits, /* in - requested sec strength in bits */ + uint32_t num_bytes, /* in - number of octets to generate */ + uint8_t *out) /* out - address for generated octets */ +{ + DRBG_STATE *drbg = NULL; + + /* find the instantiated drbg */ + + if ((drbg = drbg_get_drbg(handle)) == NULL) + DRBG_RET(DRBG_BAD_PARAMETER); + + /* check arguments */ + + if (!out) + DRBG_RET(DRBG_BAD_PARAMETER); + if (num_bytes == 0) + DRBG_RET(DRBG_BAD_LENGTH); + + /* generate pseudorandom output from the SHA256_HMAC_DRBG */ + + return sha256_hmac_drbg_generate((SHA256_HMAC_DRBG_STATE *)drbg->state, + sec_strength_bits, num_bytes, out); +} + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_drbg.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_drbg.h new file mode 100644 index 000000000..3f0297910 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_drbg.h @@ -0,0 +1,193 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_drbg.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + + +/****************************************************************************** + * + * File: ntru_crypto_drbg.h + * + * Contents: Public header file for ntru_crypto_drbg.c. + * + *****************************************************************************/ + + +#ifndef NTRU_CRYPTO_DRBG_H +#define NTRU_CRYPTO_DRBG_H + +#include "ntru_crypto_platform.h" +#include "ntru_crypto_error.h" + +#if !defined( NTRUCALL ) + #if !defined(WIN32) || defined (NTRUCRYPTO_STATIC) + // Linux, or a Win32 static library + #define NTRUCALL extern uint32_t + #elif defined (NTRUCRYPTO_EXPORTS) + // Win32 DLL build + #define NTRUCALL extern __declspec(dllexport) uint32_t + #else + // Win32 DLL import + #define NTRUCALL extern __declspec(dllimport) uint32_t + #endif +#endif /* NTRUCALL */ + +#if defined ( __cplusplus ) +extern "C" { +#endif /* __cplusplus */ + + +/******************* + * DRBG parameters * + *******************/ + +#if !defined(DRBG_MAX_INSTANTIATIONS) +#define DRBG_MAX_INSTANTIATIONS 4 +#endif +#define DRBG_MAX_SEC_STRENGTH_BITS 256 +#define DRBG_MAX_BYTES_PER_BYTE_OF_ENTROPY 8 + + +/************************ + * HMAC_DRBG parameters * + ************************/ + +#define HMAC_DRBG_MAX_PERS_STR_BYTES 32 +#define HMAC_DRBG_MAX_BYTES_PER_REQUEST 1024 + + +/******************** + * type definitions * + ********************/ + +typedef uint32_t DRBG_HANDLE; /* drbg handle */ +typedef enum { /* entropy-function commands */ + GET_NUM_BYTES_PER_BYTE_OF_ENTROPY = 0, + INIT, + GET_BYTE_OF_ENTROPY, +} ENTROPY_CMD; +typedef uint8_t (*ENTROPY_FN)( /* get entropy function */ + ENTROPY_CMD cmd, /* command */ + uint8_t *out); /* address for output */ + + +/*************** + * error codes * + ***************/ + +#define DRBG_OK 0x00000000 /* no errors */ +#define DRBG_OUT_OF_MEMORY 0x00000001 /* can't allocate memory */ +#define DRBG_BAD_PARAMETER 0x00000002 /* null pointer */ +#define DRBG_BAD_LENGTH 0x00000003 /* invalid no. of bytes */ +#define DRBG_NOT_AVAILABLE 0x00000004 /* no instantiation slot available */ +#define DRBG_ENTROPY_FAIL 0x00000005 /* entropy function failure */ + +/*************** + * error macro * + ***************/ + +#define DRBG_RESULT(r) ((uint32_t)((r) ? DRBG_ERROR_BASE + (r) : (r))) +#define DRBG_RET(r) return DRBG_RESULT(r); + + +/************************* + * function declarations * + *************************/ + +/* ntru_crypto_drbg_instantiate + * + * This routine instantiates a drbg with the requested security strength. + * See ANS X9.82: Part 3-2007. + * + * Returns DRBG_OK if successful. + * Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if an argument pointer is NULL. + * Returns DRBG_ERROR_BASE + DRBG_BAD_LENGTH if the security strength requested + * or the personalization string is too large. + * Returns DRBG_ERROR_BASE + DRBG_OUT_OF_MEMORY if the internal state cannot be + * allocated from the heap. + */ + +NTRUCALL +ntru_crypto_drbg_instantiate( + uint32_t sec_strength_bits, /* in - requested sec strength in bits */ + uint8_t const *pers_str, /* in - ptr to personalization string */ + uint32_t pers_str_bytes, /* in - no. personalization str bytes */ + ENTROPY_FN entropy_fn, /* in - pointer to entropy function */ + DRBG_HANDLE *handle); /* out - address for drbg handle */ + + +/* ntru_crypto_drbg_uninstantiate + * + * This routine frees a drbg given its handle. + * + * Returns DRBG_OK if successful. + * Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if handle is not valid. + */ + +NTRUCALL +ntru_crypto_drbg_uninstantiate( + DRBG_HANDLE handle); /* in - drbg handle */ + + +/* ntru_crypto_drbg_reseed + * + * This routine reseeds an instantiated drbg. + * See ANS X9.82: Part 3-2007. + * + * Returns DRBG_OK if successful. + * Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if handle is not valid. + * Returns NTRU_CRYPTO_HMAC errors if they occur. + */ + +NTRUCALL +ntru_crypto_drbg_reseed( + DRBG_HANDLE handle); /* in - drbg handle */ + + +/* ntru_crypto_drbg_generate + * + * This routine generates pseudorandom bytes using an instantiated drbg. + * If the maximum number of requests has been reached, reseeding will occur. + * See ANS X9.82: Part 3-2007. + * + * Returns DRBG_OK if successful. + * Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if handle is not valid or if + * an argument pointer is NULL. + * Returns DRBG_ERROR_BASE + DRBG_BAD_LENGTH if the security strength requested + * is too large or the number of bytes requested is zero or too large. + * Returns NTRU_CRYPTO_HMAC errors if they occur. + */ + +NTRUCALL +ntru_crypto_drbg_generate( + DRBG_HANDLE handle, /* in - drbg handle */ + uint32_t sec_strength_bits, /* in - requested sec strength in bits */ + uint32_t num_bytes, /* in - number of octets to generate */ + uint8_t *out); /* out - address for generated octets */ + + +#if defined ( __cplusplus ) +} +#endif /* __cplusplus */ + + +#endif /* NTRU_CRYPTO_DRBG_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_error.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_error.h new file mode 100644 index 000000000..daf88e76b --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_error.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_serror.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + + +/****************************************************************************** + * + * File: ntru_crypto_error.h + * + * Contents: Contains base values for crypto error codes. + * + *****************************************************************************/ + + +#ifndef NTRU_CRYPTO_ERROR_H +#define NTRU_CRYPTO_ERROR_H + +/* define base values for crypto error codes */ + +#define HASH_ERROR_BASE ((uint32_t)0x00000100) +#define HMAC_ERROR_BASE ((uint32_t)0x00000200) +#define SHA_ERROR_BASE ((uint32_t)0x00000400) +#define DRBG_ERROR_BASE ((uint32_t)0x00000a00) +#define NTRU_ERROR_BASE ((uint32_t)0x00003000) +#define MGF1_ERROR_BASE ((uint32_t)0x00004100) + +#endif /* NTRU_CRYPTO_ERROR_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hash.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hash.c new file mode 100644 index 000000000..e67bbfef0 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hash.c @@ -0,0 +1,335 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_hash.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_hash.c + * + * Contents: Routines implementing the hash object abstraction. + * + *****************************************************************************/ + + +#include <stdlib.h> +#include "ntru_crypto_hash.h" + + +typedef uint32_t (*NTRU_CRYPTO_HASH_INIT_FN)( + void *c); +typedef uint32_t (*NTRU_CRYPTO_HASH_UPDATE_FN)( + void *c, + void const *data, + uint32_t len); +typedef uint32_t (*NTRU_CRYPTO_HASH_FINAL_FN)( + void *c, + void *md); +typedef uint32_t (*NTRU_CRYPTO_HASH_DIGEST_FN)( + void const *data, + uint32_t len, + void *md); + +typedef struct _NTRU_CRYPTO_HASH_ALG_PARAMS { + uint8_t algid; + uint16_t block_length; + uint16_t digest_length; + NTRU_CRYPTO_HASH_INIT_FN init; + NTRU_CRYPTO_HASH_UPDATE_FN update; + NTRU_CRYPTO_HASH_FINAL_FN final; + NTRU_CRYPTO_HASH_FINAL_FN final_zero_pad; + NTRU_CRYPTO_HASH_DIGEST_FN digest; +} NTRU_CRYPTO_HASH_ALG_PARAMS; + +static NTRU_CRYPTO_HASH_ALG_PARAMS const algs_params[] = { + { + NTRU_CRYPTO_HASH_ALGID_SHA1, + SHA_1_BLK_LEN, + SHA_1_MD_LEN, + (NTRU_CRYPTO_HASH_INIT_FN) SHA_1_INIT_FN, + (NTRU_CRYPTO_HASH_UPDATE_FN) SHA_1_UPDATE_FN, + (NTRU_CRYPTO_HASH_FINAL_FN) SHA_1_FINAL_FN, + (NTRU_CRYPTO_HASH_FINAL_FN) SHA_1_FINAL_ZERO_PAD_FN, + (NTRU_CRYPTO_HASH_DIGEST_FN) SHA_1_DIGEST_FN, + }, + { + NTRU_CRYPTO_HASH_ALGID_SHA256, + SHA_256_BLK_LEN, + SHA_256_MD_LEN, + (NTRU_CRYPTO_HASH_INIT_FN) SHA_256_INIT_FN, + (NTRU_CRYPTO_HASH_UPDATE_FN) SHA_256_UPDATE_FN, + (NTRU_CRYPTO_HASH_FINAL_FN) SHA_256_FINAL_FN, + (NTRU_CRYPTO_HASH_FINAL_FN) SHA_256_FINAL_ZERO_PAD_FN, + (NTRU_CRYPTO_HASH_DIGEST_FN) SHA_256_DIGEST_FN, + }, +}; + +static int const numalgs = (sizeof(algs_params)/sizeof(algs_params[0])); + + +/* get_alg_params + * + * Return a pointer to the hash algorithm parameters for the hash algorithm + * specified, by looking for algid in the global algs_params table. + * If not found, return NULL. + */ +static NTRU_CRYPTO_HASH_ALG_PARAMS const * +get_alg_params( + NTRU_CRYPTO_HASH_ALGID algid) // in - the hash algorithm to find +{ + int i; + + for (i = 0; i < numalgs; i++) + if (algs_params[i].algid == algid) + return &algs_params[i]; + + return NULL; +} + + +/* ntru_crypto_hash_set_alg + * + * Sets the hash algorithm for the hash context. This must be called before + * any calls to ntru_crypto_hash_block_length(), + * ntru_crypto_hash_digest_length(), or ntru_crypto_hash_init() are made. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the specified algorithm is not supported. + */ + +uint32_t +ntru_crypto_hash_set_alg( + NTRU_CRYPTO_HASH_ALGID algid, // in - hash algoirithm to be used + NTRU_CRYPTO_HASH_CTX *c) // in/out - pointer to the hash context +{ + if (!c) + HASH_RET(NTRU_CRYPTO_HASH_BAD_PARAMETER); + + c->alg_params = get_alg_params(algid); + if (!c->alg_params) { + HASH_RET(NTRU_CRYPTO_HASH_BAD_ALG); + } + + HASH_RET(NTRU_CRYPTO_HASH_OK); +} + + +/* ntru_crypto_hash_block_length + * + * Gets the number of bytes in an input block for the hash algorithm + * specified in the hash context. The hash algorithm must have been set + * in the hash context with a call to ntru_crypto_hash_set_alg() prior to + * calling this function. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +uint32_t +ntru_crypto_hash_block_length( + NTRU_CRYPTO_HASH_CTX *c, // in - pointer to the hash context + uint16_t *blk_len) // out - address for block length in bytes +{ + if (!c || !blk_len) + HASH_RET(NTRU_CRYPTO_HASH_BAD_PARAMETER); + + if (!c->alg_params) + HASH_RET(NTRU_CRYPTO_HASH_BAD_ALG); + + *blk_len = c->alg_params->block_length; + HASH_RET(NTRU_CRYPTO_HASH_OK); +} + + +/* ntru_crypto_hash_digest_length + * + * Gets the number of bytes needed to hold the message digest for the + * hash algorithm specified in the hash context. The algorithm must have + * been set in the hash context with a call to ntru_crypto_hash_set_alg() prior + * to calling this function. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +uint32_t +ntru_crypto_hash_digest_length( + NTRU_CRYPTO_HASH_CTX const *c, // in - pointer to the hash context + uint16_t *md_len) // out - addr for digest length in bytes +{ + if (!c || !md_len) + HASH_RET(NTRU_CRYPTO_HASH_BAD_PARAMETER); + + if (!c->alg_params) + HASH_RET(NTRU_CRYPTO_HASH_BAD_ALG); + + *md_len = c->alg_params->digest_length; + HASH_RET(NTRU_CRYPTO_HASH_OK); +} + + +/* ntru_crypto_hash_init + * + * This routine performs standard initialization of the hash state. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +uint32_t +ntru_crypto_hash_init( + NTRU_CRYPTO_HASH_CTX *c) // in/out - pointer to hash context +{ + if (!c) + HASH_RET(NTRU_CRYPTO_HASH_BAD_PARAMETER); + + if (!c->alg_params) + HASH_RET(NTRU_CRYPTO_HASH_BAD_ALG); + + return c->alg_params->init(&c->alg_ctx); +} + + +/* ntru_crypto_hash_update + * + * This routine processes input data and updates the hash calculation. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_OVERFLOW if too much text has been fed to the + * hash algorithm. The size limit is dependent on the hash algorithm, + * and not all algorithms have this limit. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +uint32_t +ntru_crypto_hash_update( + NTRU_CRYPTO_HASH_CTX *c, // in/out - pointer to hash context + uint8_t const *data, // in - pointer to input data + uint32_t data_len) // in - number of bytes of input data +{ + if (!c || (data_len && !data)) + HASH_RET(NTRU_CRYPTO_HASH_BAD_PARAMETER); + + if (!c->alg_params) + HASH_RET(NTRU_CRYPTO_HASH_BAD_ALG); + + return c->alg_params->update(&c->alg_ctx, data, data_len); +} + + +/* ntru_crypto_hash_final + * + * This routine completes the hash calculation and returns the message digest. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +uint32_t +ntru_crypto_hash_final( + NTRU_CRYPTO_HASH_CTX *c, // in/out - pointer to hash context + uint8_t *md) // out - address for message digest +{ + if (!c || !md) + HASH_RET(NTRU_CRYPTO_HASH_BAD_PARAMETER); + + if (!c->alg_params) + HASH_RET(NTRU_CRYPTO_HASH_BAD_ALG); + + return c->alg_params->final(&c->alg_ctx, md); +} + + +/* ntru_crypto_hash_final_zero_pad + * + * This routine completes the hash calculation using zero padding and + * returns the message digest. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +uint32_t +ntru_crypto_hash_final_zero_pad( + NTRU_CRYPTO_HASH_CTX *c, // in/out - pointer to hash context + uint8_t *md) // out - address for message digest +{ + if (!c || !md) + HASH_RET(NTRU_CRYPTO_HASH_BAD_PARAMETER); + + if (!c->alg_params) + HASH_RET(NTRU_CRYPTO_HASH_BAD_ALG); + + return c->alg_params->final_zero_pad(&c->alg_ctx, md); +} + + +/* ntru_crypto_hash_digest + * + * This routine computes a message digest. It is assumed that the + * output buffer md is large enough to hold the output (see + * ntru_crypto_hash_digest_length) + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_OVERFLOW if too much text has been fed to the + * hash algorithm. The size limit is dependent on the hash algorithm, + * and not all algorithms have this limit. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the specified algorithm is not supported. + */ + +uint32_t +ntru_crypto_hash_digest( + NTRU_CRYPTO_HASH_ALGID algid, // in - the hash algorithm to use + uint8_t const *data, // in - pointer to input data + uint32_t data_len, // in - number of bytes of input data + uint8_t *md) // out - address for message digest +{ + NTRU_CRYPTO_HASH_ALG_PARAMS const *alg_params = get_alg_params(algid); + + if (!alg_params) + HASH_RET(NTRU_CRYPTO_HASH_BAD_ALG); + + if ((data_len && !data) || !md) + HASH_RET(NTRU_CRYPTO_HASH_BAD_PARAMETER); + + return alg_params->digest(data, data_len, md); +} + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hash.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hash.h new file mode 100644 index 000000000..cf023f340 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hash.h @@ -0,0 +1,233 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_hash.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_hash.h + * + * Contents: Definitions and declarations for the hash object abstraction. + * + *****************************************************************************/ + +#ifndef NTRU_CRYPTO_HASH_H +#define NTRU_CRYPTO_HASH_H + +#include "ntru_crypto_platform.h" +#include "ntru_crypto_error.h" +#include "ntru_crypto_hash_basics.h" +#include "ntru_crypto_sha1.h" +#include "ntru_crypto_sha256.h" + + +/*************** + * error macro * + ***************/ + +#define HASH_RESULT(r) ((uint32_t)((r) ? HASH_ERROR_BASE + (r) : (r))) +#define HASH_RET(r) return HASH_RESULT(r); + + +/************************* + * structure definitions * + *************************/ + +/* _NTRU_CRYPTO_HASH_ALG_PARAMS + * + * An opaque forward declaration for a private structure used + * internally by the hash object interface. + */ + +struct _NTRU_CRYPTO_HASH_ALG_PARAMS; + + +/* NTRU_CRYPTO_HASH_CTX + * + * Hash object context information. + */ + +typedef struct { + struct _NTRU_CRYPTO_HASH_ALG_PARAMS const *alg_params; + union { + NTRU_CRYPTO_SHA1_CTX sha1; + NTRU_CRYPTO_SHA2_CTX sha256; + } alg_ctx; +} NTRU_CRYPTO_HASH_CTX; + + +/************************* + * function declarations * + *************************/ + +/* ntru_crypto_hash_set_alg + * + * Sets the hash algorithm for the hash context. This must be called before + * any calls to crypto_hash_block_length(), crypto_hash_digest_length(), or + * crypto_hash_init() are made. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the specified algorithm is not supported. + */ + +extern uint32_t +ntru_crypto_hash_set_alg( + NTRU_CRYPTO_HASH_ALGID algid, // in - hash algoirithm to be used + NTRU_CRYPTO_HASH_CTX *c); // in/out - pointer to the hash context + + +/* ntru_crypto_hash_block_length + * + * Gets the number of bytes in an input block for the hash algorithm + * specified in the hash context. The hash algorithm must have been set + * in the hash context with a call to crypto_hash_set_alg() prior to + * calling this function. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +extern uint32_t +ntru_crypto_hash_block_length( + NTRU_CRYPTO_HASH_CTX *c, // in - pointer to the hash context + uint16_t *blk_len); // out - address for block length in bytes + + +/* ntru_crypto_hash_digest_length + * + * Gets the number of bytes needed to hold the message digest for the + * hash algorithm specified in the hash context. The algorithm must have + * been set in the hash context with a call to crypto_hash_set_alg() prior + * to calling this function. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +extern uint32_t +ntru_crypto_hash_digest_length( + NTRU_CRYPTO_HASH_CTX const *c, // in - pointer to the hash context + uint16_t *md_len); // out - addrfor digest length in bytes + + +/* ntru_crypto_hash_init + * + * This routine initializes the hash state. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +extern uint32_t +ntru_crypto_hash_init( + NTRU_CRYPTO_HASH_CTX *c); // in/out - pointer to hash context + + +/* ntru_crypto_hash_update + * + * This routine processes input data and updates the hash calculation. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_OVERFLOW if too much text has been fed to the + * hash algorithm. The size limit is dependent on the hash algorithm, + * and not all algorithms have this limit. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +extern uint32_t +ntru_crypto_hash_update( + NTRU_CRYPTO_HASH_CTX *c, // in/out - pointer to hash context + uint8_t const *data, // in - pointer to input data + uint32_t data_len); // in - number of bytes of input data + + +/* ntru_crypto_hash_final + * + * This routine completes the hash calculation and returns the message digest. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +extern uint32_t +ntru_crypto_hash_final( + NTRU_CRYPTO_HASH_CTX *c, // in/out - pointer to hash context + uint8_t *md); // out - address for message digest + + +/* ntru_crypto_hash_final_zero_pad + * + * This routine completes the hash calculation using zero padding and + * returns the message digest. + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the algorithm has not been set. + */ + +extern uint32_t +ntru_crypto_hash_final_zero_pad( + NTRU_CRYPTO_HASH_CTX *c, // in/out - pointer to hash context + uint8_t *md); // out - address for message digest + + +/* ntru_crypto_hash_digest + * + * This routine computes a message digest. It is assumed that the + * output buffer md is large enough to hold the output (see + * crypto_hash_digest_length) + * + * Returns NTRU_CRYPTO_HASH_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HASH_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns NTRU_CRYPTO_HASH_OVERFLOW if too much text has been fed to the + * hash algorithm. The size limit is dependent on the hash algorithm, + * and not all algorithms have this limit. + * Returns NTRU_CRYPTO_HASH_BAD_ALG if the specified algorithm is not supported. + */ + +extern uint32_t +ntru_crypto_hash_digest( + NTRU_CRYPTO_HASH_ALGID algid, // in - the hash algorithm to use + uint8_t const *data, // in - pointer to input data + uint32_t data_len, // in - number of bytes of input data + uint8_t *md); // out - address for message digest + + +#endif /* NTRU_CRYPTO_HASH_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hash_basics.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hash_basics.h new file mode 100644 index 000000000..99448d1fb --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hash_basics.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_hash_basics.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_hash_basics.h + * + * Contents: Common definitions for all hash algorithms. + * + *****************************************************************************/ + +#ifndef NTRU_CRYPTO_HASH_BASICS_H +#define NTRU_CRYPTO_HASH_BASICS_H + +#include "ntru_crypto_platform.h" + + +/************** + * algorithms * + **************/ + +typedef enum { + NTRU_CRYPTO_HASH_ALGID_NONE = 0, + NTRU_CRYPTO_HASH_ALGID_SHA1, + NTRU_CRYPTO_HASH_ALGID_SHA256, +} NTRU_CRYPTO_HASH_ALGID; + + +/*************** + * error codes * + ***************/ + +#define NTRU_CRYPTO_HASH_OK ((uint32_t)0x00) +#define NTRU_CRYPTO_HASH_FAIL ((uint32_t)0x01) +#define NTRU_CRYPTO_HASH_BAD_PARAMETER ((uint32_t)0x02) +#define NTRU_CRYPTO_HASH_OVERFLOW ((uint32_t)0x03) +#define NTRU_CRYPTO_HASH_BAD_ALG ((uint32_t)0x20) +#define NTRU_CRYPTO_HASH_OUT_OF_MEMORY ((uint32_t)0x21) + +// For backward-compatibility +typedef uint32_t NTRU_CRYPTO_HASH_ERROR; + + +/********* + * flags * + *********/ + +#define HASH_DATA_ONLY 0 +#define HASH_INIT (1 << 0) +#define HASH_FINISH (1 << 1) +#define HASH_ZERO_PAD (1 << 2) + + +#endif /* NTRU_CRYPTO_HASH_BASICS_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hmac.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hmac.c new file mode 100644 index 000000000..715331b82 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hmac.c @@ -0,0 +1,320 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_hmac.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_hmac.c + * + * Contents: Routines implementing the HMAC hash calculation. + * + *****************************************************************************/ + + +#include <stdlib.h> +#include <string.h> +#include "ntru_crypto_hmac.h" + + +/* HMAC context */ + +struct _NTRU_CRYPTO_HMAC_CTX { + NTRU_CRYPTO_HASH_CTX hash_ctx; + uint8_t *k0; + uint16_t blk_len; + uint16_t md_len; +}; + + +/* ntru_crypto_hmac_create_ctx + * + * This routine creates an HMAC context, setting the hash algorithm and + * the key to be used. + * + * Returns NTRU_CRYPTO_HMAC_OK if successful. + * Returns NTRU_CRYPTO_HMAC_BAD_ALG if the specified algorithm is not supported. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HMAC_OUT_OF_MEMORY if memory cannot be allocated. + */ + +uint32_t +ntru_crypto_hmac_create_ctx( + NTRU_CRYPTO_HASH_ALGID algid, /* in - the hash algorithm to be used */ + uint8_t const *key, /* in - pointer to the HMAC key */ + uint32_t key_len, /* in - number of bytes in HMAC key */ + NTRU_CRYPTO_HMAC_CTX **c) /* out - address for pointer to HMAC + context */ +{ + NTRU_CRYPTO_HMAC_CTX *ctx = NULL; + uint32_t result; + + /* check parameters */ + + if (!c || !key) + HMAC_RET(NTRU_CRYPTO_HMAC_BAD_PARAMETER); + + *c = NULL; + + /* allocate memory for an HMAC context */ + + if ((ctx = (NTRU_CRYPTO_HMAC_CTX*) malloc(sizeof(NTRU_CRYPTO_HMAC_CTX))) == + NULL) + HMAC_RET(NTRU_CRYPTO_HMAC_OUT_OF_MEMORY); + + /* set the algorithm */ + + if (result = ntru_crypto_hash_set_alg(algid, &ctx->hash_ctx)) { + free(ctx); + HMAC_RET(NTRU_CRYPTO_HMAC_BAD_ALG); + } + + /* set block length and digest length */ + + if ((result = ntru_crypto_hash_block_length(&ctx->hash_ctx, + &ctx->blk_len)) || + (result = ntru_crypto_hash_digest_length(&ctx->hash_ctx, + &ctx->md_len))) { + free(ctx); + return result; + } + + /* allocate memory for K0 */ + + if ((ctx->k0 = (uint8_t*) malloc(ctx->blk_len)) == NULL) { + free(ctx); + HMAC_RET(NTRU_CRYPTO_HMAC_OUT_OF_MEMORY); + } + + /* calculate K0 and store in HMAC context */ + + memset(ctx->k0, 0, ctx->blk_len); + + /* check if key is too large */ + + if (key_len > ctx->blk_len) { + + if (result = ntru_crypto_hash_digest(algid, key, key_len, ctx->k0)) { + memset(ctx->k0, 0, ctx->blk_len); + free(ctx->k0); + free(ctx); + return result; + } + + } else + memcpy(ctx->k0, key, key_len); + + /* return pointer to HMAC context */ + + *c = ctx; + HMAC_RET(NTRU_CRYPTO_HMAC_OK); +} + + +/* ntru_crypto_hmac_destroy_ctx + * + * Destroys an HMAC context. + * + * Returns NTRU_CRYPTO_HMAC_OK if successful. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + */ + +uint32_t +ntru_crypto_hmac_destroy_ctx( + NTRU_CRYPTO_HMAC_CTX *c) /* in/out - pointer to HMAC context */ +{ + if (!c || !c->k0) + HMAC_RET(NTRU_CRYPTO_HMAC_BAD_PARAMETER); + + /* clear key and release memory */ + + memset(c->k0, 0, c->blk_len); + free(c->k0); + free(c); + + HMAC_RET(NTRU_CRYPTO_HMAC_OK); +} + + +/* ntru_crypto_hmac_get_md_len + * + * This routine gets the digest length of the HMAC. + * + * Returns NTRU_CRYPTO_HMAC_OK on success. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + */ + +uint32_t +ntru_crypto_hmac_get_md_len( + NTRU_CRYPTO_HMAC_CTX const *c, /* in - pointer to HMAC context */ + uint16_t *md_len) /* out - address for digest length */ +{ + /* check parameters */ + + if (!c || !md_len) + HMAC_RET(NTRU_CRYPTO_HMAC_BAD_PARAMETER); + + /* get digest length */ + + *md_len = c->md_len; + HMAC_RET(NTRU_CRYPTO_HMAC_OK); +} + + +/* ntru_crypto_hmac_set_key + * + * This routine sets a digest-length key into the HMAC context. + * + * Returns NTRU_CRYPTO_HMAC_OK on success. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + */ + +uint32_t +ntru_crypto_hmac_set_key( + NTRU_CRYPTO_HMAC_CTX *c, /* in - pointer to HMAC context */ + uint8_t const *key) /* in - pointer to new HMAC key */ +{ + /* check parameters */ + + if (!c || !key) + HMAC_RET(NTRU_CRYPTO_HMAC_BAD_PARAMETER); + + /* copy key */ + + memcpy(c->k0, key, c->md_len); + HMAC_RET(NTRU_CRYPTO_HMAC_OK); +} + + +/* ntru_crypto_hmac_init + * + * This routine performs standard initialization of the HMAC state. + * + * Returns NTRU_CRYPTO_HMAC_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + */ + +uint32_t +ntru_crypto_hmac_init( + NTRU_CRYPTO_HMAC_CTX *c) /* in/out - pointer to HMAC context */ +{ + uint32_t result; + int i; + + /* check parameters */ + + if (!c) + HMAC_RET(NTRU_CRYPTO_HMAC_BAD_PARAMETER); + + /* init hash context and compute H(K0 ^ ipad) */ + + for (i = 0; i < c->blk_len; i++) + c->k0[i] ^= 0x36; /* K0 ^ ipad */ + if ((result = ntru_crypto_hash_init(&c->hash_ctx)) || + (result = ntru_crypto_hash_update(&c->hash_ctx, c->k0, c->blk_len))) + return result; + + HMAC_RET(NTRU_CRYPTO_HMAC_OK); +} + + +/* ntru_crypto_hmac_update + * + * This routine processes input data and updates the HMAC hash calculation. + * + * Returns NTRU_CRYPTO_HMAC_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_OVERFLOW if more than bytes are hashed than the + * underlying hash algorithm can handle. + */ + +uint32_t +ntru_crypto_hmac_update( + NTRU_CRYPTO_HMAC_CTX *c, /* in/out - pointer to HMAC context */ + const uint8_t *data, /* in - pointer to input data */ + uint32_t data_len) /* in - no. of bytes of input data */ +{ + uint32_t result; + + /* check parameters */ + + if (!c || (data_len && !data)) + HMAC_RET(NTRU_CRYPTO_HMAC_BAD_PARAMETER); + + if (result = ntru_crypto_hash_update(&c->hash_ctx, data, data_len)) + return result; + + HMAC_RET(NTRU_CRYPTO_HMAC_OK); +} + + +/* ntru_crypto_hmac_final + * + * This routine completes the HMAC hash calculation and returns the + * message digest. + * + * Returns NTRU_CRYPTO_HMAC_OK on success. + * Returns NTRU_CRYPTO_HASH_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + */ + +uint32_t +ntru_crypto_hmac_final( + NTRU_CRYPTO_HMAC_CTX *c, /* in/out - pointer to HMAC context */ + uint8_t *md) /* out - address for message digest */ +{ + uint32_t result = NTRU_CRYPTO_HMAC_OK; + int i; + + /* check parameters */ + + if (!c || !md) + HMAC_RET(NTRU_CRYPTO_HMAC_BAD_PARAMETER); + + /* form K0 ^ opad + * complete md = H((K0 ^ ipad) || data) + * compute md = H((K0 ^ opad) || md) + * re-form K0 + */ + + for (i = 0; i < c->blk_len; i++) + c->k0[i] ^= (0x36^0x5c); + if ((result = ntru_crypto_hash_final(&c->hash_ctx, md)) || + (result = ntru_crypto_hash_init(&c->hash_ctx)) || + (result = ntru_crypto_hash_update(&c->hash_ctx, c->k0, c->blk_len)) || + (result = ntru_crypto_hash_update(&c->hash_ctx, md, c->md_len)) || + (result = ntru_crypto_hash_final(&c->hash_ctx, md))) { + } + for (i = 0; i < c->blk_len; i++) + c->k0[i] ^= 0x5c; + return result; +} + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hmac.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hmac.h new file mode 100644 index 000000000..1ec426b4a --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_hmac.h @@ -0,0 +1,183 @@ +/*/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_hmac.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_hmac.h + * + * Contents: Definitions and declarations for the HMAC implementation. + * + *****************************************************************************/ + +#ifndef NTRU_CRYPTO_HMAC_H +#define NTRU_CRYPTO_HMAC_H + + +#include "ntru_crypto_platform.h" +#include "ntru_crypto_hash.h" + + +/*************** + * error codes * + ***************/ + +#define NTRU_CRYPTO_HMAC_OK ((uint32_t)NTRU_CRYPTO_HASH_OK) +#define NTRU_CRYPTO_HMAC_BAD_PARAMETER ((uint32_t)NTRU_CRYPTO_HASH_BAD_PARAMETER) +#define NTRU_CRYPTO_HMAC_BAD_ALG ((uint32_t)NTRU_CRYPTO_HASH_BAD_ALG) +#define NTRU_CRYPTO_HMAC_OUT_OF_MEMORY ((uint32_t)NTRU_CRYPTO_HASH_OUT_OF_MEMORY) + +#define HMAC_RESULT(e) ((uint32_t)((e) ? HMAC_ERROR_BASE + (e) : (e))) +#define HMAC_RET(e) return HMAC_RESULT(e) + + +/************************* + * structure definitions * + *************************/ + +/* HMAC context structure */ + +struct _NTRU_CRYPTO_HMAC_CTX; /* opaque forward reference */ +typedef struct _NTRU_CRYPTO_HMAC_CTX NTRU_CRYPTO_HMAC_CTX; + + +/************************* + * function declarations * + *************************/ + +/* ntru_crypto_hmac_create_ctx + * + * This routine creates an HMAC context, setting the hash algorithm and + * the key to be used. + * + * Returns NTRU_CRYPTO_HASH_OK if successful. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HASH_OUT_OF_MEMORY if memory cannot be allocated. + */ + +extern uint32_t +ntru_crypto_hmac_create_ctx( + NTRU_CRYPTO_HASH_ALGID algid, /* in - the hash algorithm to be used */ + uint8_t const *key, /* in - pointer to the HMAC key */ + uint32_t key_len, /* in - number of bytes in HMAC key */ + NTRU_CRYPTO_HMAC_CTX **c); /* out - address for pointer to HMAC + context */ + + +/* ntru_crypto_hmac_destroy_ctx + * + * Destroys an HMAC context. + * + * Returns NTRU_CRYPTO_HASH_OK if successful. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + */ + +extern uint32_t +ntru_crypto_hmac_destroy_ctx( + NTRU_CRYPTO_HMAC_CTX *c); /* in/out - pointer to HMAC context */ + + +/* ntru_crypto_hmac_get_md_len + * + * This routine gets the digest length of the HMAC. + * + * Returns NTRU_CRYPTO_HMAC_OK on success. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + */ + +extern uint32_t +ntru_crypto_hmac_get_md_len( + NTRU_CRYPTO_HMAC_CTX const *c, /* in - pointer to HMAC context */ + uint16_t *md_len); /* out - address for digest length */ + + +/* ntru_crypto_hmac_set_key + * + * This routine sets a digest-length key into the HMAC context. + * + * Returns NTRU_CRYPTO_HMAC_OK on success. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + */ + +extern uint32_t +ntru_crypto_hmac_set_key( + NTRU_CRYPTO_HMAC_CTX *c, /* in - pointer to HMAC context */ + uint8_t const *key); /* in - pointer to new HMAC key */ + + +/* ntru_crypto_hmac_init + * + * This routine performs standard initialization of the HMAC state. + * + * Returns NTRU_CRYPTO_HMAC_OK on success. + * Returns NTRU_CRYPTO_HMAC_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + */ + +extern uint32_t +ntru_crypto_hmac_init( + NTRU_CRYPTO_HMAC_CTX *c); /* in/out - pointer to HMAC context */ + + +/* ntru_crypto_hmac_update + * + * This routine processes input data and updates the HMAC hash calculation. + * + * Returns NTRU_CRYPTO_HMAC_OK on success. + * Returns NTRU_CRYPTO_HMAC_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + * Returns NTRU_CRYPTO_HMAC_OVERFLOW if more than bytes are hashed than the underlying + * hash algorithm can handle. + */ + +extern uint32_t +ntru_crypto_hmac_update( + NTRU_CRYPTO_HMAC_CTX *c, /* in/out - pointer to HMAC context */ + uint8_t const *data, /* in - pointer to input data */ + uint32_t data_len); /* in - no. of bytes of input data */ + + +/* ntru_crypto_hmac_final + * + * This routine completes the HMAC hash calculation and returns the + * message digest. + * + * Returns NTRU_CRYPTO_HMAC_OK on success. + * Returns NTRU_CRYPTO_HMAC_FAIL with corrupted context. + * Returns NTRU_CRYPTO_HMAC_BAD_PARAMETER if inappropriate NULL pointers are + * passed. + */ + +extern uint32_t +ntru_crypto_hmac_final( + NTRU_CRYPTO_HMAC_CTX *c, /* in/out - pointer to HMAC context */ + uint8_t *md); /* out - address for message digest */ + + +#endif /* NTRU_CRYPTO_HMAC_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_msbyte_uint32.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_msbyte_uint32.c new file mode 100644 index 000000000..e9492e3ba --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_msbyte_uint32.c @@ -0,0 +1,92 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_mbyte_uint32.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_msbyte_uint32.c + * + * Contents: Routines to convert between an array of bytes in network byte + * order (most-significant byte first) and an array of uint32 words. + * + *****************************************************************************/ + + +#include <stdlib.h> +#include "ntru_crypto_msbyte_uint32.h" + + +/* ntru_crypto_msbyte_2_uint32() + * + * This routine converts an array of bytes in network byte order to an array + * of uint32_t, placing the first byte in the most significant byte of the + * first uint32_t word. + * + * The number of bytes in the input stream MUST be at least 4 times the + * number of words expected in the output array. + */ + +void +ntru_crypto_msbyte_2_uint32( + uint32_t *words, // out - pointer to the output uint32_t array + uint8_t const *bytes, // in - pointer to the input byte array + uint32_t n) // in - number of words in the output array +{ + uint32_t i; + + for (i = 0; i < n; i++) { + words[i] = ((uint32_t) (*bytes++)) << 24; + words[i] |= ((uint32_t) (*bytes++)) << 16; + words[i] |= ((uint32_t) (*bytes++)) << 8; + words[i] |= (uint32_t) (*bytes++); + } +} + + +/* ntru_crypto_uint32_2_msbyte() + * + * This routine converts an array of uint32_t to an array of bytes in + * network byte order, placing the most significant byte of the first uint32_t + * word as the first byte of the output array. + * + * The number of bytes in the output stream will be 4 times the number of words + * specified in the input array. + */ + +void +ntru_crypto_uint32_2_msbyte( + uint8_t *bytes, // out - pointer to the output byte array + uint32_t const *words, // in - pointer to the input uint32_t array + uint32_t n) // in - number of words in the input array +{ + uint32_t i; + + for (i = 0; i < n; i++) { + *bytes++ = (uint8_t) (words[i] >> 24); + *bytes++ = (uint8_t) (words[i] >> 16); + *bytes++ = (uint8_t) (words[i] >> 8); + *bytes++ = (uint8_t) (words[i] ); + } +} + + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_msbyte_uint32.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_msbyte_uint32.h new file mode 100644 index 000000000..7d2b0a65e --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_msbyte_uint32.h @@ -0,0 +1,75 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_msbyte_uint32.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_msbyte_uint32.h + * + * Contents: Definitions and declarations for converting between a most- + * significant-first byte stream and a uint32_t array. + * + *****************************************************************************/ + +#ifndef NTRU_CRYPTO_MSBYTE_UINT32_H +#define NTRU_CRYPTO_MSBYTE_UINT32_H + + +#include "ntru_crypto_platform.h" + + +/* ntru_crypto_msbyte_2_uint32() + * + * This routine converts an array of bytes in network byte order to an array + * of uint32_t, placing the first byte in the most significant byte of the + * first uint32_t word. + * + * The number of bytes in the input stream MUST be at least 4 times the + * number of words expected in the output array. + */ + +extern void +ntru_crypto_msbyte_2_uint32( + uint32_t *words, // out - pointer to the output uint32_t array + uint8_t const *bytes, // in - pointer to the input byte array + uint32_t n); // in - number of words in the output array + + +/* ntru_crypto_uint32_2_msbyte() + * + * This routine converts an array of uint32_t to an array of bytes in + * network byte order, placing the most significant byte of the first uint32_t + * word as the first byte of the output array. + * + * The number of bytes in the output stream will be 4 times the number of words + * specified in the input array. + */ + +extern void +ntru_crypto_uint32_2_msbyte( + uint8_t *bytes, // out - pointer to the output byte array + uint32_t const *words, // in - pointer to the input uint32_t array + uint32_t n); // in - number of words in the input array + + +#endif /* NTRU_CRYPTO_MSBYTE_UINT32_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_convert.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_convert.c new file mode 100644 index 000000000..3d6dfde41 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_convert.c @@ -0,0 +1,581 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_convert.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_ntru_convert.c + * + * Contents: Conversion routines for NTRUEncrypt, including packing, unpacking, + * and others. + * + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "ntru_crypto_ntru_convert.h" + + +/* 3-bit to 2-trit conversion tables: 2 represents -1 */ + +static uint8_t const bits_2_trit1[] = {0, 0, 0, 1, 1, 1, 2, 2}; +static uint8_t const bits_2_trit2[] = {0, 1, 2, 0, 1, 2, 0, 1}; + + +/* ntru_bits_2_trits + * + * Each 3 bits in an array of octets is converted to 2 trits in an array + * of trits. + * + * The octet array may overlap the end of the trit array. + */ + +void +ntru_bits_2_trits( + uint8_t const *octets, /* in - pointer to array of octets */ + uint16_t num_trits, /* in - number of trits to produce */ + uint8_t *trits) /* out - address for array of trits */ +{ + uint32_t bits24; + uint32_t bits3; + uint32_t shift; + + assert(octets); + assert(trits); + + while (num_trits >= 16) { + + /* get next three octets */ + + bits24 = ((uint32_t)(*octets++)) << 16; + bits24 |= ((uint32_t)(*octets++)) << 8; + bits24 |= (uint32_t)(*octets++); + + /* for each 3 bits in the three octets, output 2 trits */ + + bits3 = (bits24 >> 21) & 0x7; + *trits++ = bits_2_trit1[bits3]; + *trits++ = bits_2_trit2[bits3]; + + bits3 = (bits24 >> 18) & 0x7; + *trits++ = bits_2_trit1[bits3]; + *trits++ = bits_2_trit2[bits3]; + + bits3 = (bits24 >> 15) & 0x7; + *trits++ = bits_2_trit1[bits3]; + *trits++ = bits_2_trit2[bits3]; + + bits3 = (bits24 >> 12) & 0x7; + *trits++ = bits_2_trit1[bits3]; + *trits++ = bits_2_trit2[bits3]; + + bits3 = (bits24 >> 9) & 0x7; + *trits++ = bits_2_trit1[bits3]; + *trits++ = bits_2_trit2[bits3]; + + bits3 = (bits24 >> 6) & 0x7; + *trits++ = bits_2_trit1[bits3]; + *trits++ = bits_2_trit2[bits3]; + + bits3 = (bits24 >> 3) & 0x7; + *trits++ = bits_2_trit1[bits3]; + *trits++ = bits_2_trit2[bits3]; + + bits3 = bits24 & 0x7; + *trits++ = bits_2_trit1[bits3]; + *trits++ = bits_2_trit2[bits3]; + + num_trits -= 16; + } + if (num_trits == 0) + return; + + /* get three octets */ + + bits24 = ((uint32_t)(*octets++)) << 16; + bits24 |= ((uint32_t)(*octets++)) << 8; + bits24 |= (uint32_t)(*octets++); + + shift = 21; + while (num_trits) { + + /* for each 3 bits in the three octets, output up to 2 trits + * until all trits needed are produced + */ + + bits3 = (bits24 >> shift) & 0x7; + shift -= 3; + *trits++ = bits_2_trit1[bits3]; + if (--num_trits) { + *trits++ = bits_2_trit2[bits3]; + --num_trits; + } + } +} + + +/* ntru_trits_2_bits + * + * Each 2 trits in an array of trits is converted to 3 bits, and the bits + * are packed in an array of octets. A multiple of 3 octets is output. + * Any bits in the final octets not derived from trits are zero. + * + * Returns TRUE if all trits were valid. + * Returns FALSE if invalid trits were found. + */ + +bool +ntru_trits_2_bits( + uint8_t const *trits, /* in - pointer to array of trits */ + uint32_t num_trits, /* in - number of trits to convert */ + uint8_t *octets) /* out - address for array of octets */ +{ + bool all_trits_valid = TRUE; + uint32_t bits24; + uint32_t bits3; + uint32_t shift; + + assert(octets); + assert(trits); + + while (num_trits >= 16) { + + /* convert each 2 trits to 3 bits and pack */ + + bits3 = *trits++ * 3; + bits3 += *trits++; + if (bits3 > 7) { + bits3 = 7; + all_trits_valid = FALSE; + } + bits24 = (bits3 << 21); + + bits3 = *trits++ * 3; + bits3 += *trits++; + if (bits3 > 7) { + bits3 = 7; + all_trits_valid = FALSE; + } + bits24 |= (bits3 << 18); + + bits3 = *trits++ * 3; + bits3 += *trits++; + if (bits3 > 7) { + bits3 = 7; + all_trits_valid = FALSE; + } + bits24 |= (bits3 << 15); + + bits3 = *trits++ * 3; + bits3 += *trits++; + if (bits3 > 7) { + bits3 = 7; + all_trits_valid = FALSE; + } + bits24 |= (bits3 << 12); + + bits3 = *trits++ * 3; + bits3 += *trits++; + if (bits3 > 7) { + bits3 = 7; + all_trits_valid = FALSE; + } + bits24 |= (bits3 << 9); + + bits3 = *trits++ * 3; + bits3 += *trits++; + if (bits3 > 7) { + bits3 = 7; + all_trits_valid = FALSE; + } + bits24 |= (bits3 << 6); + + bits3 = *trits++ * 3; + bits3 += *trits++; + if (bits3 > 7) { + bits3 = 7; + all_trits_valid = FALSE; + } + bits24 |= (bits3 << 3); + + bits3 = *trits++ * 3; + bits3 += *trits++; + if (bits3 > 7) { + bits3 = 7; + all_trits_valid = FALSE; + } + bits24 |= bits3; + + num_trits -= 16; + + /* output three octets */ + + *octets++ = (uint8_t)((bits24 >> 16) & 0xff); + *octets++ = (uint8_t)((bits24 >> 8) & 0xff); + *octets++ = (uint8_t)(bits24 & 0xff); + } + + bits24 = 0; + shift = 21; + while (num_trits) { + + /* convert each 2 trits to 3 bits and pack */ + + bits3 = *trits++ * 3; + if (--num_trits) { + bits3 += *trits++; + --num_trits; + } + if (bits3 > 7) { + bits3 = 7; + all_trits_valid = FALSE; + } + bits24 |= (bits3 << shift); + shift -= 3; + } + + /* output three octets */ + + *octets++ = (uint8_t)((bits24 >> 16) & 0xff); + *octets++ = (uint8_t)((bits24 >> 8) & 0xff); + *octets++ = (uint8_t)(bits24 & 0xff); + + return all_trits_valid; +} + + +/* ntru_coeffs_mod4_2_octets + * + * Takes an array of ring element coefficients mod 4 and packs the + * results into an octet string. + */ + +void +ntru_coeffs_mod4_2_octets( + uint16_t num_coeffs, /* in - number of coefficients */ + uint16_t const *coeffs, /* in - pointer to coefficients */ + uint8_t *octets) /* out - address for octets */ +{ + uint8_t bits2; + int shift; + uint16_t i; + + assert(coeffs); + assert(octets); + + *octets = 0; + shift = 6; + for (i = 0; i < num_coeffs; i++) { + bits2 = (uint8_t)(coeffs[i] & 0x3); + *octets |= bits2 << shift; + shift -= 2; + if (shift < 0) { + ++octets; + *octets = 0; + shift = 6; + } + } +} + + +/* ntru_trits_2_octet + * + * Packs 5 trits in an octet, where a trit is 0, 1, or 2 (-1). + */ + +void +ntru_trits_2_octet( + uint8_t const *trits, /* in - pointer to trits */ + uint8_t *octet) /* out - address for octet */ +{ + int i; + + assert(trits); + assert(octet); + + *octet = 0; + for (i = 4; i >= 0; i--) { + *octet = (*octet * 3) + trits[i]; + } +} + + +/* ntru_octet_2_trits + * + * Unpacks an octet to 5 trits, where a trit is 0, 1, or 2 (-1). + */ + +void +ntru_octet_2_trits( + uint8_t octet, /* in - octet to be unpacked */ + uint8_t *trits) /* out - address for trits */ +{ + int i; + + assert(trits); + + for (i = 0; i < 5; i++) { + trits[i] = octet % 3; + octet = (octet - trits[i]) / 3; + } +} + + +/* ntru_indices_2_trits + * + * Converts a list of the nonzero indices of a polynomial into an array of + * trits. + */ + +void +ntru_indices_2_trits( + uint16_t in_len, /* in - no. of indices */ + uint16_t const *in, /* in - pointer to list of indices */ + bool plus1, /* in - if list is +1 cofficients */ + uint8_t *out) /* out - address of output polynomial */ +{ + uint8_t trit = plus1 ? 1 : 2; + uint16_t i; + + assert(in); + assert(out); + + for (i = 0; i < in_len; i++) { + out[in[i]] = trit; + } +} + + +/* ntru_packed_trits_2_indices + * + * Unpacks an array of N trits and creates a list of array indices + * corresponding to trits = +1, and list of array indices corresponding to + * trits = -1. + */ + +void +ntru_packed_trits_2_indices( + uint8_t const *in, /* in - pointer to packed-trit octets */ + uint16_t num_trits, /* in - no. of packed trits */ + uint16_t *indices_plus1, /* out - address for indices of +1 trits */ + uint16_t *indices_minus1) /* out - address for indices of -1 trits */ +{ + uint8_t trits[5]; + uint16_t i = 0; + int j; + + assert(in); + assert(indices_plus1); + assert(indices_minus1); + + while (num_trits >= 5) { + ntru_octet_2_trits(*in++, trits); + num_trits -= 5; + for (j = 0; j < 5; j++, i++) { + if (trits[j] == 1) { + *indices_plus1 = i; + ++indices_plus1; + } else if (trits[j] == 2) { + *indices_minus1 = i; + ++indices_minus1; + } + } + } + if (num_trits) { + ntru_octet_2_trits(*in, trits); + for (j = 0; num_trits && (j < 5); j++, i++) { + if (trits[j] == 1) { + *indices_plus1 = i; + ++indices_plus1; + } else if (trits[j] == 2) { + *indices_minus1 = i; + ++indices_minus1; + } + --num_trits; + } + } +} + + +/* ntru_indices_2_packed_trits + * + * Takes a list of array indices corresponding to elements whose values + * are +1 or -1, and packs the N-element array of trits described by these + * lists into octets, 5 trits per octet. + */ + +void +ntru_indices_2_packed_trits( + uint16_t const *indices, /* in - pointer to indices */ + uint16_t num_plus1, /* in - no. of indices for +1 trits */ + uint16_t num_minus1, /* in - no. of indices for -1 trits */ + uint16_t num_trits, /* in - N, no. of trits in array */ + uint8_t *buf, /* in - temp buf, N octets */ + uint8_t *out) /* out - address for packed octets */ +{ + assert(indices); + assert(buf); + assert(out); + + /* convert indices to an array of trits */ + + memset(buf, 0, num_trits); + ntru_indices_2_trits(num_plus1, indices, TRUE, buf); + ntru_indices_2_trits(num_minus1, indices + num_plus1, FALSE, buf); + + /* pack the array of trits */ + + while (num_trits >= 5) { + ntru_trits_2_octet(buf, out); + num_trits -= 5; + buf += 5; + ++out; + } + if (num_trits) { + uint8_t trits[5]; + + memcpy(trits, buf, num_trits); + memset(trits + num_trits, 0, sizeof(trits) - num_trits); + ntru_trits_2_octet(trits, out); + } +} + + +/* ntru_elements_2_octets + * + * Packs an array of n-bit elements into an array of + * ((in_len * n_bits) + 7) / 8 octets, 8 < n_bits < 16. + */ + +void +ntru_elements_2_octets( + uint16_t in_len, /* in - no. of elements to be packed */ + uint16_t const *in, /* in - ptr to elements to be packed */ + uint8_t n_bits, /* in - no. of bits in input element */ + uint8_t *out) /* out - addr for output octets */ +{ + uint16_t temp; + int shift; + uint16_t i; + + assert(in_len); + assert(in); + assert((n_bits > 8) && (n_bits < 16)); + assert(out); + + /* pack */ + + temp = 0; + shift = n_bits - 8; + i = 0; + while (i < in_len) { + + /* add bits to temp to fill an octet and output the octet */ + + temp |= in[i] >> shift; + *out++ = (uint8_t)(temp & 0xff); + shift = 8 - shift; + if (shift < 1) { + + /* next full octet is in current input word */ + + shift += n_bits; + temp = 0; + + } else { + + /* put remaining bits of input word in temp as partial octet, + * and increment index to next input word + */ + temp = in[i] << (uint16_t)shift; + + ++i; + } + shift = n_bits - shift; + } + + /* output any bits remaining in last input word */ + + if (shift != n_bits - 8) { + *out++ = (uint8_t)(temp & 0xff); + } +} + + +/* ntru_octets_2_elements + * + * Unpacks an octet string into an array of ((in_len * 8) / n_bits) + * n-bit elements, 8 < n_bits < 16. Any extra bits are discarded. + */ + +void +ntru_octets_2_elements( + uint16_t in_len, /* in - no. of octets to be unpacked */ + uint8_t const *in, /* in - ptr to octets to be unpacked */ + uint8_t n_bits, /* in - no. of bits in output element */ + uint16_t *out) /* out - addr for output elements */ +{ + uint16_t temp; + uint16_t mask = (1 << n_bits) - 1; + int shift; + uint16_t i; + + assert(in_len > 1); + assert(in); + assert((n_bits > 8) && (n_bits < 16)); + assert(out); + + /* unpack */ + + temp = 0; + shift = n_bits; + i = 0; + while (i < in_len) { + shift = 8 - shift; + if (shift < 0) { + + /* the current octet will not fill the current element */ + + shift += n_bits; + + } else { + + /* add bits from the current octet to fill the current element and + * output the element + */ + + temp |= ((uint16_t)in[i]) >> shift; + *out++ = temp & mask; + temp = 0; + } + + /* add the remaining bits of the current octet to start an element */ + + shift = n_bits - shift; + temp |= ((uint16_t)in[i]) << shift; + ++i; + } +} + + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_convert.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_convert.h new file mode 100644 index 000000000..1c4b35b24 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_convert.h @@ -0,0 +1,183 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_convert.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_ntru_convert.h + * + * Contents: Definitions and declarations for conversion routines + * for NTRUEncrypt, including packing, unpacking and others. + * + *****************************************************************************/ + +#ifndef NTRU_CRYPTO_NTRU_CONVERT_H +#define NTRU_CRYPTO_NTRU_CONVERT_H + +#include "ntru_crypto.h" + + +/* function declarations */ + +/* ntru_bits_2_trits + * + * Each 3 bits in an array of octets is converted to 2 trits in an array + * of trits. + */ + +extern void +ntru_bits_2_trits( + uint8_t const *octets, /* in - pointer to array of octets */ + uint16_t num_trits, /* in - number of trits to produce */ + uint8_t *trits); /* out - address for array of trits */ + + +/* ntru_trits_2_bits + * + * Each 2 trits in an array of trits is converted to 3 bits, and the bits + * are packed in an array of octets. A multiple of 3 octets is output. + * Any bits in the final octets not derived from trits are zero. + * + * Returns TRUE if all trits were valid. + * Returns FALSE if invalid trits were found. + */ + +extern bool +ntru_trits_2_bits( + uint8_t const *trits, /* in - pointer to array of trits */ + uint32_t num_trits, /* in - number of trits to convert */ + uint8_t *octets); /* out - address for array of octets */ + + +/* ntru_coeffs_mod4_2_octets + * + * Takes an array of coefficients mod 4 and packs the results into an + * octet string. + */ + +extern void +ntru_coeffs_mod4_2_octets( + uint16_t num_coeffs, /* in - number of coefficients */ + uint16_t const *coeffs, /* in - pointer to coefficients */ + uint8_t *octets); /* out - address for octets */ + + +/* ntru_trits_2_octet + * + * Packs 5 trits in an octet, where a trit is 0, 1, or 2 (-1). + */ + +extern void +ntru_trits_2_octet( + uint8_t const *trits, /* in - pointer to trits */ + uint8_t *octet); /* out - address for octet */ + + +/* ntru_octet_2_trits + * + * Unpacks an octet to 5 trits, where a trit is 0, 1, or 2 (-1). + */ + +extern void +ntru_octet_2_trits( + uint8_t octet, /* in - octet to be unpacked */ + uint8_t *trits); /* out - address for trits */ + + +/* ntru_indices_2_trits + * + * Converts a list of the nonzero indices of a polynomial into an array of + * trits. + */ + +extern void +ntru_indices_2_trits( + uint16_t in_len, /* in - no. of indices */ + uint16_t const *in, /* in - pointer to list of indices */ + bool plus1, /* in - if list is +1 coefficients */ + uint8_t *out); /* out - address of output polynomial */ + + +/* ntru_packed_trits_2_indices + * + * Unpacks an array of N trits and creates a list of array indices + * corresponding to trits = +1, and list of array indices corresponding to + * trits = -1. + */ + +extern void +ntru_packed_trits_2_indices( + uint8_t const *in, /* in - pointer to packed-trit octets */ + uint16_t num_trits, /* in - no. of packed trits */ + uint16_t *indices_plus1, /* out - address for indices of +1 trits */ + uint16_t *indices_minus1); /* out - address for indices of -1 trits */ + + +/* ntru_indices_2_packed_trits + * + * Takes a list of array indices corresponding to elements whose values + * are +1 or -1, and packs the N-element array of trits described by these + * lists into octets, 5 trits per octet. + */ + +extern void +ntru_indices_2_packed_trits( + uint16_t const *indices, /* in - pointer to indices */ + uint16_t num_plus1, /* in - no. of indices for +1 trits */ + uint16_t num_minus1, /* in - no. of indices for -1 trits */ + uint16_t num_trits, /* in - N, no. of trits in array */ + uint8_t *buf, /* in - temp buf, N octets */ + uint8_t *out); /* out - address for packed octets */ + + +/* ntru_elements_2_octets + * + * Packs an array of n-bit elements into an array of + * ((in_len * n_bits) + 7) / 8 octets, 8 < n_bits < 16. + */ + +extern void +ntru_elements_2_octets( + uint16_t in_len, /* in - no. of elements to be packed */ + uint16_t const *in, /* in - ptr to elements to be packed */ + uint8_t n_bits, /* in - no. of bits in input element */ + uint8_t *out); /* out - addr for output octets */ + + +/* ntru_octets_2_elements + * + * Unpacks an octet string into an array of ((in_len * 8) / n_bits) + * n-bit elements, 8 < n < 16. Any extra bits are discarded. + */ + +extern void +ntru_octets_2_elements( + uint16_t in_len, /* in - no. of octets to be unpacked */ + uint8_t const *in, /* in - ptr to octets to be unpacked */ + uint8_t n_bits, /* in - no. of bits in output element */ + uint16_t *out); /* out - addr for output elements */ + + +#endif /* NTRU_CRYPTO_NTRU_CONVERT_H */ + + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt.c new file mode 100644 index 000000000..5f99446c6 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt.c @@ -0,0 +1,1292 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_encrypt.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_ntru_encrypt.c + * + * Contents: Routines implementing NTRUEncrypt encryption and decryption and + * key generation. + * + *****************************************************************************/ + + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "ntru_crypto.h" +#include "ntru_crypto_ntru_encrypt_param_sets.h" +#include "ntru_crypto_ntru_encrypt_key.h" +#include "ntru_crypto_ntru_convert.h" +#include "ntru_crypto_ntru_poly.h" +#include "ntru_crypto_ntru_mgf1.h" +#include "ntru_crypto_drbg.h" + + +/* ntru_crypto_ntru_encrypt + * + * Implements NTRU encryption (SVES) for the parameter set specified in + * the public key blob. + * + * Before invoking this function, a DRBG must be instantiated using + * ntru_crypto_drbg_instantiate() to obtain a DRBG handle, and in that + * instantiation the requested security strength must be at least as large + * as the security strength of the NTRU parameter set being used. + * Failure to instantiate the DRBG with the proper security strength will + * result in this function returning DRBG_ERROR_BASE + DRBG_BAD_LENGTH. + * + * The required minimum size of the output ciphertext buffer (ct) may be + * queried by invoking this function with ct = NULL. In this case, no + * encryption is performed, NTRU_OK is returned, and the required minimum + * size for ct is returned in ct_len. + * + * When ct != NULL, at invocation *ct_len must be the size of the ct buffer. + * Upon return it is the actual size of the ciphertext. + * + * Returns NTRU_OK if successful. + * Returns DRBG_ERROR_BASE + DRBG_BAD_PARAMETER if the DRBG handle is invalid. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PARAMETER if an argument pointer + * (other than ct) is NULL. + * Returns NTRU_ERROR_BASE + NTRU_BAD_LENGTH if a length argument + * (pubkey_blob_len or pt_len) is zero, or if pt_len exceeds the + * maximum plaintext length for the parameter set. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PUBLIC_KEY if the public-key blob is + * invalid (unknown format, corrupt, bad length). + * Returns NTRU_ERROR_BASE + NTRU_BUFFER_TOO_SMALL if the ciphertext buffer + * is too small. + * Returns NTRU_ERROR_BASE + NTRU_NO_MEMORY if memory needed cannot be + * allocated from the heap. + */ + +uint32_t +ntru_crypto_ntru_encrypt( + DRBG_HANDLE drbg_handle, /* in - handle of DRBG */ + uint16_t pubkey_blob_len, /* in - no. of octets in public key + blob */ + uint8_t const *pubkey_blob, /* in - pointer to public key */ + uint16_t pt_len, /* in - no. of octets in plaintext */ + uint8_t const *pt, /* in - pointer to plaintext */ + uint16_t *ct_len, /* in/out - no. of octets in ct, addr for + no. of octets in ciphertext */ + uint8_t *ct) /* out - address for ciphertext */ +{ + NTRU_ENCRYPT_PARAM_SET *params = NULL; + uint8_t const *pubkey_packed = NULL; + uint8_t pubkey_pack_type = 0x00; + uint16_t packed_ct_len; + size_t scratch_buf_len; + uint32_t dr; + uint32_t dr1 = 0; + uint32_t dr2 = 0; + uint32_t dr3 = 0; + uint16_t ring_mult_tmp_len; + int16_t m1 = 0; + uint16_t *scratch_buf = NULL; + uint16_t *ringel_buf = NULL; + uint16_t *r_buf = NULL; + uint8_t *b_buf = NULL; + uint8_t *tmp_buf = NULL; + bool msg_rep_good = FALSE; + NTRU_CRYPTO_HASH_ALGID hash_algid; + uint8_t md_len; + uint16_t mprime_len = 0; + uint16_t mod_q_mask; + uint32_t result = NTRU_OK; + + /* check for bad parameters */ + + if (!pubkey_blob || !pt || !ct_len) + NTRU_RET(NTRU_BAD_PARAMETER); + if ((pubkey_blob_len == 0) || (pt_len == 0)) + NTRU_RET(NTRU_BAD_LENGTH); + + /* get a pointer to the parameter-set parameters, the packing type for + * the public key, and a pointer to the packed public key + */ + + if (!ntru_crypto_ntru_encrypt_key_parse(TRUE /* pubkey */, pubkey_blob_len, + pubkey_blob, &pubkey_pack_type, + NULL, ¶ms, &pubkey_packed, + NULL)) + NTRU_RET(NTRU_BAD_PUBLIC_KEY); + + /* return the ciphertext size if requested */ + + packed_ct_len = (params->N * params->q_bits + 7) >> 3; + if (!ct) { + *ct_len = packed_ct_len; + NTRU_RET(NTRU_OK); + } + + /* check the ciphertext buffer size */ + + if (*ct_len < packed_ct_len) { + NTRU_RET(NTRU_BUFFER_TOO_SMALL); + } + + /* check the plaintext length */ + + if (pt_len > params->m_len_max) { + NTRU_RET(NTRU_BAD_LENGTH); + } + + /* allocate memory for all operations */ + + if (params->is_product_form) { + ring_mult_tmp_len = params->N << 1; /* 2N 16-bit word buffer */ + dr1 = params->dF_r & 0xff; + dr2 = (params->dF_r >> 8) & 0xff; + dr3 = (params->dF_r >> 16) & 0xff; + dr = dr1 + dr2 + dr3; + } else { + ring_mult_tmp_len = params->N; /* N 16-bit word buffer */ + dr = params->dF_r; + } + scratch_buf_len = (ring_mult_tmp_len << 1) + + /* X-byte temp buf for ring mult and + other intermediate results */ + (params->N << 1) + /* 2N-byte buffer for ring elements + and overflow from temp buffer */ + (dr << 2) + /* buffer for r indices */ + params->sec_strength_len; + /* buffer for b */ + scratch_buf = malloc(scratch_buf_len); + if (!scratch_buf) { + NTRU_RET(NTRU_OUT_OF_MEMORY); + } + ringel_buf = scratch_buf + ring_mult_tmp_len; + r_buf = ringel_buf + params->N; + b_buf = (uint8_t *)(r_buf + (dr << 1)); + tmp_buf = (uint8_t *)scratch_buf; + + /* set hash algorithm based on security strength */ + + if (params->sec_strength_len <= 20) { + hash_algid = NTRU_CRYPTO_HASH_ALGID_SHA1; + md_len = 20; + } else { + hash_algid = NTRU_CRYPTO_HASH_ALGID_SHA256; + md_len = 32; + } + + /* set constants */ + + mod_q_mask = params->q - 1; + + /* loop until a message representative with proper weight is achieved */ + + do { + uint8_t *ptr = tmp_buf; + + /* get b */ + result = ntru_crypto_drbg_generate(drbg_handle, + params->sec_strength_len << 3, + params->sec_strength_len, b_buf); + + if (result == NTRU_OK) { + + /* form sData (OID || m || b || hTrunc) */ + + memcpy(ptr, params->OID, 3); + ptr += 3; + memcpy(ptr, pt, pt_len); + ptr += pt_len; + memcpy(ptr, b_buf, params->sec_strength_len); + ptr += params->sec_strength_len; + memcpy(ptr, pubkey_packed, params->sec_strength_len); + ptr += params->sec_strength_len; + + + /* generate r */ + + result = ntru_gen_poly(hash_algid, md_len, + params->min_IGF_hash_calls, + (uint16_t)(ptr - tmp_buf), + tmp_buf, tmp_buf, + params->N, params->c_bits, + params->no_bias_limit, + params->is_product_form, + params->dF_r << 1, r_buf); + } + + if (result == NTRU_OK) { + uint16_t pubkey_packed_len; + + /* unpack the public key */ + + assert(pubkey_pack_type == NTRU_ENCRYPT_KEY_PACKED_COEFFICIENTS); + pubkey_packed_len = (params->N * params->q_bits + 7) >> 3; + ntru_octets_2_elements(pubkey_packed_len, pubkey_packed, + params->q_bits, ringel_buf); + + /* form R = h * r */ + + if (params->is_product_form) + ntru_ring_mult_product_indices(ringel_buf, (uint16_t)dr1, + (uint16_t)dr2, (uint16_t)dr3, + r_buf, params->N, params->q, + scratch_buf, ringel_buf); + else + ntru_ring_mult_indices(ringel_buf, (uint16_t)dr, (uint16_t)dr, + r_buf, params->N, params->q, + scratch_buf, ringel_buf); + + /* form R mod 4 */ + + ntru_coeffs_mod4_2_octets(params->N, ringel_buf, tmp_buf); + + /* form mask */ + + result = ntru_mgftp1(hash_algid, md_len, + params->min_MGF_hash_calls, + (params->N + 3) / 4, tmp_buf, + tmp_buf + params->N, params->N, tmp_buf); + } + if (result == NTRU_OK) { + uint8_t *Mtrin_buf = tmp_buf + params->N; + uint8_t *M_buf = Mtrin_buf + params->N - + (params->sec_strength_len + params->m_len_len + + params->m_len_max + 2); + uint16_t i; + + /* form the padded message M */ + + ptr = M_buf; + memcpy(ptr, b_buf, params->sec_strength_len); + ptr += params->sec_strength_len; + if (params->m_len_len == 2) + *ptr++ = (uint8_t)((pt_len >> 8) & 0xff); + *ptr++ = (uint8_t)(pt_len & 0xff); + memcpy(ptr, pt, pt_len); + ptr += pt_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, params->m_len_max - pt_len + 2); + + /* convert M to trits (Mbin to Mtrin) */ + + mprime_len = params->N; + if (params->is_product_form) + --mprime_len; + + ntru_bits_2_trits(M_buf, mprime_len, Mtrin_buf); + + /* form the msg representative m' by adding Mtrin to mask, mod p */ + + if (params->is_product_form) { + for (i = 0; i < mprime_len; i++) { + tmp_buf[i] = tmp_buf[i] + Mtrin_buf[i]; + if (tmp_buf[i] >= 3) + tmp_buf[i] -= 3; + if (tmp_buf[i] == 1) + ++m1; + else if (tmp_buf[i] == 2) + --m1; + } + } else { + for (i = 0; i < mprime_len; i++) { + tmp_buf[i] = tmp_buf[i] + Mtrin_buf[i]; + if (tmp_buf[i] >= 3) + tmp_buf[i] -= 3; + } + } + + /* check that message representative meets minimum weight + * requirements + */ + + if (params->is_product_form) + msg_rep_good = m1 < 0 ? (bool)(-m1 <= params->min_msg_rep_wt) : + (bool)( m1 <= params->min_msg_rep_wt); + else + msg_rep_good = ntru_poly_check_min_weight(mprime_len, tmp_buf, + params->min_msg_rep_wt); + msg_rep_good = TRUE; + } + } while ((result == NTRU_OK) && !msg_rep_good); + + if (result == NTRU_OK) { + uint16_t i; + + /* form ciphertext e by adding m' to R mod q */ + + for (i = 0; i < mprime_len; i++) { + if (tmp_buf[i] == 1) + ringel_buf[i] = (ringel_buf[i] + 1) & mod_q_mask; + else if (tmp_buf[i] == 2) + ringel_buf[i] = (ringel_buf[i] - 1) & mod_q_mask; + } + if (params->is_product_form) + ringel_buf[i] = (ringel_buf[i] - m1) & mod_q_mask; + + /* pack ciphertext */ + + ntru_elements_2_octets(params->N, ringel_buf, params->q_bits, ct); + *ct_len = packed_ct_len; + } + + /* cleanup */ + + memset(scratch_buf, 0, scratch_buf_len); + free(scratch_buf); + + return result; +} + + +/* ntru_crypto_ntru_decrypt + * + * Implements NTRU decryption (SVES) for the parameter set specified in + * the private key blob. + * + * The maximum size of the output plaintext may be queried by invoking + * this function with pt = NULL. In this case, no decryption is performed, + * NTRU_OK is returned, and the maximum size the plaintext could be is + * returned in pt_len. + * Note that until the decryption is performed successfully, the actual size + * of the resulting plaintext cannot be known. + * + * When pt != NULL, at invocation *pt_len must be the size of the pt buffer. + * Upon return it is the actual size of the plaintext. + * + * Returns NTRU_OK if successful. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PARAMETER if an argument pointer + * (other than pt) is NULL. + * Returns NTRU_ERROR_BASE + NTRU_BAD_LENGTH if a length argument + * (privkey_blob) is zero, or if ct_len is invalid for the parameter set. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PRIVATE_KEY if the private-key blob is + * invalid (unknown format, corrupt, bad length). + * Returns NTRU_ERROR_BASE + NTRU_BUFFER_TOO_SMALL if the plaintext buffer + * is too small. + * Returns NTRU_ERROR_BASE + NTRU_NO_MEMORY if memory needed cannot be + * allocated from the heap. + * Returns NTRU_ERROR_BASE + NTRU_FAIL if a decryption error occurs. + */ + +uint32_t +ntru_crypto_ntru_decrypt( + uint16_t privkey_blob_len, /* in - no. of octets in private key + blob */ + uint8_t const *privkey_blob, /* in - pointer to private key */ + uint16_t ct_len, /* in - no. of octets in ciphertext */ + uint8_t const *ct, /* in - pointer to ciphertext */ + uint16_t *pt_len, /* in/out - no. of octets in pt, addr for + no. of octets in plaintext */ + uint8_t *pt) /* out - address for plaintext */ +{ + NTRU_ENCRYPT_PARAM_SET *params = NULL; + uint8_t const *privkey_packed = NULL; + uint8_t const *pubkey_packed = NULL; + uint8_t privkey_pack_type = 0x00; + uint8_t pubkey_pack_type = 0x00; + size_t scratch_buf_len; + uint32_t dF_r; + uint32_t dF_r1 = 0; + uint32_t dF_r2 = 0; + uint32_t dF_r3 = 0; + uint16_t ring_mult_tmp_len; + int16_t m1 = 0; + uint16_t *scratch_buf = NULL; + uint16_t *ringel_buf1 = NULL; + uint16_t *ringel_buf2 = NULL; + uint16_t *i_buf = NULL; + uint8_t *m_buf = NULL; + uint8_t *tmp_buf = NULL; + uint8_t *Mtrin_buf = NULL; + uint8_t *M_buf = NULL; + uint8_t *ptr = NULL; + NTRU_CRYPTO_HASH_ALGID hash_algid; + uint8_t md_len; + uint16_t cmprime_len; + uint16_t mod_q_mask; + uint16_t q_mod_p; + uint16_t cm_len = 0; + uint16_t num_zeros; + uint16_t i; + bool decryption_ok = TRUE; + uint32_t result = NTRU_OK; + + /* check for bad parameters */ + + if (!privkey_blob || !ct || !pt_len) + NTRU_RET(NTRU_BAD_PARAMETER); + if ((privkey_blob_len == 0) || (ct_len == 0)) + NTRU_RET(NTRU_BAD_LENGTH); + + /* get a pointer to the parameter-set parameters, the packing types for + * the public and private keys, and pointers to the packed public and + * private keys + */ + + if (!ntru_crypto_ntru_encrypt_key_parse(FALSE /* privkey */, + privkey_blob_len, + privkey_blob, &pubkey_pack_type, + &privkey_pack_type, ¶ms, + &pubkey_packed, &privkey_packed)) + NTRU_RET(NTRU_BAD_PRIVATE_KEY); + + /* return the max plaintext size if requested */ + + if (!pt) { + *pt_len = params->m_len_max; + NTRU_RET(NTRU_OK); + } + + /* cannot check the plaintext buffer size until after the plaintext + * is derived, if we allow plaintext buffers only as large as the + * actual plaintext + */ + + /* check the ciphertext length */ + + if (ct_len != (params->N * params->q_bits + 7) >> 3) + NTRU_RET(NTRU_BAD_LENGTH); + + /* allocate memory for all operations */ + + if (params->is_product_form) { + ring_mult_tmp_len = params->N << 1; /* 2N 16-bit word buffer */ + dF_r1 = params->dF_r & 0xff; + dF_r2 = (params->dF_r >> 8) & 0xff; + dF_r3 = (params->dF_r >> 16) & 0xff; + dF_r = dF_r1 + dF_r2 + dF_r3; + } else { + ring_mult_tmp_len = params->N; /* N 16-bit word buffer */ + dF_r = params->dF_r; + } + scratch_buf_len = (ring_mult_tmp_len << 1) + + /* X-byte temp buf for ring mult and + other intermediate results */ + (params->N << 2) + /* 2 2N-byte bufs for ring elements + and overflow from temp buffer */ + (dF_r << 2) + /* buffer for F, r indices */ + params->m_len_max; /* buffer for plaintext */ + scratch_buf = malloc(scratch_buf_len); + if (!scratch_buf) { + NTRU_RET(NTRU_OUT_OF_MEMORY); + } + ringel_buf1 = scratch_buf + ring_mult_tmp_len; + ringel_buf2 = ringel_buf1 + params->N; + i_buf = ringel_buf2 + params->N; + m_buf = (uint8_t *)(i_buf + (dF_r << 1)); + tmp_buf = (uint8_t *)scratch_buf; + Mtrin_buf = (uint8_t *)ringel_buf1; + M_buf = Mtrin_buf + params->N; + + /* set hash algorithm based on security strength */ + + if (params->sec_strength_len <= 20) { + hash_algid = NTRU_CRYPTO_HASH_ALGID_SHA1; + md_len = 20; + } else { + hash_algid = NTRU_CRYPTO_HASH_ALGID_SHA256; + md_len = 32; + } + + /* set constants */ + + mod_q_mask = params->q - 1; + q_mod_p = params->q % 3; + + /* unpack the ciphertext */ + + ntru_octets_2_elements(ct_len, ct, params->q_bits, ringel_buf2); + + /* unpack the private key */ + + if (privkey_pack_type == NTRU_ENCRYPT_KEY_PACKED_TRITS) { + ntru_packed_trits_2_indices(privkey_packed, params->N, i_buf, + i_buf + dF_r); + + } else if (privkey_pack_type == NTRU_ENCRYPT_KEY_PACKED_INDICES) { + ntru_octets_2_elements( + (((uint16_t)dF_r << 1) * params->N_bits + 7) >> 3, + privkey_packed, params->N_bits, i_buf); + + } else { + assert(FALSE); + } + + /* form cm': + * F * e + * A = e * (1 + pF) mod q = e + pFe mod q + * a = A in the range [-q/2, q/2) + * cm' = a mod p + */ + + cmprime_len = params->N; + if (params->is_product_form) { + --cmprime_len; + ntru_ring_mult_product_indices(ringel_buf2, (uint16_t)dF_r1, + (uint16_t)dF_r2, (uint16_t)dF_r3, + i_buf, params->N, params->q, + scratch_buf, ringel_buf1); + for (i = 0; i < cmprime_len; i++) { + ringel_buf1[i] = (ringel_buf2[i] + 3 * ringel_buf1[i]) & mod_q_mask; + if (ringel_buf1[i] >= (params->q >> 1)) + ringel_buf1[i] = ringel_buf1[i] - q_mod_p; + Mtrin_buf[i] = (uint8_t)(ringel_buf1[i] % 3); + if (Mtrin_buf[i] == 1) + ++m1; + else if (Mtrin_buf[i] == 2) + --m1; + } + } else { + ntru_ring_mult_indices(ringel_buf2, (uint16_t)dF_r, (uint16_t)dF_r, + i_buf, params->N, params->q, + scratch_buf, ringel_buf1); + for (i = 0; i < cmprime_len; i++) { + ringel_buf1[i] = (ringel_buf2[i] + 3 * ringel_buf1[i]) & mod_q_mask; + if (ringel_buf1[i] >= (params->q >> 1)) + ringel_buf1[i] = ringel_buf1[i] - q_mod_p; + Mtrin_buf[i] = (uint8_t)(ringel_buf1[i] % 3); + } + } + + /* check that the candidate message representative meets minimum weight + * requirements + */ + + if (params->is_product_form) + decryption_ok = m1 < 0 ? (bool)(-m1 <= params->min_msg_rep_wt) : + (bool)( m1 <= params->min_msg_rep_wt); + else + decryption_ok = ntru_poly_check_min_weight(cmprime_len, Mtrin_buf, + params->min_msg_rep_wt); + + /* form cR = e - cm' mod q */ + + for (i = 0; i < cmprime_len; i++) { + if (Mtrin_buf[i] == 1) + ringel_buf2[i] = --ringel_buf2[i] & mod_q_mask; + else if (Mtrin_buf[i] == 2) + ringel_buf2[i] = ++ringel_buf2[i] & mod_q_mask; + } + if (params->is_product_form) + ringel_buf2[i] = (ringel_buf2[i] + m1) & mod_q_mask; + + + /* form cR mod 4 */ + + ntru_coeffs_mod4_2_octets(params->N, ringel_buf2, tmp_buf); + + /* form mask */ + + result = ntru_mgftp1(hash_algid, md_len, + params->min_MGF_hash_calls, + (params->N + 3) / 4, tmp_buf, + tmp_buf + params->N, params->N, tmp_buf); + + if (result == NTRU_OK) { + + /* form cMtrin by subtracting mask from cm', mod p */ + + for (i = 0; i < cmprime_len; i++) { + Mtrin_buf[i] = Mtrin_buf[i] - tmp_buf[i]; + if (Mtrin_buf[i] >= 3) + Mtrin_buf[i] += 3; + } + if (params->is_product_form) + + /* set the last trit to zero since that's what it was, and + * because it can't be calculated from (cm' - mask) since + * we don't have the correct value for the last cm' trit + */ + + Mtrin_buf[i] = 0; + + /* convert cMtrin to cM (Mtrin to Mbin) */ + + if (!ntru_trits_2_bits(Mtrin_buf, params->N, M_buf)) + decryption_ok = FALSE; + + /* validate the padded message cM and copy cm to m_buf */ + + ptr = M_buf + params->sec_strength_len; + if (params->m_len_len == 2) + cm_len = (uint16_t)(*ptr++) << 16; + cm_len |= (uint16_t)(*ptr++); + if (cm_len > params->m_len_max) { + cm_len = params->m_len_max; + decryption_ok = FALSE; + } + memcpy(m_buf, ptr, cm_len); + ptr += cm_len; + num_zeros = params->m_len_max - cm_len + 1; + for (i = 0; i < num_zeros; i++) { + if (ptr[i] != 0) + decryption_ok = FALSE; + } + + /* form sData (OID || m || b || hTrunc) */ + + ptr = tmp_buf; + memcpy(ptr, params->OID, 3); + ptr += 3; + memcpy(ptr, m_buf, cm_len); + ptr += cm_len; + memcpy(ptr, M_buf, params->sec_strength_len); + ptr += params->sec_strength_len; + memcpy(ptr, pubkey_packed, params->sec_strength_len); + ptr += params->sec_strength_len; + + /* generate cr */ + + result = ntru_gen_poly(hash_algid, md_len, + params->min_IGF_hash_calls, + (uint16_t)(ptr - tmp_buf), + tmp_buf, tmp_buf, + params->N, params->c_bits, + params->no_bias_limit, + params->is_product_form, + params->dF_r << 1, i_buf); + } + + if (result == NTRU_OK) { + + /* unpack the public key */ + + { + uint16_t pubkey_packed_len; + + assert(pubkey_pack_type == NTRU_ENCRYPT_KEY_PACKED_COEFFICIENTS); + pubkey_packed_len = (params->N * params->q_bits + 7) >> 3; + ntru_octets_2_elements(pubkey_packed_len, pubkey_packed, + params->q_bits, ringel_buf1); + } + + /* form cR' = h * cr */ + + if (params->is_product_form) + ntru_ring_mult_product_indices(ringel_buf1, (uint16_t)dF_r1, + (uint16_t)dF_r2, (uint16_t)dF_r3, + i_buf, params->N, params->q, + scratch_buf, ringel_buf1); + else + ntru_ring_mult_indices(ringel_buf1, (uint16_t)dF_r, (uint16_t)dF_r, + i_buf, params->N, params->q, + scratch_buf, ringel_buf1); + + /* compare cR' to cR */ + + for (i = 0; i < params->N; i++) { + if (ringel_buf1[i] != ringel_buf2[i]) + decryption_ok = FALSE; + } + + /* output plaintext and plaintext length */ + + if (decryption_ok) { + if (*pt_len < cm_len) + NTRU_RET(NTRU_BUFFER_TOO_SMALL); + memcpy(pt, m_buf, cm_len); + *pt_len = cm_len; + } + } + + /* cleanup */ + + memset(scratch_buf, 0, scratch_buf_len); + free(scratch_buf); + + if (!decryption_ok) + NTRU_RET(NTRU_FAIL); + return result; +} + + +/* ntru_crypto_ntru_encrypt_keygen + * + * Implements key generation for NTRUEncrypt for the parameter set specified. + * + * Before invoking this function, a DRBG must be instantiated using + * ntru_crypto_drbg_instantiate() to obtain a DRBG handle, and in that + * instantiation the requested security strength must be at least as large + * as the security strength of the NTRU parameter set being used. + * Failure to instantiate the DRBG with the proper security strength will + * result in this function returning DRBG_ERROR_BASE + DRBG_BAD_LENGTH. + * + * The required minimum size of the output public-key buffer (pubkey_blob) + * may be queried by invoking this function with pubkey_blob = NULL. + * In this case, no key generation is performed, NTRU_OK is returned, and + * the required minimum size for pubkey_blob is returned in pubkey_blob_len. + * + * The required minimum size of the output private-key buffer (privkey_blob) + * may be queried by invoking this function with privkey_blob = NULL. + * In this case, no key generation is performed, NTRU_OK is returned, and + * the required minimum size for privkey_blob is returned in privkey_blob_len. + * + * The required minimum sizes of both pubkey_blob and privkey_blob may be + * queried as described above, in a single invocation of this function. + * + * When pubkey_blob != NULL and privkey_blob != NULL, at invocation + * *pubkey_blob_len must be the size of the pubkey_blob buffer and + * *privkey_blob_len must be the size of the privkey_blob buffer. + * Upon return, *pubkey_blob_len is the actual size of the public-key blob + * and *privkey_blob_len is the actual size of the private-key blob. + * + * Returns NTRU_OK if successful. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PARAMETER if an argument pointer + * (other than pubkey_blob or privkey_blob) is NULL. + * Returns NTRU_ERROR_BASE + NTRU_INVALID_PARAMETER_SET if the parameter-set + * ID is invalid. + * Returns NTRU_ERROR_BASE + NTRU_BAD_LENGTH if a length argument is invalid. + * Returns NTRU_ERROR_BASE + NTRU_BUFFER_TOO_SMALL if either the pubkey_blob + * buffer or the privkey_blob buffer is too small. + * Returns NTRU_ERROR_BASE + NTRU_NO_MEMORY if memory needed cannot be + * allocated from the heap. + * Returns NTRU_ERROR_BASE + NTRU_FAIL if the polynomial generated for f is + * not invertible in (Z/qZ)[X]/(X^N - 1), which is extremely unlikely. + * Should this occur, this function should simply be invoked again. + */ + +uint32_t +ntru_crypto_ntru_encrypt_keygen( + DRBG_HANDLE drbg_handle, /* in - handle of DRBG */ + NTRU_ENCRYPT_PARAM_SET_ID param_set_id, /* in - parameter set ID */ + uint16_t *pubkey_blob_len, /* in/out - no. of octets in + pubkey_blob, addr + for no. of octets + in pubkey_blob */ + uint8_t *pubkey_blob, /* out - address for + public key blob */ + uint16_t *privkey_blob_len, /* in/out - no. of octets in + privkey_blob, addr + for no. of octets + in privkey_blob */ + uint8_t *privkey_blob) /* out - address for + private key blob */ +{ + NTRU_ENCRYPT_PARAM_SET *params = NULL; + uint16_t public_key_blob_len; + uint16_t private_key_blob_len; + uint8_t pubkey_pack_type; + uint8_t privkey_pack_type; + size_t scratch_buf_len; + uint32_t dF; + uint32_t dF1 = 0; + uint32_t dF2 = 0; + uint32_t dF3 = 0; + uint16_t *scratch_buf = NULL; + uint16_t *ringel_buf1 = NULL; + uint16_t *ringel_buf2 = NULL; + uint16_t *F_buf = NULL; + uint8_t *tmp_buf = NULL; + uint16_t mod_q_mask; + NTRU_CRYPTO_HASH_ALGID hash_algid; + uint8_t md_len; + uint16_t seed_len; + uint32_t result = NTRU_OK; + + /* get a pointer to the parameter-set parameters */ + + if ((params = ntru_encrypt_get_params_with_id(param_set_id)) == NULL) + NTRU_RET(NTRU_INVALID_PARAMETER_SET); + + /* check for bad parameters */ + + if (!pubkey_blob_len || !privkey_blob_len) + NTRU_RET(NTRU_BAD_PARAMETER); + + /* get public and private key packing types and blob lengths */ + + ntru_crypto_ntru_encrypt_key_get_blob_params(params, &pubkey_pack_type, + &public_key_blob_len, + &privkey_pack_type, + &private_key_blob_len); + + /* return the pubkey_blob size and/or privkey_blob size if requested */ + + if (!pubkey_blob || !privkey_blob) { + if (!pubkey_blob) + *pubkey_blob_len = public_key_blob_len; + if (!privkey_blob) + *privkey_blob_len = private_key_blob_len; + NTRU_RET(NTRU_OK); + } + + /* check size of output buffers */ + + if ((*pubkey_blob_len < public_key_blob_len) || + (*privkey_blob_len < private_key_blob_len)) + NTRU_RET(NTRU_BUFFER_TOO_SMALL); + + /* allocate memory for all operations */ + + if (params->is_product_form) { + dF1 = params->dF_r & 0xff; + dF2 = (params->dF_r >> 8) & 0xff; + dF3 = (params->dF_r >> 16) & 0xff; + dF = dF1 + dF2 + dF3; + } else { + dF = params->dF_r; + } + + scratch_buf_len = (params->N * 8) + /* 4N-byte temp buffer for ring inv + and other intermediate results, + 2N-byte buffer for f, g indices + and overflow from temp buffer, + 2N-byte buffer for f^-1 */ + (dF << 2); /* buffer for F indices */ + scratch_buf = malloc(scratch_buf_len); + if (!scratch_buf) { + NTRU_RET(NTRU_OUT_OF_MEMORY); + } + ringel_buf1 = scratch_buf + (params->N << 1); + ringel_buf2 = ringel_buf1 + params->N; + F_buf = ringel_buf2 + params->N; + tmp_buf = (uint8_t *)scratch_buf; + + /* set hash algorithm and seed length based on security strength */ + + if (params->sec_strength_len <= 20) { + hash_algid = NTRU_CRYPTO_HASH_ALGID_SHA1; + md_len = 20; + } else { + hash_algid = NTRU_CRYPTO_HASH_ALGID_SHA256; + md_len = 32; + } + seed_len = params->sec_strength_len + 8; + + /* set constants */ + + mod_q_mask = params->q - 1; + + /* get random bytes for seed for generating trinary F + * as a list of indices + */ + + result = ntru_crypto_drbg_generate(drbg_handle, + params->sec_strength_len << 3, + seed_len, tmp_buf); + + if (result == NTRU_OK) { + + /* generate F */ + + result = ntru_gen_poly(hash_algid, md_len, + params->min_IGF_hash_calls, + seed_len, tmp_buf, tmp_buf, + params->N, params->c_bits, + params->no_bias_limit, + params->is_product_form, + params->dF_r << 1, F_buf); + } + + if (result == NTRU_OK) { + uint32_t i; + + memset(ringel_buf1, 0, params->N * sizeof(uint16_t)); + + /* form F as a ring element */ + + if (params->is_product_form) { + uint32_t dF3_offset = (dF1 + dF2) << 1; + + /* form F1 as a ring element */ + + for (i = 0; i < dF1; i++) + ringel_buf1[F_buf[i]] = 1; + for (; i < (dF1 << 1); i++) + ringel_buf1[F_buf[i]] = mod_q_mask; + + /* form F1 * F2 */ + + ntru_ring_mult_indices(ringel_buf1, (uint16_t)dF2, (uint16_t)dF2, + F_buf + (dF1 << 1), params->N, params->q, + scratch_buf, ringel_buf1); + + /* form (F1 * F2) + F3 */ + + for (i = 0; i < dF3; i++) { + uint16_t index = F_buf[dF3_offset + i]; + ringel_buf1[index] = ++ringel_buf1[index] & mod_q_mask; + } + for (; i < (dF3 << 1); i++) { + uint16_t index = F_buf[dF3_offset + i]; + ringel_buf1[index] = --ringel_buf1[index] & mod_q_mask; + } + + } else { + + /* form F as a ring element */ + + for (i = 0; i < dF; i++) + ringel_buf1[F_buf[i]] = 1; + for (; i < (dF << 1); i++) + ringel_buf1[F_buf[i]] = mod_q_mask; + } + + /* form f = 1 + pF */ + + for (i = 0; i < params->N; i++) + ringel_buf1[i] = (ringel_buf1[i] * 3) & mod_q_mask; + ringel_buf1[0] = (ringel_buf1[0] + 1) & mod_q_mask; + + /* find f^-1 in (Z/qZ)[X]/(X^N - 1) */ + + if (!ntru_ring_inv(ringel_buf1, params->N, params->q, + scratch_buf, ringel_buf2)) + result = NTRU_ERROR_BASE + NTRU_FAIL; + } + + if (result == NTRU_OK) { + + /* get random bytes for seed for generating trinary g + * as a list of indices + */ + result = ntru_crypto_drbg_generate(drbg_handle, + params->sec_strength_len << 3, + seed_len, tmp_buf); + } + + if (result == NTRU_OK) { + uint16_t min_IGF_hash_calls = + ((((params->dg << 2) + 2) * params->N_bits) + (md_len << 3) - 1) / + (md_len << 3); + + /* generate g */ + + result = ntru_gen_poly(hash_algid, md_len, + (uint8_t)min_IGF_hash_calls, + seed_len, tmp_buf, tmp_buf, + params->N, params->c_bits, + params->no_bias_limit, FALSE, + (params->dg << 1) + 1, ringel_buf1); + } + + if (result == NTRU_OK) { + uint16_t i; + + /* compute h = p * (f^-1 * g) mod q */ + + ntru_ring_mult_indices(ringel_buf2, params->dg + 1, params->dg, + ringel_buf1, params->N, params->q, scratch_buf, + ringel_buf2); + + for (i = 0; i < params->N; i++) + ringel_buf2[i] = (ringel_buf2[i] * 3) & mod_q_mask; + + /* create public key blob */ + + ntru_crypto_ntru_encrypt_key_create_pubkey_blob(params, ringel_buf2, + pubkey_pack_type, + pubkey_blob); + *pubkey_blob_len = public_key_blob_len; + + /* create private key blob */ + + ntru_crypto_ntru_encrypt_key_create_privkey_blob(params, ringel_buf2, + F_buf, + privkey_pack_type, + tmp_buf, privkey_blob); + *privkey_blob_len = private_key_blob_len; + } + + /* cleanup */ + + memset(scratch_buf, 0, scratch_buf_len); + free(scratch_buf); + + return result; +} + + +/* DER-encoding prefix template for NTRU public keys, + * with parameter-set-specific fields nomalized + */ + +static uint8_t const der_prefix_template[] = { + 0x30, 0x82, + 0x00, 0x23, /* add pubkey length */ + 0x30, 0x18, 0x06, 0x0a, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0xc1, 0x70, 0x01, 0x01, 0x02, /* end of NTRU OID compare */ + 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, + 0xc1, 0x70, 0x01, 0x02, + 0x00, /* set param-set DER id */ + 0x03, 0x82, + 0x00, 0x05, /* add pubkey length */ + 0x00, 0x04, 0x82, + 0x00, 0x00, /* add pubkey length */ +}; + + +/* add_16_to_8s + * + * adds a 16-bit value to two bytes + */ + +static void +add_16_to_8s( + uint16_t a, + uint8_t *b) +{ + uint16_t tmp = ((uint16_t)b[0] << 8) + b[1]; + + tmp = tmp + a; + b[0] = (uint8_t)((tmp >> 8) & 0xff); + b[1] = (uint8_t)(tmp & 0xff); +} + + +/* sub_16_from_8s + * + * subtracts a 16-bit value from two bytes + */ + +static void +sub_16_from_8s( + uint16_t a, + uint8_t *b) +{ + uint16_t tmp = ((uint16_t)b[0] << 8) + b[1]; + + tmp = tmp - a; + b[0] = (uint8_t)((tmp >> 8) & 0xff); + b[1] = (uint8_t)(tmp & 0xff); +} + + +/* ntru_crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo + * + * DER-encodes an NTRUEncrypt public-key from a public-key blob into a + * SubjectPublicKeyInfo field for inclusion in an X.509 certificate. + * + * The required minimum size of the output SubjectPublicKeyInfo buffer + * (encoded_subjectPublicKeyInfo) may be queried by invoking this function + * with encoded_subjectPublicKeyInfo = NULL. In this case, no encoding is + * performed, NTRU_OK is returned, and the required minimum size for + * encoded_subjectPublicKeyInfo is returned in encoded_subjectPublicKeyInfo_len. + * + * When encoded_subjectPublicKeyInfo != NULL, at invocation + * *encoded_subjectPublicKeyInfo_len must be the size of the + * encoded_subjectPublicKeyInfo buffer. + * Upon return, it is the actual size of the encoded public key. + * + * Returns NTRU_OK if successful. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PARAMETER if an argument pointer + * (other than encoded_subjectPublicKeyInfo) is NULL. + * Returns NTRU_ERROR_BASE + NTRU_BAD_LENGTH if pubkey_blob_len is zero. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PUBLIC_KEY if the public-key blob is + * invalid (unknown format, corrupt, bad length). + * Returns NTRU_ERROR_BASE + NTRU_BUFFER_TOO_SMALL if the SubjectPublicKeyInfo + * buffer is too small. + */ + +uint32_t +ntru_crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( + uint16_t pubkey_blob_len, /* in - no. of octets in public-key + blob */ + uint8_t const *pubkey_blob, /* in - ptr to public-key blob */ + uint16_t *encoded_subjectPublicKeyInfo_len, + /* in/out - no. of octets in encoded info, + address for no. of octets in + encoded info */ + uint8_t *encoded_subjectPublicKeyInfo) + /* out - address for encoded info */ +{ + NTRU_ENCRYPT_PARAM_SET *params = NULL; + uint8_t const *pubkey_packed = NULL; + uint8_t pubkey_pack_type; + uint16_t packed_pubkey_len; + uint16_t encoded_len; + + /* check for bad parameters */ + + if (!pubkey_blob || !encoded_subjectPublicKeyInfo_len) + NTRU_RET(NTRU_BAD_PARAMETER); + if (pubkey_blob_len == 0) + NTRU_RET(NTRU_BAD_LENGTH); + + /* get a pointer to the parameter-set parameters, the packing type for + * the public key, and a pointer to the packed public key + */ + + if (!ntru_crypto_ntru_encrypt_key_parse(TRUE /* pubkey */, pubkey_blob_len, + pubkey_blob, &pubkey_pack_type, + NULL, ¶ms, &pubkey_packed, + NULL)) + NTRU_RET(NTRU_BAD_PUBLIC_KEY); + + /* return the encoded_subjectPublicKeyInfo size if requested */ + + packed_pubkey_len = (params->N * params->q_bits + 7) >> 3; + encoded_len = sizeof(der_prefix_template) + packed_pubkey_len; + if (!encoded_subjectPublicKeyInfo) { + *encoded_subjectPublicKeyInfo_len = encoded_len; + NTRU_RET(NTRU_OK); + } + + /* check the encoded_subjectPublicKeyInfo buffer size */ + + if (*encoded_subjectPublicKeyInfo_len < encoded_len) { + NTRU_RET(NTRU_BUFFER_TOO_SMALL); + } + + /* form the encoded subjectPublicKey */ + + memcpy(encoded_subjectPublicKeyInfo, der_prefix_template, + sizeof(der_prefix_template)); + add_16_to_8s(packed_pubkey_len, encoded_subjectPublicKeyInfo + 2); + add_16_to_8s(packed_pubkey_len, encoded_subjectPublicKeyInfo + 32); + add_16_to_8s(packed_pubkey_len, encoded_subjectPublicKeyInfo + 37); + encoded_subjectPublicKeyInfo[29] = params->der_id; + memcpy(encoded_subjectPublicKeyInfo + sizeof(der_prefix_template), + pubkey_packed, packed_pubkey_len); + + *encoded_subjectPublicKeyInfo_len = encoded_len; + + NTRU_RET(NTRU_OK); +} + + +/* ntru_crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey + * + * Decodes a DER-encoded NTRUEncrypt public-key from a + * SubjectPublicKeyInfo field in an X.509 certificate and returns the + * public-key blob itself. + * + * The required minimum size of the output public-key buffer (pubkey_blob) + * may be queried by invoking this function with pubkey_blob = NULL. + * In this case, no decoding is performed, NTRU_OK is returned, and the + * required minimum size for pubkey_blob is returned in pubkey_blob_len. + * + * When pubkey_blob != NULL, at invocation *pubkey_blob_len must be the + * size of the pubkey_blob buffer. + * Upon return, it is the actual size of the public-key blob. + * + * Returns NTRU_OK if successful. + * Returns NTRU_ERROR_BASE + NTRU_BAD_PARAMETER if an argument pointer + * (other than pubkey_blob) is NULL. + * Returns NTRU_ERROR_BASE + NTRU_BAD_ENCODING if the encoded data is + * an invalid encoding of an NTRU public key. + * Returns NTRU_ERROR_BASE + NTRU_OID_NOT_RECOGNIZED if the + * encoded data contains an OID that identifies an object other than + * an NTRU public key. + * Returns NTRU_ERROR_BASE + NTRU_BUFFER_TOO_SMALL if the pubkey_blob buffer + * is too small. + */ + +uint32_t +ntru_crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey( + uint8_t const *encoded_data, /* in - ptr to subjectPublicKeyInfo + in the encoded data */ + uint16_t *pubkey_blob_len, /* in/out - no. of octets in pubkey blob, + address for no. of octets in + pubkey blob */ + uint8_t *pubkey_blob, /* out - address for pubkey blob */ + uint8_t **next) /* out - address for ptr to encoded + data following the + subjectPublicKeyInfo */ +{ + NTRU_ENCRYPT_PARAM_SET *params = NULL; + uint8_t prefix_buf[39]; + bool der_id_valid; + uint16_t packed_pubkey_len = 0; + uint8_t pubkey_pack_type; + uint16_t public_key_blob_len; + + /* check for bad parameters */ + + if (!encoded_data || !pubkey_blob_len || !next) + NTRU_RET(NTRU_BAD_PARAMETER); + + /* determine if data to be decoded is a valid encoding of an NTRU + * public key + */ + + memcpy(prefix_buf, encoded_data, sizeof(prefix_buf)); + + /* get a pointer to the parameter-set parameters */ + + if ((params = ntru_encrypt_get_params_with_DER_id(encoded_data[29])) == + NULL) { + der_id_valid = FALSE; + + /* normalize the prefix-buffer data used in an NTRU OID comparison */ + + prefix_buf[2] = der_prefix_template[2]; + prefix_buf[3] = der_prefix_template[3]; + + } else { + der_id_valid = TRUE; + + /* normalize the prefix-buffer data for the specific parameter set */ + + packed_pubkey_len = (params->N * params->q_bits + 7) >> 3; + sub_16_from_8s(packed_pubkey_len, prefix_buf + 2); + sub_16_from_8s(packed_pubkey_len, prefix_buf + 32); + sub_16_from_8s(packed_pubkey_len, prefix_buf + 37); + prefix_buf[29] = 0; + } + + /* validate the DER prefix encoding */ + + if (!der_id_valid || memcmp(prefix_buf, der_prefix_template, + sizeof(der_prefix_template))) { + + /* bad DER prefix, so determine if this is a bad NTRU encoding or an + * unknown OID by comparing the first 18 octets + */ + + if (memcmp(prefix_buf, der_prefix_template, 18)) + NTRU_RET(NTRU_OID_NOT_RECOGNIZED); + else + NTRU_RET(NTRU_BAD_ENCODING); + } + + /* get public key packing type and blob length */ + + ntru_crypto_ntru_encrypt_key_get_blob_params(params, &pubkey_pack_type, + &public_key_blob_len, NULL, + NULL); + + /* return the pubkey_blob size if requested */ + + if (!pubkey_blob) { + *pubkey_blob_len = public_key_blob_len; + NTRU_RET(NTRU_OK); + } + + /* check size of output buffer */ + + if (*pubkey_blob_len < public_key_blob_len) + NTRU_RET(NTRU_BUFFER_TOO_SMALL); + + /* create the public-key blob */ + + ntru_crypto_ntru_encrypt_key_recreate_pubkey_blob(params, packed_pubkey_len, + encoded_data + sizeof(der_prefix_template), + pubkey_pack_type, pubkey_blob); + *pubkey_blob_len = public_key_blob_len; + + *next = *next + sizeof(der_prefix_template) + packed_pubkey_len; + + NTRU_RET(NTRU_OK); +} + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_key.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_key.c new file mode 100644 index 000000000..b44ca81d7 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_key.c @@ -0,0 +1,397 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_encrypt_key.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_ntru_encrypt_key.c + * + * Contents: Routines for exporting and importing public and private keys + * for NTRUEncrypt. + * + *****************************************************************************/ + + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "ntru_crypto_ntru_encrypt_key.h" + + +/* ntru_crypto_ntru_encrypt_key_parse + * + * Parses an NTRUEncrypt key blob. + * If the blob is not corrupt, returns packing types for public and private + * keys, a pointer to the parameter set, a pointer to the public key, and + * a pointer to the private key if it exists. + * + * Returns TRUE if successful. + * Returns FALSE if the blob is invalid. + */ + +bool +ntru_crypto_ntru_encrypt_key_parse( + bool pubkey_parse, /* in - if parsing pubkey + blob */ + uint16_t key_blob_len, /* in - no. octets in key + blob */ + uint8_t const *key_blob, /* in - pointer to key blob */ + uint8_t *pubkey_pack_type, /* out - addr for pubkey + packing type */ + uint8_t *privkey_pack_type, /* out - addr for privkey + packing type */ + NTRU_ENCRYPT_PARAM_SET **params, /* out - addr for ptr to + parameter set */ + uint8_t const **pubkey, /* out - addr for ptr to + packed pubkey */ + uint8_t const **privkey) /* out - addr for ptr to + packed privkey */ +{ + uint8_t tag; + + assert(key_blob_len); + assert(key_blob); + assert(pubkey_pack_type); + assert(params); + assert(pubkey); + + /* parse key blob based on tag */ + + tag = key_blob[0]; + switch (tag) { + case NTRU_ENCRYPT_PUBKEY_TAG: + if (!pubkey_parse) + return FALSE; + break; + case NTRU_ENCRYPT_PRIVKEY_DEFAULT_TAG: + case NTRU_ENCRYPT_PRIVKEY_TRITS_TAG: + case NTRU_ENCRYPT_PRIVKEY_INDICES_TAG: + assert(privkey_pack_type); + assert(privkey); + if (pubkey_parse) + return FALSE; + break; + default: + return FALSE; + } + + switch (tag) { + case NTRU_ENCRYPT_PUBKEY_TAG: + case NTRU_ENCRYPT_PRIVKEY_DEFAULT_TAG: + case NTRU_ENCRYPT_PRIVKEY_TRITS_TAG: + case NTRU_ENCRYPT_PRIVKEY_INDICES_TAG: + + /* Version 0: + * byte 0: tag + * byte 1: no. of octets in OID + * bytes 2-4: OID + * bytes 5- : packed pubkey + * [packed privkey] + */ + + { + NTRU_ENCRYPT_PARAM_SET *p = NULL; + uint16_t pubkey_packed_len; + + /* check OID length and minimum blob length for tag and OID */ + + if ((key_blob_len < 5) || (key_blob[1] != 3)) + return FALSE; + + /* get a pointer to the parameter set corresponding to the OID */ + + if ((p = ntru_encrypt_get_params_with_OID(key_blob + 2)) == NULL) + return FALSE; + + /* check blob length and assign pointers to blob fields */ + + pubkey_packed_len = (p->N * p->q_bits + 7) / 8; + if (pubkey_parse) { /* public-key parsing */ + if (key_blob_len != 5 + pubkey_packed_len) + return FALSE; + + *pubkey = key_blob + 5; + + } else { /* private-key parsing */ + uint16_t privkey_packed_len; + uint16_t privkey_packed_trits_len = (p->N + 4) / 5; + uint16_t privkey_packed_indices_len; + uint16_t dF; + + /* check packing type for product-form private keys */ + + if (p->is_product_form && + (tag == NTRU_ENCRYPT_PRIVKEY_TRITS_TAG)) + return FALSE; + + /* set packed-key length for packed indices */ + + if (p->is_product_form) + dF = (uint16_t)( (p->dF_r & 0xff) + /* df1 */ + ((p->dF_r >> 8) & 0xff) + /* df2 */ + ((p->dF_r >> 16) & 0xff)); /* df3 */ + else + dF = (uint16_t)p->dF_r; + privkey_packed_indices_len = ((dF << 1) * p->N_bits + 7) >> 3; + + /* set private-key packing type if defaulted */ + + if (tag == NTRU_ENCRYPT_PRIVKEY_DEFAULT_TAG) { + if (p->is_product_form || + (privkey_packed_indices_len <= + privkey_packed_trits_len)) + tag = NTRU_ENCRYPT_PRIVKEY_INDICES_TAG; + else + tag = NTRU_ENCRYPT_PRIVKEY_TRITS_TAG; + } + + if (tag == NTRU_ENCRYPT_PRIVKEY_TRITS_TAG) + privkey_packed_len = privkey_packed_trits_len; + else + privkey_packed_len = privkey_packed_indices_len; + + if (key_blob_len != 5 + pubkey_packed_len + privkey_packed_len) + return FALSE; + + *pubkey = key_blob + 5; + *privkey = *pubkey + pubkey_packed_len; + *privkey_pack_type = (tag == NTRU_ENCRYPT_PRIVKEY_TRITS_TAG) ? + NTRU_ENCRYPT_KEY_PACKED_TRITS : + NTRU_ENCRYPT_KEY_PACKED_INDICES; + } + + /* return parameter set pointer */ + + *pubkey_pack_type = NTRU_ENCRYPT_KEY_PACKED_COEFFICIENTS; + *params = p; + } + default: + break; /* can't get here */ + } + return TRUE; +} + + +/* ntru_crypto_ntru_encrypt_key_get_blob_params + * + * Returns public and private key packing types and blob lengths given + * a packing format. For now, only a default packing format exists. + * + * Only public-key params may be returned by setting privkey_pack_type + * and privkey_blob_len to NULL. + */ + +void +ntru_crypto_ntru_encrypt_key_get_blob_params( + NTRU_ENCRYPT_PARAM_SET const *params, /* in - pointer to + param set + parameters */ + uint8_t *pubkey_pack_type, /* out - addr for pubkey + packing type */ + uint16_t *pubkey_blob_len, /* out - addr for no. of + bytes in + pubkey blob */ + uint8_t *privkey_pack_type, /* out - addr for privkey + packing type */ + uint16_t *privkey_blob_len) /* out - addr for no. of + bytes in + privkey blob */ +{ + uint16_t pubkey_packed_len = (params->N * params->q_bits + 7) >> 3; + + assert(params); + assert(pubkey_pack_type); + assert(pubkey_blob_len); + + *pubkey_pack_type = NTRU_ENCRYPT_KEY_PACKED_COEFFICIENTS; + *pubkey_blob_len = 5 + pubkey_packed_len; + + if (privkey_pack_type && privkey_blob_len) { + uint16_t privkey_packed_trits_len = (params->N + 4) / 5; + uint16_t privkey_packed_indices_len; + uint16_t dF; + + if (params->is_product_form) + dF = (uint16_t)( (params->dF_r & 0xff) + /* df1 */ + ((params->dF_r >> 8) & 0xff) + /* df2 */ + ((params->dF_r >> 16) & 0xff)); /* df3 */ + else + dF = (uint16_t)params->dF_r; + privkey_packed_indices_len = ((dF << 1) * params->N_bits + 7) >> 3; + + if (params->is_product_form || + (privkey_packed_indices_len <= privkey_packed_trits_len)) { + *privkey_pack_type = NTRU_ENCRYPT_KEY_PACKED_INDICES; + *privkey_blob_len = + 5 + pubkey_packed_len + privkey_packed_indices_len; + } else { + *privkey_pack_type = NTRU_ENCRYPT_KEY_PACKED_TRITS; + *privkey_blob_len = + 5 + pubkey_packed_len + privkey_packed_trits_len; + } + } +} + + +/* ntru_crypto_ntru_encrypt_key_create_pubkey_blob + * + * Returns a public key blob, packed according to the packing type provided. + */ + +void +ntru_crypto_ntru_encrypt_key_create_pubkey_blob( + NTRU_ENCRYPT_PARAM_SET const *params, /* in - pointer to + param set + parameters */ + uint16_t const *pubkey, /* in - pointer to the + coefficients + of the pubkey */ + uint8_t pubkey_pack_type, /* out - pubkey packing + type */ + uint8_t *pubkey_blob) /* out - addr for the + pubkey blob */ +{ + assert(params); + assert(pubkey); + assert(pubkey_blob); + + switch (pubkey_pack_type) { + case NTRU_ENCRYPT_KEY_PACKED_COEFFICIENTS: + *pubkey_blob++ = NTRU_ENCRYPT_PUBKEY_TAG; + *pubkey_blob++ = (uint8_t)sizeof(params->OID); + memcpy(pubkey_blob, params->OID, sizeof(params->OID)); + pubkey_blob += sizeof(params->OID); + ntru_elements_2_octets(params->N, pubkey, params->q_bits, + pubkey_blob); + break; + default: + assert(FALSE); + } +} + + +/* ntru_crypto_ntru_encrypt_key_recreate_pubkey_blob + * + * Returns a public key blob, recreated from an already-packed public key. + */ + +void +ntru_crypto_ntru_encrypt_key_recreate_pubkey_blob( + NTRU_ENCRYPT_PARAM_SET const *params, /* in - pointer to + param set + parameters */ + uint16_t packed_pubkey_len, /* in - no. octets in + packed pubkey */ + uint8_t const *packed_pubkey, /* in - pointer to the + packed pubkey */ + uint8_t pubkey_pack_type, /* out - pubkey packing + type */ + uint8_t *pubkey_blob) /* out - addr for the + pubkey blob */ +{ + assert(params); + assert(packed_pubkey); + assert(pubkey_blob); + + switch (pubkey_pack_type) { + case NTRU_ENCRYPT_KEY_PACKED_COEFFICIENTS: + *pubkey_blob++ = NTRU_ENCRYPT_PUBKEY_TAG; + *pubkey_blob++ = (uint8_t)sizeof(params->OID); + memcpy(pubkey_blob, params->OID, sizeof(params->OID)); + pubkey_blob += sizeof(params->OID); + memcpy(pubkey_blob, packed_pubkey, packed_pubkey_len); + break; + default: + assert(FALSE); + } +} + + +/* ntru_crypto_ntru_encrypt_key_create_privkey_blob + * + * Returns a private key blob, packed according to the packing type provided. + */ + +void +ntru_crypto_ntru_encrypt_key_create_privkey_blob( + NTRU_ENCRYPT_PARAM_SET const *params, /* in - pointer to + param set + parameters */ + uint16_t const *pubkey, /* in - pointer to the + coefficients + of the pubkey */ + uint16_t const *privkey, /* in - pointer to the + indices of the + privkey */ + uint8_t privkey_pack_type, /* in - privkey packing + type */ + uint8_t *buf, /* in - temp, N bytes */ + uint8_t *privkey_blob) /* out - addr for the + privkey blob */ +{ + assert(params); + assert(pubkey); + assert(privkey); + assert(privkey_blob); + + switch (privkey_pack_type) { + case NTRU_ENCRYPT_KEY_PACKED_TRITS: + case NTRU_ENCRYPT_KEY_PACKED_INDICES: + + /* format header and packed public key */ + + *privkey_blob++ = NTRU_ENCRYPT_PRIVKEY_DEFAULT_TAG; + *privkey_blob++ = (uint8_t)sizeof(params->OID); + memcpy(privkey_blob, params->OID, sizeof(params->OID)); + privkey_blob += sizeof(params->OID); + ntru_elements_2_octets(params->N, pubkey, params->q_bits, + privkey_blob); + privkey_blob += (params->N * params->q_bits + 7) >> 3; + + /* add packed private key */ + + if (privkey_pack_type == NTRU_ENCRYPT_KEY_PACKED_TRITS) { + ntru_indices_2_packed_trits(privkey, (uint16_t)params->dF_r, + (uint16_t)params->dF_r, + params->N, buf, privkey_blob); + } else { + uint32_t dF; + + if (params->is_product_form) { + dF = (params->dF_r & 0xff) + + ((params->dF_r >> 8) & 0xff) + + ((params->dF_r >> 16) & 0xff); + } else { + dF = params->dF_r; + } + ntru_elements_2_octets((uint16_t)dF << 1, privkey, + params->N_bits, privkey_blob); + } + break; + default: + assert(FALSE); + break; + } +} + + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_key.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_key.h new file mode 100644 index 000000000..6734f2a4c --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_key.h @@ -0,0 +1,167 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_cencrypt_key.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + + +#ifndef NTRU_CRYPTO_NTRU_ENCRYPT_KEY_H +#define NTRU_CRYPTO_NTRU_ENCRYPT_KEY_H + +#include "ntru_crypto_ntru_convert.h" +#include "ntru_crypto_ntru_encrypt_param_sets.h" + + +/* key-blob definitions */ + +#define NTRU_ENCRYPT_PUBKEY_TAG 0x01 +#define NTRU_ENCRYPT_PRIVKEY_DEFAULT_TAG 0x02 +#define NTRU_ENCRYPT_PRIVKEY_TRITS_TAG 0xfe +#define NTRU_ENCRYPT_PRIVKEY_INDICES_TAG 0xff + +/* packing types */ + +#define NTRU_ENCRYPT_KEY_PACKED_COEFFICIENTS 0x01 +#define NTRU_ENCRYPT_KEY_PACKED_INDICES 0x02 +#define NTRU_ENCRYPT_KEY_PACKED_TRITS 0x03 + +/* function declarations */ + + +/* ntru_crypto_ntru_encrypt_key_parse + * + * Parses an NTRUEncrypt key blob. + * If the blob is not corrupt, returns packing types for public and private + * keys, a pointer to the parameter set, a pointer to the public key, and + * a pointer to the private key if it exists. + * + * Returns TRUE if successful. + * Returns FALSE if the blob is invalid. + */ + +extern bool +ntru_crypto_ntru_encrypt_key_parse( + bool pubkey_parse, /* in - if parsing pubkey + blob */ + uint16_t key_blob_len, /* in - no. octets in key + blob */ + uint8_t const *key_blob, /* in - pointer to key blob */ + uint8_t *pubkey_pack_type, /* out - addr for pubkey + packing type */ + uint8_t *privkey_pack_type, /* out - addr for privkey + packing type */ + NTRU_ENCRYPT_PARAM_SET **params, /* out - addr for ptr to + parameter set */ + uint8_t const **pubkey, /* out - addr for ptr to + packed pubkey */ + uint8_t const **privkey); /* out - addr for ptr to + packed privkey */ + + +/* ntru_crypto_ntru_encrypt_key_get_blob_params + * + * Returns public and private key packing types and blob lengths given + * a packing format. For now, only a default packing format exists. + * + * Only public-key params may be returned by setting privkey_pack_type + * and privkey_blob_len to NULL. + */ + +extern void +ntru_crypto_ntru_encrypt_key_get_blob_params( + NTRU_ENCRYPT_PARAM_SET const *params, /* in - pointer to + param set + parameters */ + uint8_t *pubkey_pack_type, /* out - addr for pubkey + packing type */ + uint16_t *pubkey_blob_len, /* out - addr for no. of + bytes in + pubkey blob */ + uint8_t *privkey_pack_type, /* out - addr for privkey + packing type */ + uint16_t *privkey_blob_len); /* out - addr for no. of + bytes in + privkey blob */ + + +/* ntru_crypto_ntru_encrypt_key_create_pubkey_blob + * + * Returns a public key blob, packed according to the packing type provided. + */ + +extern void +ntru_crypto_ntru_encrypt_key_create_pubkey_blob( + NTRU_ENCRYPT_PARAM_SET const *params, /* in - pointer to + param set + parameters */ + uint16_t const *pubkey, /* in - pointer to the + coefficients + of the pubkey */ + uint8_t pubkey_pack_type, /* out - addr for pubkey + packing type */ + uint8_t *pubkey_blob); /* out - addr for the + pubkey blob */ + + +/* ntru_crypto_ntru_encrypt_key_recreate_pubkey_blob + * + * Returns a public key blob, recreated from an already-packed public key. + */ + +extern void +ntru_crypto_ntru_encrypt_key_recreate_pubkey_blob( + NTRU_ENCRYPT_PARAM_SET const *params, /* in - pointer to + param set + parameters */ + uint16_t packed_pubkey_len, /* in - no. octets in + packed pubkey */ + uint8_t const *packed_pubkey, /* in - pointer to the + packed pubkey */ + uint8_t pubkey_pack_type, /* out - pubkey packing + type */ + uint8_t *pubkey_blob); /* out - addr for the + pubkey blob */ + + +/* ntru_crypto_ntru_encrypt_key_create_privkey_blob + * + * Returns a privlic key blob, packed according to the packing type provided. + */ + +extern void +ntru_crypto_ntru_encrypt_key_create_privkey_blob( + NTRU_ENCRYPT_PARAM_SET const *params, /* in - pointer to + param set + parameters */ + uint16_t const *pubkey, /* in - pointer to the + coefficients + of the pubkey */ + uint16_t const *privkey, /* in - pointer to the + indices of the + privkey */ + uint8_t privkey_pack_type, /* in - privkey packing + type */ + uint8_t *buf, /* in - temp, N bytes */ + uint8_t *privkey_blob); /* out - addr for the + privkey blob */ + + +#endif /* NTRU_CRYPTO_NTRU_ENCRYPT_KEY_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_param_sets.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_param_sets.c new file mode 100644 index 000000000..d99b7d6c4 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_param_sets.c @@ -0,0 +1,457 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_param_sets.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_ntru_encrypt_param_sets.c + * + * Contents: Defines the NTRUEncrypt parameter sets. + * + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include "ntru_crypto_ntru_encrypt_param_sets.h" + + +/* parameter sets */ + +static NTRU_ENCRYPT_PARAM_SET ntruParamSets[] = { + + { + NTRU_EES401EP1, /* parameter-set id */ + {0x00, 0x02, 0x04}, /* OID */ + 0x22, /* DER id */ + 9, /* no. of bits in N (i.e., in an index) */ + 401, /* N */ + 14, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 113, /* df, dr */ + 133, /* dg */ + 60, /* maxMsgLenBytes */ + 113, /* dm0 */ + 2005, /* 2^c - (2^c mod N) */ + 11, /* c */ + 1, /* lLen */ + 32, /* min. no. of hash calls for IGF-2 */ + 9, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES449EP1, /* parameter-set id */ + {0x00, 0x03, 0x03}, /* OID */ + 0x23, /* DER id */ + 9, /* no. of bits in N (i.e., in an index) */ + 449, /* N */ + 16, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 134, /* df, dr */ + 149, /* dg */ + 67, /* maxMsgLenBytes */ + 134, /* dm0 */ + 449, /* 2^c - (2^c mod N) */ + 9, /* c */ + 1, /* lLen */ + 31, /* min. no. of hash calls for IGF-2 */ + 9, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES677EP1, /* parameter-set id */ + {0x00, 0x05, 0x03}, /* OID */ + 0x24, /* DER id */ + 10, /* no. of bits in N (i.e., in an index) */ + 677, /* N */ + 24, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 157, /* df, dr */ + 225, /* dg */ + 101, /* maxMsgLenBytes */ + 157, /* dm0 */ + 2031, /* 2^c - (2^c mod N) */ + 11, /* c */ + 1, /* lLen */ + 27, /* min. no. of hash calls for IGF-2 */ + 9, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES1087EP2, /* parameter-set id */ + {0x00, 0x06, 0x03}, /* OID */ + 0x25, /* DER id */ + 10, /* no. of bits in N (i.e., in an index) */ + 1087, /* N */ + 32, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 120, /* df, dr */ + 362, /* dg */ + 170, /* maxMsgLenBytes */ + 120, /* dm0 */ + 7609, /* 2^c - (2^c mod N) */ + 13, /* c */ + 1, /* lLen */ + 25, /* min. no. of hash calls for IGF-2 */ + 14, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES541EP1, /* parameter-set id */ + {0x00, 0x02, 0x05}, /* OID */ + 0x26, /* DER id */ + 10, /* no. of bits in N (i.e., in an index) */ + 541, /* N */ + 14, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 49, /* df, dr */ + 180, /* dg */ + 86, /* maxMsgLenBytes */ + 49, /* dm0 */ + 3787, /* 2^c - (2^c mod N) */ + 12, /* c */ + 1, /* lLen */ + 15, /* min. no. of hash calls for IGF-2 */ + 11, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES613EP1, /* parameter-set id */ + {0x00, 0x03, 0x04}, /* OID */ + 0x27, /* DER id */ + 10, /* no. of bits in N (i.e., in an index) */ + 613, /* N */ + 16, /* securuity strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 55, /* df, dr */ + 204, /* dg */ + 97, /* maxMsgLenBytes */ + 55, /* dm0 */ + 1839, /* 2^c - (2^c mod N) */ + 11, /* c */ + 1, /* lLen */ + 16, /* min. no. of hash calls for IGF-2 */ + 13, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES887EP1, /* parameter-set id */ + {0x00, 0x05, 0x04}, /* OID */ + 0x28, /* DER id */ + 10, /* no. of bits in N (i.e., in an index) */ + 887, /* N */ + 24, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 81, /* df, dr */ + 295, /* dg */ + 141, /* maxMsgLenBytes */ + 81, /* dm0 */ + 887, /* 2^c - (2^c mod N) */ + 10, /* c */ + 1, /* lLen */ + 13, /* min. no. of hash calls for IGF-2 */ + 12, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES1171EP1, /* parameter-set id */ + {0x00, 0x06, 0x04}, /* OID */ + 0x29, /* DER id */ + 11, /* no. of bits in N (i.e., in an index) */ + 1171, /* N */ + 32, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 106, /* df, dr */ + 390, /* dg */ + 186, /* maxMsgLenBytes */ + 106, /* dm0 */ + 3513, /* 2^c - (2^c mod N) */ + 12, /* c */ + 1, /* lLen */ + 20, /* min. no. of hash calls for IGF-2 */ + 15, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES659EP1, /* parameter-set id */ + {0x00, 0x02, 0x06}, /* OID */ + 0x2a, /* DER id */ + 10, /* no. of bits in N (i.e., in an index) */ + 659, /* N */ + 14, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 38, /* df, dr */ + 219, /* dg */ + 108, /* maxMsgLenBytes */ + 38, /* dm0 */ + 1977, /* 2^c - (2^c mod N) */ + 11, /* c */ + 1, /* lLen */ + 11, /* min. no. of hash calls for IGF-2 */ + 14, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES761EP1, /* parameter-set id */ + {0x00, 0x03, 0x05}, /* OID */ + 0x2b, /* DER id */ + 10, /* no. of bits in N (i.e., in an index) */ + 761, /* N */ + 16, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 42, /* df, dr */ + 253, /* dg */ + 125, /* maxMsgLenBytes */ + 42, /* dm0 */ + 3805, /* 2^c - (2^c mod N) */ + 12, /* c */ + 1, /* lLen */ + 13, /* min. no. of hash calls for IGF-2 */ + 16, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES1087EP1, /* parameter-set id */ + {0x00, 0x05, 0x05}, /* OID */ + 0x2c, /* DER id */ + 11, /* no. of bits in N (i.e., in an index) */ + 1087, /* N */ + 24, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 63, /* df, dr */ + 362, /* dg */ + 178, /* maxMsgLenBytes */ + 63, /* dm0 */ + 7609, /* 2^c - (2^c mod N) */ + 13, /* c */ + 1, /* lLen */ + 13, /* min. no. of hash calls for IGF-2 */ + 14, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES1499EP1, /* parameter-set id */ + {0x00, 0x06, 0x05}, /* OID */ + 0x2d, /* DER id */ + 11, /* no. of bits in N (i.e., in an index) */ + 1499, /* N */ + 32, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + FALSE, /* product form */ + 79, /* df, dr */ + 499, /* dg */ + 247, /* maxMsgLenBytes */ + 79, /* dm0 */ + 7495, /* 2^c - (2^c mod N) */ + 13, /* c */ + 1, /* lLen */ + 17, /* min. no. of hash calls for IGF-2 */ + 19, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES401EP2, /* parameter-set id */ + {0x00, 0x02, 0x10}, /* OID */ + 0x2e, /* DER id */ + 9, /* no. of bits in N (i.e., in an index) */ + 401, /* N */ + 14, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + TRUE, /* product form */ + 8 + (8 << 8) + (6 << 16), /* df, dr */ + 133, /* dg */ + 60, /* maxMsgLenBytes */ + 136, /* m(1)_max */ + 2005, /* 2^c - (2^c mod N) */ + 11, /* c */ + 1, /* lLen */ + 10, /* min. no. of hash calls for IGF-2 */ + 6, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES439EP1, /* parameter-set id */ + {0x00, 0x03, 0x10}, /* OID */ + 0x2f, /* DER id */ + 9, /* no. of bits in N (i.e., in an index) */ + 439, /* N */ + 16, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + TRUE, /* product form */ + 9 + (8 << 8) + (5 << 16), /* df, dr */ + 146, /* dg */ + 65, /* maxMsgLenBytes */ + 126, /* m(1)_max */ + 439, /* 2^c - (2^c mod N) */ + 9, /* c */ + 1, /* lLen */ + 15, /* min. no. of hash calls for IGF-2 */ + 6, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES593EP1, /* parameter-set id */ + {0x00, 0x05, 0x10}, /* OID */ + 0x30, /* DER id */ + 10, /* no. of bits in N (i.e., in an index) */ + 593, /* N */ + 24, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + TRUE, /* product form */ + 10 + (10 << 8) + (8 << 16), /* df, dr */ + 197, /* dg */ + 86, /* maxMsgLenBytes */ + 90, /* m(1)_max */ + 1779, /* 2^c - (2^c mod N) */ + 11, /* c */ + 1, /* lLen */ + 12, /* min. no. of hash calls for IGF-2 */ + 5, /* min. no. of hash calls for MGF-TP-1 */ + }, + + { + NTRU_EES743EP1, /* parameter-set id */ + {0x00, 0x06, 0x10}, /* OID */ + 0x31, /* DER id */ + 10, /* no. of bits in N (i.e., in an index) */ + 743, /* N */ + 32, /* security strength in octets */ + 2048, /* q */ + 11, /* no. of bits in q (i.e., in a coeff) */ + TRUE, /* product form */ + 11 + (11 << 8) + (15 << 16), /* df, dr */ + 247, /* dg */ + 106, /* maxMsgLenBytes */ + 60, /* m(1)_max */ + 8173, /* 2^c - (2^c mod N) */ + 13, /* c */ + 1, /* lLen */ + 12, /* min. no. of hash calls for IGF-2 */ + 7, /* min. no. of hash calls for MGF-TP-1 */ + }, + +}; + +static size_t numParamSets = + sizeof(ntruParamSets)/sizeof(NTRU_ENCRYPT_PARAM_SET); + + +/* functions */ + +/* ntru_encrypt_get_params_with_id + * + * Looks up a set of NTRUEncrypt parameters based on the id of the + * parameter set. + * + * Returns a pointer to the parameter set parameters if successful. + * Returns NULL if the parameter set cannot be found. + */ + +NTRU_ENCRYPT_PARAM_SET * +ntru_encrypt_get_params_with_id( + NTRU_ENCRYPT_PARAM_SET_ID id) /* in - parameter-set id */ +{ + size_t i; + + for (i = 0; i < numParamSets; i++) { + if (ntruParamSets[i].id == id) { + return &(ntruParamSets[i]); + } + } + return NULL; +} + + +/* ntru_encrypt_get_params_with_OID + * + * Looks up a set of NTRUEncrypt parameters based on the OID of the + * parameter set. + * + * Returns a pointer to the parameter set parameters if successful. + * Returns NULL if the parameter set cannot be found. + */ + +NTRU_ENCRYPT_PARAM_SET * +ntru_encrypt_get_params_with_OID( + uint8_t const *oid) /* in - pointer to parameter-set OID */ +{ + size_t i; + + for (i = 0; i < numParamSets; i++) { + if (!memcmp(ntruParamSets[i].OID, oid, 3)) { + return &(ntruParamSets[i]); + } + } + return NULL; +} + + +/* ntru_encrypt_get_params_with_DER_id + * + * Looks up a set of NTRUEncrypt parameters based on the DER id of the + * parameter set. + * + * Returns a pointer to the parameter set parameters if successful. + * Returns NULL if the parameter set cannot be found. + */ + +NTRU_ENCRYPT_PARAM_SET * +ntru_encrypt_get_params_with_DER_id( + uint8_t der_id) /* in - parameter-set DER id */ +{ + size_t i; + + for (i = 0; i < numParamSets; i++) { + if (ntruParamSets[i].der_id == der_id) { + return &(ntruParamSets[i]); + } + } + return NULL; +} + + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_param_sets.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_param_sets.h new file mode 100644 index 000000000..ad2b89b95 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_encrypt_param_sets.h @@ -0,0 +1,124 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_encrypt_param_sets.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_ntru_encrypt_param_sets.h + * + * Contents: Definitions and declarations for the NTRUEncrypt parameter sets. + * + *****************************************************************************/ + +#ifndef NTRU_CRYPTO_NTRU_ENCRYPT_PARAM_SETS_H +#define NTRU_CRYPTO_NTRU_ENCRYPT_PARAM_SETS_H + +#include "ntru_crypto.h" +#include "ntru_crypto_hash_basics.h" + + +/* structures */ + +typedef struct _NTRU_ENCRYPT_PARAM_SET { + NTRU_ENCRYPT_PARAM_SET_ID id; /* parameter-set ID */ + uint8_t const OID[3]; /* pointer to OID */ + uint8_t der_id; /* parameter-set DER id */ + uint8_t N_bits; /* no. of bits in N (i.e. in + an index */ + uint16_t N; /* ring dimension */ + uint16_t sec_strength_len; /* no. of octets of + security strength */ + uint16_t q; /* big modulus */ + uint8_t q_bits; /* no. of bits in q (i.e. in + a coefficient */ + bool is_product_form; /* if product form used */ + uint32_t dF_r; /* no. of 1 or -1 coefficients + in ring elements F, r */ + uint16_t dg; /* no. - 1 of 1 coefficients + or no. of -1 coefficients + in ring element g */ + uint16_t m_len_max; /* max no. of plaintext + octets */ + uint16_t min_msg_rep_wt; /* min. message + representative weight */ + uint16_t no_bias_limit; /* limit for no bias in + IGF-2 */ + uint8_t c_bits; /* no. bits in candidate for + deriving an index in + IGF-2 */ + uint8_t m_len_len; /* no. of octets to hold + mLenOctets */ + uint8_t min_IGF_hash_calls; /* min. no. of hash calls for + IGF-2 */ + uint8_t min_MGF_hash_calls; /* min. no. of hash calls for + MGF-TP-1 */ +} NTRU_ENCRYPT_PARAM_SET; + + + +/* function declarations */ + +/* ntru_encrypt_get_params_with_id + * + * Looks up a set of NTRU Encrypt parameters based on the id of the + * parameter set. + * + * Returns a pointer to the parameter set parameters if successful. + * Returns NULL if the parameter set cannot be found. + */ + +extern NTRU_ENCRYPT_PARAM_SET * +ntru_encrypt_get_params_with_id( + NTRU_ENCRYPT_PARAM_SET_ID id); /* in - parameter-set id */ + + +/* ntru_encrypt_get_params_with_OID + * + * Looks up a set of NTRU Encrypt parameters based on the OID of the + * parameter set. + * + * Returns a pointer to the parameter set parameters if successful. + * Returns NULL if the parameter set cannot be found. + */ + +extern NTRU_ENCRYPT_PARAM_SET * +ntru_encrypt_get_params_with_OID( + uint8_t const *oid); /* in - pointer to parameter-set OID */ + + +/* ntru_encrypt_get_params_with_DER_id + * + * Looks up a set of NTRUEncrypt parameters based on the DER id of the + * parameter set. + * + * Returns a pointer to the parameter set parameters if successful. + * Returns NULL if the parameter set cannot be found. + */ + +extern NTRU_ENCRYPT_PARAM_SET * +ntru_encrypt_get_params_with_DER_id( + uint8_t der_id); /* in - parameter-set DER id */ + + +#endif /* NTRU_CRYPTO_NTRU_ENCRYPT_PARAM_SETS_H */ + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_mgf1.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_mgf1.c new file mode 100644 index 000000000..194af4fc9 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_mgf1.c @@ -0,0 +1,197 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_mgf1.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_ntru_mgf1.c + * + * Contents: Routines implementing MGF-TP-1 and MGF-1. + * + *****************************************************************************/ + + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "ntru_crypto_ntru_mgf1.h" +#include "ntru_crypto_ntru_convert.h" + + +/* ntru_mgf1 + * + * Implements a basic mask-generation function, generating an arbitrary + * number of octets based on hashing a digest-length string concatenated + * with a 4-octet counter. + * + * The state (string and counter) is initialized when a seed is present. + * + * Returns NTRU_OK if successful. + * Returns NTRU_CRYPTO_HASH_ errors if they occur. + * + */ + +uint32_t +ntru_mgf1( + uint8_t *state, /* in/out - pointer to the state */ + NTRU_CRYPTO_HASH_ALGID algid, /* in - hash algorithm ID */ + uint8_t md_len, /* in - no. of octets in digest */ + uint8_t num_calls, /* in - no. of hash calls */ + uint16_t seed_len, /* in - no. of octets in seed */ + uint8_t const *seed, /* in - pointer to seed */ + uint8_t *out) /* out - address for output */ +{ + uint8_t *ctr = state + md_len; + uint32_t retcode; + + assert(state); + assert(out); + + /* if seed present, init state */ + + if (seed) { + if ((retcode = ntru_crypto_hash_digest(algid, seed, seed_len, state)) != + NTRU_CRYPTO_HASH_OK) + return retcode; + memset(ctr, 0, 4); + } + + /* generate output */ + + while (num_calls-- > 0) { + if ((retcode = ntru_crypto_hash_digest(algid, state, md_len + 4, + out)) != + NTRU_CRYPTO_HASH_OK) + return retcode; + out += md_len; + + /* increment counter */ + + if (++ctr[3] == 0) + if (++ctr[2] == 0) + if (++ctr[1] == 0) + ++ctr[0]; + } + + NTRU_RET(NTRU_OK); +} + + +/* ntru_mgftp1 + * + * Implements a mask-generation function for trinary polynomials, + * MGF-TP-1, generating an arbitrary number of octets based on hashing + * a digest-length string concatenated with a 4-octet counter. From + * these octets, N trits are derived. + * + * The state (string and counter) is initialized when a seed is present. + * + * Returns NTRU_OK if successful. + * Returns NTRU_CRYPTO_HASH_ errors if they occur. + * + */ + +uint32_t +ntru_mgftp1( + NTRU_CRYPTO_HASH_ALGID hash_algid, /* in - hash alg ID for + MGF-TP-1 */ + uint8_t md_len, /* in - no. of octets in + digest */ + uint8_t min_calls, /* in - minimum no. of hash + calls */ + uint16_t seed_len, /* in - no. of octets in seed */ + uint8_t *seed, /* in - pointer to seed */ + uint8_t *buf, /* in - pointer to working + buffer */ + uint16_t num_trits_needed, /* in - no. of trits in mask */ + uint8_t *mask) /* out - address for mask trits */ +{ + uint8_t *mgf_out; + uint8_t *octets; + uint16_t octets_available; + uint32_t retcode; + + assert(seed); + assert(buf); + assert(mask); + + /* generate minimum MGF1 output */ + + mgf_out = buf + md_len + 4; + if ((retcode = ntru_mgf1(buf, hash_algid, md_len, min_calls, + seed_len, seed, mgf_out)) != NTRU_OK) + return retcode; + octets = mgf_out; + octets_available = min_calls * md_len; + + /* get trits for mask */ + + while (num_trits_needed >= 5) { + + /* get another octet and convert it to 5 trits */ + + if (octets_available == 0) { + if ((retcode = ntru_mgf1(buf, hash_algid, md_len, 1, + 0, NULL, mgf_out)) != NTRU_OK) + return retcode; + octets = mgf_out; + octets_available = md_len; + } + + if (*octets < 243) { + ntru_octet_2_trits(*octets, mask); + mask += 5; + num_trits_needed -= 5; + } + octets++; + --octets_available; + } + + /* get any remaining trits */ + + while (num_trits_needed) { + uint8_t trits[5]; + + /* get another octet and convert it to remaining trits */ + + if (octets_available == 0) { + if ((retcode = ntru_mgf1(buf, hash_algid, md_len, 1, + 0, NULL, mgf_out)) != NTRU_OK) + return retcode; + octets = mgf_out; + octets_available = md_len; + } + if (*octets < 243) { + ntru_octet_2_trits(*octets, trits); + memcpy(mask, trits, num_trits_needed); + num_trits_needed = 0; + } else { + octets++; + --octets_available; + } + } + + NTRU_RET(NTRU_OK); +} + + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_mgf1.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_mgf1.h new file mode 100644 index 000000000..b3615fac8 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_mgf1.h @@ -0,0 +1,98 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_mgf1.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_ntru_mgf1.h + * + * Contents: Public header file for MGF-1 in the NTRU algorithm. + * + *****************************************************************************/ + + +#ifndef NTRU_CRYPTO_NTRU_MGF1_H +#define NTRU_CRYPTO_NTRU_MGF1_H + + +#include "ntru_crypto.h" +#include "ntru_crypto_hash.h" + + +/* function declarations */ + +/* ntru_mgf1 + * + * Implements a basic mask-generation function, generating an arbitrary + * number of octets based on hashing a digest-length string concatenated + * with a 4-octet counter. + * + * The state (string and counter) is initialized when a seed is present. + * + * Returns NTRU_OK if successful. + * Returns NTRU_CRYPTO_HASH_ errors if they occur. + * + */ + +extern uint32_t +ntru_mgf1( + uint8_t *state, /* in/out - pointer to the state */ + NTRU_CRYPTO_HASH_ALGID algid, /* in - hash algorithm ID */ + uint8_t md_len, /* in - no. of octets in digest */ + uint8_t num_calls, /* in - no. of hash calls */ + uint16_t seed_len, /* in - no. of octets in seed */ + uint8_t const *seed, /* in - pointer to seed */ + uint8_t *out); /* out - address for output */ + + +/* ntru_mgftp1 + * + * Implements a mask-generation function for trinary polynomials, + * MGF-TP-1, generating an arbitrary number of octets based on hashing + * a digest-length string concatenated with a 4-octet counter. From + * these octets, N trits are derived. + * + * The state (string and counter) is initialized when a seed is present. + * + * Returns NTRU_OK if successful. + * Returns NTRU_CRYPTO_HASH_ errors if they occur. + * + */ + +extern uint32_t +ntru_mgftp1( + NTRU_CRYPTO_HASH_ALGID hash_algid, /* in - hash alg ID for + MGF-TP-1 */ + uint8_t md_len, /* in - no. of octets in + digest */ + uint8_t min_calls, /* in - minimum no. of hash + calls */ + uint16_t seed_len, /* in - no. of octets in seed */ + uint8_t *seed, /* in - pointer to seed */ + uint8_t *buf, /* in - pointer to working + buffer */ + uint16_t num_trits_needed, /* in - no. of trits in mask */ + uint8_t *mask); /* out - address for mask trits */ + + +#endif /* NTRU_CRYPTO_NTRU_MGF1_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_poly.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_poly.c new file mode 100644 index 000000000..6fc34146d --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_poly.c @@ -0,0 +1,586 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_poly.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_ntru_poly.c + * + * Contents: Routines for generating and operating on polynomials in the + * NTRU algorithm. + * + *****************************************************************************/ + + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "ntru_crypto_ntru_poly.h" +#include "ntru_crypto_ntru_mgf1.h" + + +/* ntru_gen_poly + * + * Generates polynomials by creating for each polynomial, a list of the + * indices of the +1 coefficients followed by a list of the indices of + * the -1 coefficients. + * + * If a single polynomial is generated (non-product form), indices_counts + * contains a single value of the total number of indices (for +1 and -1 + * comefficients combined). + * + * If multiple polynomials are generated (for product form), their lists of + * indices are sequentially stored in the indices buffer. Each byte of + * indices_counts contains the total number of indices (for +1 and -1 + * coefficients combined) for a single polynomial, beginning with the + * low-order byte for the first polynomial. The high-order byte is unused. + * + * Returns NTRU_OK if successful. + * Returns HASH_BAD_ALG if the algorithm is not supported. + * + */ + +uint32_t +ntru_gen_poly( + NTRU_CRYPTO_HASH_ALGID hash_algid, /* in - hash algorithm ID for + IGF-2 */ + uint8_t md_len, /* in - no. of octets in digest */ + uint8_t min_calls, /* in - minimum no. of hash + calls */ + uint16_t seed_len, /* in - no. of octets in seed */ + uint8_t *seed, /* in - pointer to seed */ + uint8_t *buf, /* in - pointer to working + buffer */ + uint16_t N, /* in - max index + 1 */ + uint8_t c_bits, /* in - no. bits for candidate */ + uint16_t limit, /* in - conversion to index + limit */ + bool is_product_form, /* in - if generating multiple + polys */ + uint32_t indices_counts, /* in - nos. of indices needed */ + uint16_t *indices) /* out - address for indices */ +{ + uint8_t *mgf_out; + uint8_t *octets; + uint8_t *used; + uint8_t num_polys; + uint16_t num_indices; + uint16_t octets_available; + uint16_t index_cnt = 0; + uint8_t left = 0; + uint8_t num_left = 0; + uint32_t retcode; + + assert(seed); + assert(buf); + assert(indices); + + /* generate minimum MGF1 output */ + + mgf_out = buf + md_len + 4; + if ((retcode = ntru_mgf1(buf, hash_algid, md_len, min_calls, + seed_len, seed, mgf_out)) != NTRU_OK) + return retcode; + octets = mgf_out; + octets_available = min_calls * md_len; + + /* init indices counts for number of polynomials being generated */ + + if (is_product_form) { + + /* number of indices for poly1 is in low byte of indices_counts, + * number of indices for poly2 and poly3 are in next higher bytes + */ + + num_polys = 3; + num_indices = (uint16_t)(indices_counts & 0xff); + indices_counts >>= 8; + + } else { + + /* number of bytes for poly is in low 16 bits of indices_counts */ + + num_polys = 1; + num_indices = (uint16_t)indices_counts; + } + + /* init used-index array */ + + used = mgf_out + octets_available; + memset(used, 0, N); + + /* generate indices (IGF-2) for all polynomials */ + + while (num_polys > 0) { + + /* generate indices for a single polynomial */ + + while (index_cnt < num_indices) { + uint16_t index; + uint8_t num_needed; + + /* form next index to convert to an index */ + + do { + /* use any leftover bits first */ + + if (num_left != 0) { + index = left << (c_bits - num_left); + } else { + index = 0; + } + + /* get the rest of the bits needed from new octets */ + + num_needed = c_bits - num_left; + while (num_needed != 0) { + + /* get another octet */ + + if (octets_available == 0) { + if ((retcode = ntru_mgf1(buf, hash_algid, md_len, 1, + 0, NULL, mgf_out)) != NTRU_OK) + return retcode; + octets = mgf_out; + octets_available = md_len; + } + left = *octets++; + --octets_available; + + if (num_needed <= 8) { + + /* all bits needed to fill the index are in this octet */ + + index |= ((uint16_t)(left)) >> (8 - num_needed); + num_left = 8 - num_needed; + num_needed = 0; + left &= 0xff >> (8 - num_left); + + } else { + + /* another octet will be needed after using this + * whole octet + */ + + index |= ((uint16_t)left) << (num_needed - 8); + num_needed -= 8; + } + } + } while (index >= limit); + + /* form index and check if unique */ + + index %= N; + if (!used[index]) { + used[index] = 1; + indices[index_cnt] = index; + ++index_cnt; + } + } + --num_polys; + + /* init for next polynomial if another polynomial to be generated */ + + if (num_polys > 0) { + memset(used, 0, N); + num_indices = num_indices + + (uint16_t)(indices_counts & 0xff); + indices_counts >>= 8; + } + } + + NTRU_RET(NTRU_OK); +} + + +/* ntru_poly_check_min_weight + * + * Checks that the number of 0, +1, and -1 trinary ring elements meet or exceed + * a minimum weight. + */ + +bool +ntru_poly_check_min_weight( + uint16_t num_els, /* in - degree of polynomial */ + uint8_t *ringels, /* in - pointer to trinary ring elements */ + uint16_t min_wt) /* in - minimum weight */ +{ + uint16_t wt[3]; + uint16_t i; + + wt[0] = wt[1] = wt[2] = 0; + for (i = 0; i < num_els; i++) { + ++wt[ringels[i]]; + } + if ((wt[0] < min_wt) || (wt[1] < min_wt) || (wt[2] < min_wt)) { + return FALSE; + } + return TRUE; +} + + +/* ntru_ring_mult_indices + * + * Multiplies ring element (polynomial) "a" by ring element (polynomial) "b" + * to produce ring element (polynomial) "c" in (Z/qZ)[X]/(X^N - 1). + * This is a convolution operation. + * + * Ring element "b" is a sparse trinary polynomial with coefficients -1, 0, + * and 1. It is specified by a list, bi, of its nonzero indices containing + * indices for the bi_P1_len +1 coefficients followed by the indices for the + * bi_M1_len -1 coefficients. + * The indices are in the range [0,N). + * + * The result array "c" may share the same memory space as input array "a", + * input array "b", or temp array "t". + * + * This assumes q is 2^r where 8 < r < 16, so that overflow of the sum + * beyond 16 bits does not matter. + */ + +void +ntru_ring_mult_indices( + uint16_t const *a, /* in - pointer to ring element a */ + uint16_t bi_P1_len, /* in - no. of +1 coefficients in b */ + uint16_t bi_M1_len, /* in - no. of -1 coefficients in b */ + uint16_t const *bi, /* in - pointer to the list of nonzero + indices of ring element b, + containing indices for the +1 + coefficients followed by the + indices for -1 coefficients */ + uint16_t N, /* in - no. of coefficients in a, b, c */ + uint16_t q, /* in - large modulus */ + uint16_t *t, /* in - temp buffer of N elements */ + uint16_t *c) /* out - address for polynomial c */ +{ + uint16_t mod_q_mask = q - 1; + uint16_t i, j, k; + + assert(a); + assert(bi); + assert(t); + assert(c); + + /* t[(i+k)%N] = sum i=0 through N-1 of a[i], for b[k] = -1 */ + + for (k = 0; k < N; k++) + t[k] = 0; + for (j = bi_P1_len; j < bi_P1_len + bi_M1_len; j++) { + k = bi[j]; + for (i = 0; k < N; ++i, ++k) + t[k] = t[k] + a[i]; + for (k = 0; i < N; ++i, ++k) + t[k] = t[k] + a[i]; + } + + /* t[(i+k)%N] = -(sum i=0 through N-1 of a[i] for b[k] = -1) */ + + for (k = 0; k < N; k++) + t[k] = -t[k]; + + /* t[(i+k)%N] += sum i=0 through N-1 of a[i] for b[k] = +1 */ + + for (j = 0; j < bi_P1_len; j++) { + k = bi[j]; + for (i = 0; k < N; ++i, ++k) + t[k] = t[k] + a[i]; + for (k = 0; i < N; ++i, ++k) + t[k] = t[k] + a[i]; + } + + /* c = (a * b) mod q */ + + for (k = 0; k < N; k++) + c[k] = t[k] & mod_q_mask; +} + + +/* ntru_ring_mult_product_indices + * + * Multiplies ring element (polynomial) "a" by ring element (polynomial) "b" + * to produce ring element (polynomial) "c" in (Z/qZ)[X]/(X^N - 1). + * This is a convolution operation. + * + * Ring element "b" is represented by the product form b1 * b2 + b3, where + * b1, b2, and b3 are each a sparse trinary polynomial with coefficients -1, + * 0, and 1. It is specified by a list, bi, of the nonzero indices of b1, b2, + * and b3, containing the indices for the +1 coefficients followed by the + * indices for the -1 coefficients for each polynomial in that order. + * The indices are in the range [0,N). + * + * The result array "c" may share the same memory space as input array "a", + * or input array "b". + * + * This assumes q is 2^r where 8 < r < 16, so that overflow of the sum + * beyond 16 bits does not matter. + */ + +void +ntru_ring_mult_product_indices( + uint16_t *a, /* in - pointer to ring element a */ + uint16_t b1i_len, /* in - no. of +1 or -1 coefficients in b1 */ + uint16_t b2i_len, /* in - no. of +1 or -1 coefficients in b2 */ + uint16_t b3i_len, /* in - no. of +1 or -1 coefficients in b3 */ + uint16_t const *bi, /* in - pointer to the list of nonzero + indices of polynomials b1, b2, b3, + containing indices for the +1 + coefficients followed by the + indices for -1 coefficients for + each polynomial */ + uint16_t N, /* in - no. of coefficients in a, b, c */ + uint16_t q, /* in - large modulus */ + uint16_t *t, /* in - temp buffer of 2N elements */ + uint16_t *c) /* out - address for polynomial c */ +{ + uint16_t *t2 = t + N; + uint16_t mod_q_mask = q - 1; + uint16_t i; + + assert(a); + assert(bi); + assert(t); + assert(c); + + /* t2 = a * b1 */ + + ntru_ring_mult_indices(a, b1i_len, b1i_len, bi, N, q, t, t2); + + /* t2 = (a * b1) * b2 */ + + ntru_ring_mult_indices(t2, b2i_len, b2i_len, bi + (b1i_len << 1), N, q, + t, t2); + + /* t = a * b3 */ + + ntru_ring_mult_indices(a, b3i_len, b3i_len, + bi + ((b1i_len + b2i_len) << 1), N, q, t, t); + + /* c = (a * b1 * b2) + (a * b3) */ + + for (i = 0; i < N; i++) + c[i] = (t2[i] + t[i]) & mod_q_mask; +} + + +/* ntru_ring_mult_coefficients + * + * Multiplies ring element (polynomial) "a" by ring element (polynomial) "b" + * to produce ring element (polynomial) "c" in (Z/qZ)[X]/(X^N - 1). + * This is a convolution operation. + * + * Ring element "b" has coefficients in the range [0,N). + * + * This assumes q is 2^r where 8 < r < 16, so that overflow of the sum + * beyond 16 bits does not matter. + */ + +void +ntru_ring_mult_coefficients( + uint16_t const *a, /* in - pointer to polynomial a */ + uint16_t const *b, /* in - pointer to polynomial b */ + uint16_t N, /* in - no. of coefficients in a, b, c */ + uint16_t q, /* in - large modulus */ + uint16_t *c) /* out - address for polynomial c */ +{ + uint16_t const *bptr = b; + uint16_t mod_q_mask = q - 1; + uint16_t i, k; + + assert(a); + assert(b); + assert(c); + + /* c[k] = sum(a[i] * b[k-i]) mod q */ + + memset(c, 0, N * sizeof(uint16_t)); + for (k = 0; k < N; k++) { + i = 0; + while (i <= k) + c[k] += a[i++] * *bptr--; + bptr += N; + while (i < N) + c[k] += a[i++] * *bptr--; + c[k] &= mod_q_mask; + ++bptr; + } +} + + +/* ntru_ring_inv + * + * Finds the inverse of a polynomial, a, in (Z/2^rZ)[X]/(X^N - 1). + * + * This assumes q is 2^r where 8 < r < 16, so that operations mod q can + * wait until the end, and only 16-bit arrays need to be used. + */ + +bool +ntru_ring_inv( + uint16_t *a, /* in - pointer to polynomial a */ + uint16_t N, /* in - no. of coefficients in a */ + uint16_t q, /* in - large modulus */ + uint16_t *t, /* in - temp buffer of 2N elements */ + uint16_t *a_inv) /* out - address for polynomial a^-1 */ +{ + uint8_t *b = (uint8_t *)t; /* b cannot be in a_inv since it must be + rotated and copied there as a^-1 mod 2 */ + uint8_t *c = b + N; /* c cannot be in a_inv since it exchanges + with b, and b cannot be in a_inv */ + uint8_t *f = c + N; + uint8_t *g = (uint8_t *)a_inv; /* g needs N + 1 bytes */ + uint16_t *t2 = t + N; + uint16_t deg_b; + uint16_t deg_c; + uint16_t deg_f; + uint16_t deg_g; + uint16_t k = 0; + bool done = FALSE; + uint16_t i, j; + + assert(a); + assert(t); + assert(a_inv); + + /* form a^-1 in (Z/2Z)[X]/X^N - 1) */ + + memset(b, 0, (N << 1)); /* clear to init b, c */ + + /* b(X) = 1 */ + + b[0] = 1; + deg_b = 0; + + /* c(X) = 0 (cleared above) */ + + deg_c = 0; + + /* f(X) = a(X) mod 2 */ + + for (i = 0; i < N; i++) + f[i] = (uint8_t)(a[i] & 1); + deg_f = N - 1; + + /* g(X) = X^N - 1 */ + + g[0] = 1; + memset(g + 1, 0, N - 1); + g[N] = 1; + deg_g = N; + + /* until f(X) = 1 */ + + while (!done) { + + /* while f[0] = 0, f(X) /= X, c(X) *= X, k++ */ + + for (i = 0; (i <= deg_f) && (f[i] == 0); ++i); + if (i > deg_f) + return FALSE; + if (i) { + f = f + i; + deg_f = deg_f - i; + deg_c = deg_c + i; + for (j = deg_c; j >= i; j--) + c[j] = c[j-i]; + for (j = 0; j < i; j++) + c[j] = 0; + k = k + i; + } + + /* adjust degree of f(X) if the highest coefficients are zero + * Note: f[0] = 1 from above so the loop will terminate. + */ + + while (f[deg_f] == 0) + --deg_f; + + /* if f(X) = 1, done + * Note: f[0] = 1 from above, so only check the x term and up + */ + + for (i = 1; (i <= deg_f) && (f[i] == 0); ++i); + if (i > deg_f) { + done = TRUE; + break; + } + + /* if deg_f < deg_g, f <-> g, b <-> c */ + + if (deg_f < deg_g) { + uint8_t *x; + + x = f; + f = g; + g = x; + deg_f ^= deg_g; + deg_g ^= deg_f; + deg_f ^= deg_g; + x = b; + b = c; + c = x; + deg_b ^= deg_c; + deg_c ^= deg_b; + deg_b ^= deg_c; + } + + /* f(X) += g(X), b(X) += c(X) */ + + for (i = 0; i <= deg_g; i++) + f[i] ^= g[i]; + + if (deg_c > deg_b) + deg_b = deg_c; + for (i = 0; i <= deg_c; i++) + b[i] ^= c[i]; + } + + /* a^-1 in (Z/2Z)[X]/(X^N - 1) = b(X) shifted left k coefficients */ + + j = 0; + if (k >= N) + k = k - N; + for (i = k; i < N; i++) + a_inv[j++] = (uint16_t)(b[i]); + for (i = 0; i < k; i++) + a_inv[j++] = (uint16_t)(b[i]); + + /* lift a^-1 in (Z/2Z)[X]/(X^N - 1) to a^-1 in (Z/qZ)[X]/(X^N -1) */ + + for (j = 0; j < 4; ++j) { /* assumes 256 < q <= 65536 */ + + /* a^-1 = a^-1 * (2 - a * a^-1) mod q */ + + memcpy(t2, a_inv, N * sizeof(uint16_t)); + ntru_ring_mult_coefficients(a, t2, N, q, t); + for (i = 0; i < N; ++i) + t[i] = q - t[i]; + t[0] = t[0] + 2; + ntru_ring_mult_coefficients(t2, t, N, q, a_inv); + } + + return TRUE; + + +} + + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_poly.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_poly.h new file mode 100644 index 000000000..242fb4109 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_ntru_poly.h @@ -0,0 +1,211 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_poly.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_ntru_poly.h + * + * Contents: Public header file for generating and operating on polynomials + * in the NTRU algorithm. + * + *****************************************************************************/ + + +#ifndef NTRU_CRYPTO_NTRU_POLY_H +#define NTRU_CRYPTO_NTRU_POLY_H + + +#include "ntru_crypto.h" +#include "ntru_crypto_hash_basics.h" + + +/* function declarations */ + +/* ntru_gen_poly + * + * Generates polynomials by creating for each polynomial, a list of the + * indices of the +1 coefficients followed by a list of the indices of + * the -1 coefficients. + * + * If a single polynomial is generated (non-product form), indices_counts + * contains a single value of the total number of indices (for +1 and -1 + * comefficients combined). + * + * If multiple polynomials are generated (for product form), their lists of + * indices are sequentially stored in the indices buffer. Each byte of + * indices_counts contains the total number of indices (for +1 and -1 + * coefficients combined) for a single polynomial, beginning with the + * low-order byte for the first polynomial. The high-order byte is unused. + * + * Returns NTRU_OK if successful. + * Returns HASH_BAD_ALG if the algorithm is not supported. + * + */ + +extern uint32_t +ntru_gen_poly( + NTRU_CRYPTO_HASH_ALGID hash_algid, /* in - hash algorithm ID for + IGF-2 */ + uint8_t md_len, /* in - no. of octets in digest */ + uint8_t min_calls, /* in - minimum no. of hash + calls */ + uint16_t seed_len, /* in - no. of octets in seed */ + uint8_t *seed, /* in - pointer to seed */ + uint8_t *buf, /* in - pointer to working + buffer */ + uint16_t N, /* in - max index + 1 */ + uint8_t c_bits, /* in - no. bits for candidate */ + uint16_t limit, /* in - conversion to index + limit */ + bool is_product_form, /* in - if generating multiple + polys */ + uint32_t indices_counts, /* in - nos. of indices needed */ + uint16_t *indices); /* out - address for indices */ + + +/* ntru_poly_check_min_weight + * + * Checks that the number of 0, +1, and -1 trinary ring elements meet or exceed + * a minimum weight. + */ + +extern bool +ntru_poly_check_min_weight( + uint16_t num_els, /* in - degree of polynomial */ + uint8_t *ringels, /* in - pointer to trinary ring elements */ + uint16_t min_wt); /* in - minimum weight */ + + +/* ntru_ring_mult_indices + * + * Multiplies ring element (polynomial) "a" by ring element (polynomial) "b" + * to produce ring element (polynomial) "c" in (Z/qZ)[X]/(X^N - 1). + * This is a convolution operation. + * + * Ring element "b" is a sparse trinary polynomial with coefficients -1, 0, + * and 1. It is specified by a list, bi, of its nonzero indices containing + * indices for the bi_P1_len +1 coefficients followed by the indices for the + * bi_M1_len -1 coefficients. + * The indices are in the range [0,N). + * + * The result array "c" may share the same memory space as input array "a", + * or input array "b". + * + * This assumes q is 2^r where 8 < r < 16, so that overflow of the sum + * beyond 16 bits does not matter. + */ + +extern void +ntru_ring_mult_indices( + uint16_t const *a, /* in - pointer to ring element a */ + uint16_t bi_P1_len, /* in - no. of +1 coefficients in b */ + uint16_t bi_M1_len, /* in - no. of -1 coefficients in b */ + uint16_t const *bi, /* in - pointer to the list of nonzero + indices of ring element b, + containing indices for the +1 + coefficients followed by the + indices for -1 coefficients */ + uint16_t N, /* in - no. of coefficients in a, b, c */ + uint16_t q, /* in - large modulus */ + uint16_t *t, /* in - temp buffer of N elements */ + uint16_t *c); /* out - address for polynomial c */ + + +/* ntru_ring_mult_product_indices + * + * Multiplies ring element (polynomial) "a" by ring element (polynomial) "b" + * to produce ring element (polynomial) "c" in (Z/qZ)[X]/(X^N - 1). + * This is a convolution operation. + * + * Ring element "b" is represented by the product form b1 * b2 + b3, where + * b1, b2, and b3 are each a sparse trinary polynomial with coefficients -1, + * 0, and 1. It is specified by a list, bi, of the nonzero indices of b1, b2, + * and b3, containing the indices for the +1 coefficients followed by the + * indices for the -1 coefficients for each polynomial in that order. + * The indices are in the range [0,N). + * + * The result array "c" may share the same memory space as input array "a", + * or input array "b". + * + * This assumes q is 2^r where 8 < r < 16, so that overflow of the sum + * beyond 16 bits does not matter. + */ + +extern void +ntru_ring_mult_product_indices( + uint16_t *a, /* in - pointer to ring element a */ + uint16_t b1i_len, /* in - no. of +1 or -1 coefficients in b1 */ + uint16_t b2i_len, /* in - no. of +1 or -1 coefficients in b2 */ + uint16_t b3i_len, /* in - no. of +1 or -1 coefficients in b3 */ + uint16_t const *bi, /* in - pointer to the list of nonzero + indices of polynomials b1, b2, b3, + containing indices for the +1 + coefficients followed by the + indices for -1 coefficients for + each polynomial */ + uint16_t N, /* in - no. of coefficients in a, b, c */ + uint16_t q, /* in - large modulus */ + uint16_t *t, /* in - temp buffer of 2N elements */ + uint16_t *c); /* out - address for polynomial c */ + + +/* ntru_ring_mult_coefficients + * + * Multiplies ring element (polynomial) "a" by ring element (polynomial) "b" + * to produce ring element (polynomial) "c" in (Z/qZ)[X]/(X^N - 1). + * This is a convolution operation. + * + * Ring element "b" has coefficients in the range [0,N). + * + * This assumes q is 2^r where 8 < r < 16, so that overflow of the sum + * beyond 16 bits does not matter. + */ + +extern void +ntru_ring_mult_coefficients( + uint16_t const *a, /* in - pointer to polynomial a */ + uint16_t const *b, /* in - pointer to polynomial b */ + uint16_t N, /* in - no. of coefficients in a, b, c */ + uint16_t q, /* in - large modulus */ + uint16_t *c); /* out - address for polynomial c */ + + +/* ntru_ring_inv + * + * Finds the inverse of a polynomial, a, in (Z/2^rZ)[X]/(X^N - 1). + * + * This assumes q is 2^r where 8 < r < 16, so that operations mod q can + * wait until the end, and only 16-bit arrays need to be used. + */ + +extern bool +ntru_ring_inv( + uint16_t *a, /* in - pointer to polynomial a */ + uint16_t N, /* in - no. of coefficients in a */ + uint16_t q, /* in - large modulus */ + uint16_t *t, /* in - temp buffer of 2N elements */ + uint16_t *a_inv); /* out - address for polynomial a^-1 */ + + +#endif /* NTRU_CRYPTO_NTRU_POLY_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_platform.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_platform.h new file mode 100644 index 000000000..b236cfe69 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_platform.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_platform.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + + +/****************************************************************************** + * + * File: ntru_crypto_platform.h + * + * Contents: Platform-specific basic definitions. + * + *****************************************************************************/ + +#ifndef NTRU_CRYPTO_PLATFORM_H +#define NTRU_CRYPTO_PLATFORM_H + +#include <library.h> + +#endif /* NTRU_CRYPTO_PLATFORM_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha.h new file mode 100644 index 000000000..776d10a4e --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha.h @@ -0,0 +1,65 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_sha.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_sha.h + * + * Contents: Definitions and declarations common to all SHA hash algorithms. + * + *****************************************************************************/ + +#ifndef NTRU_CRYPTO_SHA_H +#define NTRU_CRYPTO_SHA_H + + +#include "ntru_crypto_error.h" +#include "ntru_crypto_hash_basics.h" + + +/*************** + * error codes * + ***************/ + +#define SHA_OK ((uint32_t)NTRU_CRYPTO_HASH_OK) +#define SHA_FAIL ((uint32_t)NTRU_CRYPTO_HASH_FAIL) +#define SHA_BAD_PARAMETER ((uint32_t)NTRU_CRYPTO_HASH_BAD_PARAMETER) +#define SHA_OVERFLOW ((uint32_t)NTRU_CRYPTO_HASH_OVERFLOW) + +#define SHA_RESULT(r) ((uint32_t)((r) ? SHA_ERROR_BASE + (r) : (r))) +#define SHA_RET(r) return SHA_RESULT(r); + + +/********* + * flags * + *********/ + +#define SHA_DATA_ONLY HASH_DATA_ONLY +#define SHA_INIT HASH_INIT +#define SHA_FINISH HASH_FINISH +#define SHA_ZERO_PAD HASH_ZERO_PAD + + +#endif /* NTRU_CRYPTO_SHA_H */ + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha1.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha1.c new file mode 100644 index 000000000..0469ca1d7 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha1.c @@ -0,0 +1,588 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_ntru_crypto_sha1.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_sha1.c + * + * Contents: Routines implementing the SHA-1 hash calculation. + * + *****************************************************************************/ + + +#include <stdlib.h> +#include <string.h> +#include "ntru_crypto_sha1.h" +#include "ntru_crypto_msbyte_uint32.h" + + +/* chaining state elements */ + +#define H0 state[0] +#define H1 state[1] +#define H2 state[2] +#define H3 state[3] +#define H4 state[4] + + +/* standard SHA-1 initialization values */ + +#define H0_INIT 0x67452301UL +#define H1_INIT 0xefcdab89UL +#define H2_INIT 0x98badcfeUL +#define H3_INIT 0x10325476UL +#define H4_INIT 0xc3d2e1f0UL + + +/* sha1_blk() + * + * This routine updates the current hash output (chaining state) + * by performing SHA-1 on a 512-bit block of data represented as sixteen + * 32-bit words. + */ + +#define K00_19 0x5a827999UL +#define K20_39 0x6ed9eba1UL +#define K40_59 0x8f1bbcdcUL +#define K60_79 0xca62c1d6UL + +#define RL(a, n) ( ((a) << (n)) | ((a) >> (32 - (n))) ) + + +static void +sha1_blk( + uint32_t const *data, // in - ptr to 16 32-bit word input block + uint32_t *state) // in/out - ptr to 5 32-bit word chaining state +{ + uint32_t A, B, C, D, E; + uint32_t w[16]; + + /* init A - E */ + + A = H0; B = H1; C = H2; D = H3; E = H4; + + /* rounds 0 - 15 */ + + E += RL(A, 5) + K00_19 + (B & (C ^ D) ^ D) + data[ 0]; B = RL(B, 30); + D += RL(E, 5) + K00_19 + (A & (B ^ C) ^ C) + data[ 1]; A = RL(A, 30); + C += RL(D, 5) + K00_19 + (E & (A ^ B) ^ B) + data[ 2]; E = RL(E, 30); + B += RL(C, 5) + K00_19 + (D & (E ^ A) ^ A) + data[ 3]; D = RL(D, 30); + A += RL(B, 5) + K00_19 + (C & (D ^ E) ^ E) + data[ 4]; C = RL(C, 30); + E += RL(A, 5) + K00_19 + (B & (C ^ D) ^ D) + data[ 5]; B = RL(B, 30); + D += RL(E, 5) + K00_19 + (A & (B ^ C) ^ C) + data[ 6]; A = RL(A, 30); + C += RL(D, 5) + K00_19 + (E & (A ^ B) ^ B) + data[ 7]; E = RL(E, 30); + B += RL(C, 5) + K00_19 + (D & (E ^ A) ^ A) + data[ 8]; D = RL(D, 30); + A += RL(B, 5) + K00_19 + (C & (D ^ E) ^ E) + data[ 9]; C = RL(C, 30); + E += RL(A, 5) + K00_19 + (B & (C ^ D) ^ D) + data[10]; B = RL(B, 30); + D += RL(E, 5) + K00_19 + (A & (B ^ C) ^ C) + data[11]; A = RL(A, 30); + C += RL(D, 5) + K00_19 + (E & (A ^ B) ^ B) + data[12]; E = RL(E, 30); + B += RL(C, 5) + K00_19 + (D & (E ^ A) ^ A) + data[13]; D = RL(D, 30); + A += RL(B, 5) + K00_19 + (C & (D ^ E) ^ E) + data[14]; C = RL(C, 30); + E += RL(A, 5) + K00_19 + (B & (C ^ D) ^ D) + data[15]; B = RL(B, 30); + + /* rounds 16 - 19 */ + + w[ 0] = data[ 0] ^ data[ 2] ^ data[ 8] ^ data[13]; w[ 0] = RL(w[0], 1); + D += RL(E, 5) + K00_19 + (A & (B ^ C) ^ C) + w[ 0]; A = RL(A, 30); + w[ 1] = data[ 1] ^ data[ 3] ^ data[ 9] ^ data[14]; w[ 1] = RL(w[1], 1); + C += RL(D, 5) + K00_19 + (E & (A ^ B) ^ B) + w[ 1]; E = RL(E, 30); + w[ 2] = data[ 2] ^ data[ 4] ^ data[10] ^ data[15]; w[ 2] = RL(w[ 2], 1); + B += RL(C, 5) + K00_19 + (D & (E ^ A) ^ A) + w[ 2]; D = RL(D, 30); + w[ 3] = data[ 3] ^ data[ 5] ^ data[11] ^ w[ 0]; w[ 3] = RL(w[ 3], 1); + A += RL(B, 5) + K00_19 + (C & (D ^ E) ^ E) + w[ 3]; C = RL(C, 30); + + /* rounds 20 - 39 */ + + w[ 4] = data[ 4] ^ data[ 6] ^ data[12] ^ w[ 1]; w[ 4] = RL(w[ 4], 1); + E += RL(A, 5) + K20_39 + (B ^ C ^ D) + w[ 4]; B = RL(B, 30); + w[ 5] = data[ 5] ^ data[ 7] ^ data[13] ^ w[ 2]; w[ 5] = RL(w[ 5], 1); + D += RL(E, 5) + K20_39 + (A ^ B ^ C) + w[ 5]; A = RL(A, 30); + w[ 6] = data[ 6] ^ data[ 8] ^ data[14] ^ w[ 3]; w[ 6] = RL(w[ 6], 1); + C += RL(D, 5) + K20_39 + (E ^ A ^ B) + w[ 6]; E = RL(E, 30); + w[ 7] = data[ 7] ^ data[ 9] ^ data[15] ^ w[ 4]; w[ 7] = RL(w[ 7], 1); + B += RL(C, 5) + K20_39 + (D ^ E ^ A) + w[ 7]; D = RL(D, 30); + w[ 8] = data[ 8] ^ data[10] ^ w[ 0] ^ w[ 5]; w[ 8] = RL(w[ 8], 1); + A += RL(B, 5) + K20_39 + (C ^ D ^ E) + w[ 8]; C = RL(C, 30); + w[ 9] = data[ 9] ^ data[11] ^ w[ 1] ^ w[ 6]; w[ 9] = RL(w[ 9], 1); + E += RL(A, 5) + K20_39 + (B ^ C ^ D) + w[ 9]; B = RL(B, 30); + w[10] = data[10] ^ data[12] ^ w[ 2] ^ w[ 7]; w[10] = RL(w[10], 1); + D += RL(E, 5) + K20_39 + (A ^ B ^ C) + w[10]; A = RL(A, 30); + w[11] = data[11] ^ data[13] ^ w[ 3] ^ w[ 8]; w[11] = RL(w[11], 1); + C += RL(D, 5) + K20_39 + (E ^ A ^ B) + w[11]; E = RL(E, 30); + w[12] = data[12] ^ data[14] ^ w[ 4] ^ w[ 9]; w[12] = RL(w[12], 1); + B += RL(C, 5) + K20_39 + (D ^ E ^ A) + w[12]; D = RL(D, 30); + w[13] = data[13] ^ data[15] ^ w[ 5] ^ w[10]; w[13] = RL(w[13], 1); + A += RL(B, 5) + K20_39 + (C ^ D ^ E) + w[13]; C = RL(C, 30); + w[14] = data[14] ^ w[ 0] ^ w[ 6] ^ w[11]; w[14] = RL(w[14], 1); + E += RL(A, 5) + K20_39 + (B ^ C ^ D) + w[14]; B = RL(B, 30); + w[15] = data[15] ^ w[ 1] ^ w[ 7] ^ w[12]; w[15] = RL(w[15], 1); + D += RL(E, 5) + K20_39 + (A ^ B ^ C) + w[15]; A = RL(A, 30); + w[ 0] = w[ 0] ^ w[ 2] ^ w[ 8] ^ w[13]; w[ 0] = RL(w[ 0], 1); + C += RL(D, 5) + K20_39 + (E ^ A ^ B) + w[ 0]; E = RL(E, 30); + w[ 1] = w[ 1] ^ w[ 3] ^ w[ 9] ^ w[14]; w[ 1] = RL(w[ 1], 1); + B += RL(C, 5) + K20_39 + (D ^ E ^ A) + w[ 1]; D = RL(D, 30); + w[ 2] = w[ 2] ^ w[ 4] ^ w[10] ^ w[15]; w[ 2] = RL(w[ 2], 1); + A += RL(B, 5) + K20_39 + (C ^ D ^ E) + w[ 2]; C = RL(C, 30); + w[ 3] = w[ 3] ^ w[ 5] ^ w[11] ^ w[ 0]; w[ 3] = RL(w[ 3], 1); + E += RL(A, 5) + K20_39 + (B ^ C ^ D) + w[ 3]; B = RL(B, 30); + w[ 4] = w[ 4] ^ w[ 6] ^ w[12] ^ w[ 1]; w[ 4] = RL(w[ 4], 1); + D += RL(E, 5) + K20_39 + (A ^ B ^ C) + w[ 4]; A = RL(A, 30); + w[ 5] = w[ 5] ^ w[ 7] ^ w[13] ^ w[ 2]; w[ 5] = RL(w[ 5], 1); + C += RL(D, 5) + K20_39 + (E ^ A ^ B) + w[ 5]; E = RL(E, 30); + w[ 6] = w[ 6] ^ w[ 8] ^ w[14] ^ w[ 3]; w[ 6] = RL(w[ 6], 1); + B += RL(C, 5) + K20_39 + (D ^ E ^ A) + w[ 6]; D = RL(D, 30); + w[ 7] = w[ 7] ^ w[ 9] ^ w[15] ^ w[ 4]; w[ 7] = RL(w[ 7], 1); + A += RL(B, 5) + K20_39 + (C ^ D ^ E) + w[ 7]; C = RL(C, 30); + + /* rounds 40 - 59 */ + + w[ 8] = w[ 8] ^ w[10] ^ w[ 0] ^ w[ 5]; w[ 8] = RL(w[ 8], 1); + E += RL(A, 5) + K40_59 + ((B & C) | (D & (B | C))) + w[ 8]; B = RL(B, 30); + w[ 9] = w[ 9] ^ w[11] ^ w[ 1] ^ w[ 6]; w[ 9] = RL(w[ 9], 1); + D += RL(E, 5) + K40_59 + ((A & B) | (C & (A | B))) + w[ 9]; A = RL(A, 30); + w[10] = w[10] ^ w[12] ^ w[ 2] ^ w[ 7]; w[10] = RL(w[10], 1); + C += RL(D, 5) + K40_59 + ((E & A) | (B & (E | A))) + w[10]; E = RL(E, 30); + w[11] = w[11] ^ w[13] ^ w[ 3] ^ w[ 8]; w[11] = RL(w[11], 1); + B += RL(C, 5) + K40_59 + ((D & E) | (A & (D | E))) + w[11]; D = RL(D, 30); + w[12] = w[12] ^ w[14] ^ w[ 4] ^ w[ 9]; w[12] = RL(w[12], 1); + A += RL(B, 5) + K40_59 + ((C & D) | (E & (C | D))) + w[12]; C = RL(C, 30); + w[13] = w[13] ^ w[15] ^ w[ 5] ^ w[10]; w[13] = RL(w[13], 1); + E += RL(A, 5) + K40_59 + ((B & C) | (D & (B | C))) + w[13]; B = RL(B, 30); + w[14] = w[14] ^ w[ 0] ^ w[ 6] ^ w[11]; w[14] = RL(w[14], 1); + D += RL(E, 5) + K40_59 + ((A & B) | (C & (A | B))) + w[14]; A = RL(A, 30); + w[15] = w[15] ^ w[ 1] ^ w[ 7] ^ w[12]; w[15] = RL(w[15], 1); + C += RL(D, 5) + K40_59 + ((E & A) | (B & (E | A))) + w[15]; E = RL(E, 30); + w[ 0] = w[ 0] ^ w[ 2] ^ w[ 8] ^ w[13]; w[ 0] = RL(w[ 0], 1); + B += RL(C, 5) + K40_59 + ((D & E) | (A & (D | E))) + w[ 0]; D = RL(D, 30); + w[ 1] = w[ 1] ^ w[ 3] ^ w[ 9] ^ w[14]; w[ 1] = RL(w[ 1], 1); + A += RL(B, 5) + K40_59 + ((C & D) | (E & (C | D))) + w[ 1]; C = RL(C, 30); + w[ 2] = w[ 2] ^ w[ 4] ^ w[10] ^ w[15]; w[ 2] = RL(w[ 2], 1); + E += RL(A, 5) + K40_59 + ((B & C) | (D & (B | C))) + w[ 2]; B = RL(B, 30); + w[ 3] = w[ 3] ^ w[ 5] ^ w[11] ^ w[ 0]; w[ 3] = RL(w[ 3], 1); + D += RL(E, 5) + K40_59 + ((A & B) | (C & (A | B))) + w[ 3]; A = RL(A, 30); + w[ 4] = w[ 4] ^ w[ 6] ^ w[12] ^ w[ 1]; w[ 4] = RL(w[ 4], 1); + C += RL(D, 5) + K40_59 + ((E & A) | (B & (E | A))) + w[ 4]; E = RL(E, 30); + w[ 5] = w[ 5] ^ w[ 7] ^ w[13] ^ w[ 2]; w[ 5] = RL(w[ 5], 1); + B += RL(C, 5) + K40_59 + ((D & E) | (A & (D | E))) + w[ 5]; D = RL(D, 30); + w[ 6] = w[ 6] ^ w[ 8] ^ w[14] ^ w[ 3]; w[ 6] = RL(w[ 6], 1); + A += RL(B, 5) + K40_59 + ((C & D) | (E & (C | D))) + w[ 6]; C = RL(C, 30); + w[ 7] = w[ 7] ^ w[ 9] ^ w[15] ^ w[ 4]; w[ 7] = RL(w[ 7], 1); + E += RL(A, 5) + K40_59 + ((B & C) | (D & (B | C))) + w[ 7]; B = RL(B, 30); + w[ 8] = w[ 8] ^ w[10] ^ w[ 0] ^ w[ 5]; w[ 8] = RL(w[ 8], 1); + D += RL(E, 5) + K40_59 + ((A & B) | (C & (A | B))) + w[ 8]; A = RL(A, 30); + w[ 9] = w[ 9] ^ w[11] ^ w[ 1] ^ w[ 6]; w[ 9] = RL(w[ 9], 1); + C += RL(D, 5) + K40_59 + ((E & A) | (B & (E | A))) + w[ 9]; E = RL(E, 30); + w[10] = w[10] ^ w[12] ^ w[ 2] ^ w[ 7]; w[10] = RL(w[10], 1); + B += RL(C, 5) + K40_59 + ((D & E) | (A & (D | E))) + w[10]; D = RL(D, 30); + w[11] = w[11] ^ w[13] ^ w[ 3] ^ w[ 8]; w[11] = RL(w[11], 1); + A += RL(B, 5) + K40_59 + ((C & D) | (E & (C | D))) + w[11]; C = RL(C, 30); + + /* rounds 60 - 79 */ + + w[12] = w[12] ^ w[14] ^ w[ 4] ^ w[ 9]; w[12] = RL(w[12], 1); + E += RL(A, 5) + K60_79 + (B ^ C ^ D) + w[12]; B = RL(B, 30); + w[13] = w[13] ^ w[15] ^ w[ 5] ^ w[10]; w[13] = RL(w[13], 1); + D += RL(E, 5) + K60_79 + (A ^ B ^ C) + w[13]; A = RL(A, 30); + w[14] = w[14] ^ w[ 0] ^ w[ 6] ^ w[11]; w[14] = RL(w[14], 1); + C += RL(D, 5) + K60_79 + (E ^ A ^ B) + w[14]; E = RL(E, 30); + w[15] = w[15] ^ w[ 1] ^ w[ 7] ^ w[12]; w[15] = RL(w[15], 1); + B += RL(C, 5) + K60_79 + (D ^ E ^ A) + w[15]; D = RL(D, 30); + w[ 0] = w[ 0] ^ w[ 2] ^ w[ 8] ^ w[13]; w[ 0] = RL(w[ 0], 1); + A += RL(B, 5) + K60_79 + (C ^ D ^ E) + w[ 0]; C = RL(C, 30); + w[ 1] = w[ 1] ^ w[ 3] ^ w[ 9] ^ w[14]; w[ 1] = RL(w[ 1], 1); + E += RL(A, 5) + K60_79 + (B ^ C ^ D) + w[ 1]; B = RL(B, 30); + w[ 2] = w[ 2] ^ w[ 4] ^ w[10] ^ w[15]; w[ 2] = RL(w[ 2], 1); + D += RL(E, 5) + K60_79 + (A ^ B ^ C) + w[ 2]; A = RL(A, 30); + w[ 3] = w[ 3] ^ w[ 5] ^ w[11] ^ w[ 0]; w[ 3] = RL(w[ 3], 1); + C += RL(D, 5) + K60_79 + (E ^ A ^ B) + w[ 3]; E = RL(E, 30); + w[ 4] = w[ 4] ^ w[ 6] ^ w[12] ^ w[ 1]; w[ 4] = RL(w[ 4], 1); + B += RL(C, 5) + K60_79 + (D ^ E ^ A) + w[ 4]; D = RL(D, 30); + w[ 5] = w[ 5] ^ w[ 7] ^ w[13] ^ w[ 2]; w[ 5] = RL(w[ 5], 1); + A += RL(B, 5) + K60_79 + (C ^ D ^ E) + w[ 5]; C = RL(C, 30); + w[ 6] = w[ 6] ^ w[ 8] ^ w[14] ^ w[ 3]; w[ 6] = RL(w[ 6], 1); + E += RL(A, 5) + K60_79 + (B ^ C ^ D) + w[ 6]; B = RL(B, 30); + w[ 7] = w[ 7] ^ w[ 9] ^ w[15] ^ w[ 4]; w[ 7] = RL(w[ 7], 1); + D += RL(E, 5) + K60_79 + (A ^ B ^ C) + w[ 7]; A = RL(A, 30); + w[ 8] = w[ 8] ^ w[10] ^ w[ 0] ^ w[ 5]; w[ 8] = RL(w[ 8], 1); + C += RL(D, 5) + K60_79 + (E ^ A ^ B) + w[ 8]; E = RL(E, 30); + w[ 9] = w[ 9] ^ w[11] ^ w[ 1] ^ w[ 6]; w[ 9] = RL(w[ 9], 1); + B += RL(C, 5) + K60_79 + (D ^ E ^ A) + w[ 9]; D = RL(D, 30); + w[10] = w[10] ^ w[12] ^ w[ 2] ^ w[ 7]; w[10] = RL(w[10], 1); + A += RL(B, 5) + K60_79 + (C ^ D ^ E) + w[10]; C = RL(C, 30); + w[11] = w[11] ^ w[13] ^ w[ 3] ^ w[ 8]; w[11] = RL(w[11], 1); + E += RL(A, 5) + K60_79 + (B ^ C ^ D) + w[11]; B = RL(B, 30); + w[12] = w[12] ^ w[14] ^ w[ 4] ^ w[ 9]; w[12] = RL(w[12], 1); + D += RL(E, 5) + K60_79 + (A ^ B ^ C) + w[12]; A = RL(A, 30); + w[13] = w[13] ^ w[15] ^ w[ 5] ^ w[10]; + C += RL(D, 5) + K60_79 + (E ^ A ^ B) + RL(w[13], 1); E = RL(E, 30); + w[14] = w[14] ^ w[ 0] ^ w[ 6] ^ w[11]; + B += RL(C, 5) + K60_79 + (D ^ E ^ A) + RL(w[14], 1); D = RL(D, 30); + + /* update H0 - H4 */ + + w[15] = w[15] ^ w[ 1] ^ w[ 7] ^ w[12]; + H0 += A + RL(B, 5) + K60_79 + (C ^ D ^ E) + RL(w[15], 1); + H1 += B; + H2 += RL(C, 30); + H3 += D; + H4 += E; + + /* clear temp variables */ + + A = B = C = D = E = 0; + memset(w, 0, sizeof(w)); +} + + +/* ntru_crypto_sha1() + * + * This routine provides all operations for a SHA-1 hash, and the use + * of SHA-1 for DSA signing and key generation. + * It may be used to initialize, update, or complete a message digest, + * or any combination of those actions, as determined by the SHA_INIT flag, + * the in_len parameter, and the SHA_FINISH flag, respectively. + * + * When in_len == 0 (no data to hash), the parameter, in, may be NULL. + * When the SHA_FINISH flag is not set, the parameter, md, may be NULL. + * + * Initialization may be standard or use a specified initialization vector, + * and is indicated by setting the SHA_INIT flag. + * Setting init = NULL specifies standard initialization. Otherwise, init + * points to the array of five alternate initialization 32-bit words. + * + * The hash operation can be updated with any number of input bytes, including + * zero. + * + * The hash operation can be completed with normal padding or with zero + * padding as required for parts of DSA parameter generation, and is indicated + * by setting the SHA_FINISH flag. Using zero padding, indicated by setting + * the SHA_ZERO_PAD flag, never creates an extra input block because the + * bit count is not included in the hashed data. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +uint32_t +ntru_crypto_sha1( + NTRU_CRYPTO_SHA1_CTX *c, /* in/out - pointer to SHA-1 context */ + uint32_t const *init, /* in - pointer to alternate */ + /* initialization - may be NULL */ + uint8_t const *in, /* in - pointer to input data - + may be NULL if in_len == 0 */ + uint32_t in_len, /* in - number of input data bytes */ + uint32_t flags, /* in - INIT, FINISH, zero-pad flags */ + uint8_t *md) /* out - address for message digest - + may be NULL if not FINISH */ +{ + uint32_t in_blk[16]; /* input block */ + uint32_t space; + uint8_t *d = NULL; + + /* check error conditions */ + + if (!c || (in_len && !in) || ((flags & SHA_FINISH) && !md)) + SHA_RET(SHA_BAD_PARAMETER) + + /* initialize context if requested */ + + if (flags & SHA_INIT) { + + /* init chaining state */ + + if (!init) { + c->state[0] = H0_INIT; // standard initialization + c->state[1] = H1_INIT; + c->state[2] = H2_INIT; + c->state[3] = H3_INIT; + c->state[4] = H4_INIT; + } else { + c->state[0] = init[0]; // alternate initialization + c->state[1] = init[1]; + c->state[2] = init[2]; + c->state[3] = init[3]; + c->state[4] = init[4]; + } + + /* init bit count and number of unhashed data bytes */ + + c->num_bits_hashed[0] = 0; + c->num_bits_hashed[1] = 0; + c->unhashed_len = 0; + } + + /* determine space left in unhashed data buffer */ + + if (c->unhashed_len > 63) + SHA_RET(SHA_FAIL) + + space = 64 - c->unhashed_len; + + /* process input if it exists */ + + if (in_len) { + + /* update count of bits hashed */ + + { + uint32_t bits0, bits1; + + bits0 = in_len << 3; + bits1 = in_len >> 29; + if ((c->num_bits_hashed[0] += bits0) < bits0) + bits1++; + if ((c->num_bits_hashed[1] += bits1) < bits1) { + memset((uint8_t *) c, 0, sizeof(NTRU_CRYPTO_SHA1_CTX)); + space = 0; + memset((char *) in_blk, 0, sizeof(in_blk)); + SHA_RET(SHA_OVERFLOW) + } + } + + /* process input bytes */ + + if (in_len < space) { + + /* input does not fill block buffer: + * add input to buffer + */ + + memcpy(c->unhashed + c->unhashed_len, in, in_len); + c->unhashed_len += in_len; + + } else { + uint32_t blks; + + /* input will fill block buffer: + * fill unhashed data buffer, + * convert to block buffer, + * and process block + */ + + in_len -= space; + for (d = c->unhashed + c->unhashed_len; space; space--) + *d++ = *in++; + ntru_crypto_msbyte_2_uint32(in_blk, (uint8_t const *) c->unhashed, + 16); + sha1_blk((uint32_t const *) in_blk, c->state); + + /* process any remaining full blocks */ + + for (blks = in_len >> 6; blks--; in += 64) { + ntru_crypto_msbyte_2_uint32(in_blk, in, 16); + sha1_blk((uint32_t const *) in_blk, c->state); + } + + /* put any remaining input in the unhashed data buffer */ + + in_len &= 0x3f; + memcpy(c->unhashed, in, in_len); + c->unhashed_len = in_len; + } + } + + /* complete message digest if requested */ + + if (flags & SHA_FINISH) { + space = 64 - c->unhashed_len; + + /* check padding type */ + + if (!(flags & SHA_ZERO_PAD)) { + + /* add 0x80 padding byte to the unhashed data buffer + * (there is always space since the buffer can't be full) + */ + + d = c->unhashed + c->unhashed_len; + *d++ = 0x80; + space--; + + /* check for space for bit count */ + + if (space < 8) { + + /* no space for count: + * fill remainder of unhashed data buffer with zeros, + * convert to input block, + * process block, + * fill all but 8 bytes of unhashed data buffer with zeros + */ + + memset(d, 0, space); + ntru_crypto_msbyte_2_uint32(in_blk, + (uint8_t const *) c->unhashed, 16); + sha1_blk((uint32_t const *) in_blk, c->state); + memset(c->unhashed, 0, 56); + + } else { + + /* fill unhashed data buffer with zeros, + * leaving space for bit count + */ + + for (space -= 8; space; space--) + *d++ = 0; + } + + /* convert partially filled unhashed data buffer to input block and + * add bit count to input block + */ + + ntru_crypto_msbyte_2_uint32(in_blk, (uint8_t const *) c->unhashed, + 14); + in_blk[14] = c->num_bits_hashed[1]; + in_blk[15] = c->num_bits_hashed[0]; + + } else { + + /* pad unhashed data buffer with zeros and no bit count and + * convert to input block + */ + + memset(c->unhashed + c->unhashed_len, 0, space); + ntru_crypto_msbyte_2_uint32(in_blk, (uint8_t const *) c->unhashed, + 16); + } + + /* process last block */ + + sha1_blk((uint32_t const *) in_blk, c->state); + + /* copy result to message digest buffer */ + + ntru_crypto_uint32_2_msbyte(md, c->state, 5); + + /* clear context and stack variables */ + + memset((uint8_t *) c, 0, sizeof(NTRU_CRYPTO_SHA1_CTX)); + space = 0; + memset((char *) in_blk, 0, sizeof(in_blk)); + } + + SHA_RET(SHA_OK) +} + + +/* ntru_crypto_sha1_init + * + * This routine performs standard initialization of the SHA-1 state. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + */ + +uint32_t +ntru_crypto_sha1_init( + NTRU_CRYPTO_SHA1_CTX *c) /* in/out - pointer to SHA-1 context */ +{ + return ntru_crypto_sha1(c, NULL, NULL, 0, SHA_INIT, NULL); +} + + +/* ntru_crypto_sha1_update + * + * This routine processes input data and updates the SHA-1 hash calculation. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +uint32_t +ntru_crypto_sha1_update( + NTRU_CRYPTO_SHA1_CTX *c, /* in/out - pointer to SHA-1 context */ + uint8_t const *data, /* in - pointer to input data */ + uint32_t data_len) /* in - number of bytes of input data */ +{ + return ntru_crypto_sha1(c, NULL, data, data_len, SHA_DATA_ONLY, NULL); +} + + +/* ntru_crypto_sha1_final + * + * This routine completes the SHA-1 hash calculation and returns the + * message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +uint32_t +ntru_crypto_sha1_final( + NTRU_CRYPTO_SHA1_CTX *c, /* in/out - pointer to SHA-1 context */ + uint8_t *md) /* out - address for message digest */ +{ + return ntru_crypto_sha1(c, NULL, NULL, 0, SHA_FINISH, md); +} + + +/* ntru_crypto_sha1_final_zero_pad + * + * This routine completes the SHA-1 hash calculation using zero padding + * and returns the message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +uint32_t +ntru_crypto_sha1_final_zero_pad( + NTRU_CRYPTO_SHA1_CTX *c, /* in/out - pointer to SHA-1 context */ + uint8_t *md) /* out - address for message digest */ +{ + return ntru_crypto_sha1(c, NULL, NULL, 0, SHA_FINISH | SHA_ZERO_PAD, md); +} + + +/* ntru_crypto_sha1_digest + * + * This routine computes a SHA-1 message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +uint32_t +ntru_crypto_sha1_digest( + uint8_t const *data, // in - pointer to input data + uint32_t data_len, // in - number of bytes of input data + uint8_t *md) // out - address for message digest +{ + NTRU_CRYPTO_SHA1_CTX c; + + return ntru_crypto_sha1(&c, NULL, data, data_len, SHA_INIT | SHA_FINISH, + md); +} + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha1.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha1.h new file mode 100644 index 000000000..fbb2e4617 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha1.h @@ -0,0 +1,205 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_crypto_sha1.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_sha1.h + * + * Contents: Definitions and declarations for the SHA-1 implementation. + * + *****************************************************************************/ + +#ifndef NTRU_CRYPTO_SHA1_H +#define NTRU_CRYPTO_SHA1_H + + +#include "ntru_crypto_platform.h" +#include "ntru_crypto_sha.h" + + +/****************************************** + * macros needed for generic hash objects * + ******************************************/ + +#define SHA_1_CTX_LEN sizeof(SHA1_CTX) /* no. bytes in SHA-1 + ctx */ +#define SHA_1_BLK_LEN 64 /* 64 bytes in input + block */ +#define SHA_1_MD_LEN 20 /* 20 bytes in msg + digest */ +#define SHA_1_INIT_FN &ntru_crypto_sha1_init /* init function */ +#define SHA_1_UPDATE_FN &ntru_crypto_sha1_update /* update function */ +#define SHA_1_FINAL_FN &ntru_crypto_sha1_final /* final function */ +#define SHA_1_FINAL_ZERO_PAD_FN \ + &ntru_crypto_sha1_final_zero_pad + /* final function using + zero padding */ +#define SHA_1_DIGEST_FN &ntru_crypto_sha1_digest /* digest function */ + + +/************************* + * structure definitions * + *************************/ + +/* SHA-1 context structure */ + +typedef struct { + uint32_t state[5]; // chaining state + uint32_t num_bits_hashed[2]; // number of bits hashed + uint8_t unhashed[64]; // input data not yet hashed + uint32_t unhashed_len; // number of bytes of unhashed input data +} NTRU_CRYPTO_SHA1_CTX; + + +/************************* + * function declarations * + *************************/ + +/* ntru_crypto_sha1() + * + * This routine provides all operations for a SHA-1 hash, and the use + * of SHA-1 for DSA signing and key generation. + * It may be used to initialize, update, or complete a message digest, + * or any combination of those actions, as determined by the SHA_INIT flag, + * the in_len parameter, and the SHA_FINISH flag, respectively. + * + * When in_len == 0 (no data to hash), the parameter, in, may be NULL. + * When the SHA_FINISH flag is not set, the parameter, md, may be NULL. + * + * Initialization may be standard or use a specified initialization vector, + * and is indicated by setting the SHA_INIT flag. + * Setting init = NULL specifies standard initialization. Otherwise, init + * points to the array of five alternate initialization 32-bit words. + * + * The hash operation can be updated with any number of input bytes, including + * zero. + * + * The hash operation can be completed with normal padding or with zero + * padding as required for parts of DSA parameter generation, and is indicated + * by setting the SHA_FINISH flag. Using zero padding, indicated by setting + * the SHA_ZERO_PAD flag, never creates an extra input block because the + * bit count is not included in the hashed data. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +extern uint32_t +ntru_crypto_sha1( + NTRU_CRYPTO_SHA1_CTX *c, /* in/out - pointer to SHA-1 context */ + uint32_t const *init, /* in - pointer to alternate */ + /* initialization - may be NULL */ + uint8_t const *in, /* in - pointer to input data - + may be NULL if in_len == 0 */ + uint32_t in_len, /* in - number of input data bytes */ + uint32_t flags, /* in - INIT, FINISH, zero-pad flags */ + uint8_t *md); /* out - address for message digest - + may be NULL if not FINISH */ + + +/* ntru_crypto_sha1_init + * + * This routine performs standard initialization of the SHA-1 state. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + */ + +extern uint32_t +ntru_crypto_sha1_init( + NTRU_CRYPTO_SHA1_CTX *c); /* in/out - pointer to SHA-1 context */ + + +/* ntru_crypto_sha1_update + * + * This routine processes input data and updates the SHA-1 hash calculation. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +extern uint32_t +ntru_crypto_sha1_update( + NTRU_CRYPTO_SHA1_CTX *c, /* in/out - pointer to SHA-1 context */ + uint8_t const *data, /* in - pointer to input data */ + uint32_t data_len); /* in - number of bytes of input data */ + + +/* ntru_crypto_sha1_final + * + * This routine completes the SHA-1 hash calculation and returns the + * message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +extern uint32_t +ntru_crypto_sha1_final( + NTRU_CRYPTO_SHA1_CTX *c, /* in/out - pointer to SHA-1 context */ + uint8_t *md); /* out - address for message digest */ + + +/* ntru_crypto_sha1_final_zero_pad + * + * This routine completes the SHA-1 hash calculation using zero padding + * and returns the message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +extern uint32_t +ntru_crypto_sha1_final_zero_pad( + NTRU_CRYPTO_SHA1_CTX *c, /* in/out - pointer to SHA-1 context */ + uint8_t *md); /* out - address for message digest */ + + +/* ntru_crypto_sha1_digest + * + * This routine computes a SHA-1 message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +uint32_t +ntru_crypto_sha1_digest( + uint8_t const *data, /* in - pointer to input data */ + uint32_t data_len, /* in - number of bytes of input data */ + uint8_t *md); /* out - address for message digest */ + + +#endif /* NTRU_CRYPTO_SHA1_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha2.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha2.c new file mode 100644 index 000000000..796cc4f2b --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha2.c @@ -0,0 +1,532 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_sha2.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_sha2.c + * + * Contents: Routines implementing the SHA-256 hash calculation. + * + *****************************************************************************/ + + +#include <stdlib.h> +#include <string.h> +#include "ntru_crypto_sha2.h" +#include "ntru_crypto_msbyte_uint32.h" + + +/* chaining state elements */ + +#define H0 state[0] +#define H1 state[1] +#define H2 state[2] +#define H3 state[3] +#define H4 state[4] +#define H5 state[5] +#define H6 state[6] +#define H7 state[7] + + +/* standard SHA-256 initialization values */ + +#define H0_SHA256_INIT 0x6a09e667UL +#define H1_SHA256_INIT 0xbb67ae85UL +#define H2_SHA256_INIT 0x3c6ef372UL +#define H3_SHA256_INIT 0xa54ff53aUL +#define H4_SHA256_INIT 0x510e527fUL +#define H5_SHA256_INIT 0x9b05688cUL +#define H6_SHA256_INIT 0x1f83d9abUL +#define H7_SHA256_INIT 0x5be0cd19UL + + +/* sha2_blk() + * + * This routine updates the current hash output (chaining state) + * by performing SHA-256 on a 512-bit block of data represented + * as sixteen 32-bit words. + */ + +#define RR(a, n) ( ((a) >> (n)) | ((a) << (32 - (n))) ) +#define S0(a) ( RR((a), 2) ^ RR((a), 13) ^ RR((a), 22) ) +#define S1(a) ( RR((a), 6) ^ RR((a), 11) ^ RR((a), 25) ) +#define s0(a) ( RR((a), 7) ^ RR((a), 18) ^ ((a) >> 3) ) +#define s1(a) ( RR((a), 17) ^ RR((a), 19) ^ ((a) >> 10) ) + + +static void +sha2_blk( + uint32_t const *data, // in - ptr to 16 32-bit word input block + uint32_t *state) // in/out - ptr to 8 32-bit word chaining state +{ + uint32_t A, B, C, D, E, F, G, H; + uint32_t w[16]; + + /* init A - H */ + + A = H0; B = H1; C = H2; D = H3; E = H4; F = H5; G = H6; H = H7; + + /* rounds 0 - 15 */ + + H += S1(E) + (E & (F ^ G) ^ G) + 0x428A2F98UL + data[ 0]; D += H; + H += S0(A) + ((A & B) | (C & (A | B))); + G += S1(D) + (D & (E ^ F) ^ F) + 0x71374491UL + data[ 1]; C += G; + G += S0(H) + ((H & A) | (B & (H | A))); + F += S1(C) + (C & (D ^ E) ^ E) + 0xB5C0FBCFUL + data[ 2]; B += F; + F += S0(G) + ((G & H) | (A & (G | H))); + E += S1(B) + (B & (C ^ D) ^ D) + 0xE9B5DBA5UL + data[ 3]; A += E; + E += S0(F) + ((F & G) | (H & (F | G))); + D += S1(A) + (A & (B ^ C) ^ C) + 0x3956C25BUL + data[ 4]; H += D; + D += S0(E) + ((E & F) | (G & (E | F))); + C += S1(H) + (H & (A ^ B) ^ B) + 0x59F111F1UL + data[ 5]; G += C; + C += S0(D) + ((D & E) | (F & (D | E))); + B += S1(G) + (G & (H ^ A) ^ A) + 0x923F82A4UL + data[ 6]; F += B; + B += S0(C) + ((C & D) | (E & (C | D))); + A += S1(F) + (F & (G ^ H) ^ H) + 0xAB1C5ED5UL + data[ 7]; E += A; + A += S0(B) + ((B & C) | (D & (B | C))); + H += S1(E) + (E & (F ^ G) ^ G) + 0xD807AA98UL + data[ 8]; D += H; + H += S0(A) + ((A & B) | (C & (A | B))); + G += S1(D) + (D & (E ^ F) ^ F) + 0x12835B01UL + data[ 9]; C += G; + G += S0(H) + ((H & A) | (B & (H | A))); + F += S1(C) + (C & (D ^ E) ^ E) + 0x243185BEUL + data[10]; B += F; + F += S0(G) + ((G & H) | (A & (G | H))); + E += S1(B) + (B & (C ^ D) ^ D) + 0x550C7DC3UL + data[11]; A += E; + E += S0(F) + ((F & G) | (H & (F | G))); + D += S1(A) + (A & (B ^ C) ^ C) + 0x72BE5D74UL + data[12]; H += D; + D += S0(E) + ((E & F) | (G & (E | F))); + C += S1(H) + (H & (A ^ B) ^ B) + 0x80DEB1FEUL + data[13]; G += C; + C += S0(D) + ((D & E) | (F & (D | E))); + B += S1(G) + (G & (H ^ A) ^ A) + 0x9BDC06A7UL + data[14]; F += B; + B += S0(C) + ((C & D) | (E & (C | D))); + A += S1(F) + (F & (G ^ H) ^ H) + 0xC19BF174UL + data[15]; E += A; + A += S0(B) + ((B & C) | (D & (B | C))); + + /* rounds 16 - 63 */ + + w[ 0] = data[ 0] + s0(data[ 1]) + data[ 9] + s1(data[14]); + H += S1(E) + (E & (F ^ G) ^ G) + 0xE49B69C1UL + w[ 0]; D += H; + H += S0(A) + ((A & B) | (C & (A | B))); + w[ 1] = data[ 1] + s0(data[ 2]) + data[10] + s1(data[15]); + G += S1(D) + (D & (E ^ F) ^ F) + 0xEFBE4786UL + w[ 1]; C += G; + G += S0(H) + ((H & A) | (B & (H | A))); + w[ 2] = data[ 2] + s0(data[ 3]) + data[11] + s1(w[ 0]); + F += S1(C) + (C & (D ^ E) ^ E) + 0x0FC19DC6UL + w[ 2]; B += F; + F += S0(G) + ((G & H) | (A & (G | H))); + w[ 3] = data[ 3] + s0(data[ 4]) + data[12] + s1(w[ 1]); + E += S1(B) + (B & (C ^ D) ^ D) + 0x240CA1CCUL + w[ 3]; A += E; + E += S0(F) + ((F & G) | (H & (F | G))); + w[ 4] = data[ 4] + s0(data[ 5]) + data[13] + s1(w[ 2]); + D += S1(A) + (A & (B ^ C) ^ C) + 0x2DE92C6FUL + w[ 4]; H += D; + D += S0(E) + ((E & F) | (G & (E | F))); + w[ 5] = data[ 5] + s0(data[ 6]) + data[14] + s1(w[ 3]); + C += S1(H) + (H & (A ^ B) ^ B) + 0x4A7484AAUL + w[ 5]; G += C; + C += S0(D) + ((D & E) | (F & (D | E))); + w[ 6] = data[ 6] + s0(data[ 7]) + data[15] + s1(w[ 4]); + B += S1(G) + (G & (H ^ A) ^ A) + 0x5CB0A9DCUL + w[ 6]; F += B; + B += S0(C) + ((C & D) | (E & (C | D))); + w[ 7] = data[ 7] + s0(data[ 8]) + w[ 0] + s1(w[ 5]); + A += S1(F) + (F & (G ^ H) ^ H) + 0x76F988DAUL + w[ 7]; E += A; + A += S0(B) + ((B & C) | (D & (B | C))); + w[ 8] = data[ 8] + s0(data[ 9]) + w[ 1] + s1(w[ 6]); + H += S1(E) + (E & (F ^ G) ^ G) + 0x983E5152UL + w[ 8]; D += H; + H += S0(A) + ((A & B) | (C & (A | B))); + w[ 9] = data[ 9] + s0(data[10]) + w[ 2] + s1(w[ 7]); + G += S1(D) + (D & (E ^ F) ^ F) + 0xA831C66DUL + w[ 9]; C += G; + G += S0(H) + ((H & A) | (B & (H | A))); + w[10] = data[10] + s0(data[11]) + w[ 3] + s1(w[ 8]); + F += S1(C) + (C & (D ^ E) ^ E) + 0xB00327C8UL + w[10]; B += F; + F += S0(G) + ((G & H) | (A & (G | H))); + w[11] = data[11] + s0(data[12]) + w[ 4] + s1(w[ 9]); + E += S1(B) + (B & (C ^ D) ^ D) + 0xBF597FC7UL + w[11]; A += E; + E += S0(F) + ((F & G) | (H & (F | G))); + w[12] = data[12] + s0(data[13]) + w[ 5] + s1(w[10]); + D += S1(A) + (A & (B ^ C) ^ C) + 0xC6E00BF3UL + w[12]; H += D; + D += S0(E) + ((E & F) | (G & (E | F))); + w[13] = data[13] + s0(data[14]) + w[ 6] + s1(w[11]); + C += S1(H) + (H & (A ^ B) ^ B) + 0xD5A79147UL + w[13]; G += C; + C += S0(D) + ((D & E) | (F & (D | E))); + w[14] = data[14] + s0(data[15]) + w[ 7] + s1(w[12]); + B += S1(G) + (G & (H ^ A) ^ A) + 0x06CA6351UL + w[14]; F += B; + B += S0(C) + ((C & D) | (E & (C | D))); + w[15] = data[15] + s0(w[ 0]) + w[ 8] + s1(w[13]); + A += S1(F) + (F & (G ^ H) ^ H) + 0x14292967UL + w[15]; E += A; + A += S0(B) + ((B & C) | (D & (B | C))); + w[ 0] = w[ 0] + s0(w[ 1]) + w[ 9] + s1(w[14]); + H += S1(E) + (E & (F ^ G) ^ G) + 0x27B70A85UL + w[ 0]; D += H; + H += S0(A) + ((A & B) | (C & (A | B))); + w[ 1] = w[ 1] + s0(w[ 2]) + w[10] + s1(w[15]); + G += S1(D) + (D & (E ^ F) ^ F) + 0x2E1B2138UL + w[ 1]; C += G; + G += S0(H) + ((H & A) | (B & (H | A))); + w[ 2] = w[ 2] + s0(w[ 3]) + w[11] + s1(w[ 0]); + F += S1(C) + (C & (D ^ E) ^ E) + 0x4D2C6DFCUL + w[ 2]; B += F; + F += S0(G) + ((G & H) | (A & (G | H))); + w[ 3] = w[ 3] + s0(w[ 4]) + w[12] + s1(w[ 1]); + E += S1(B) + (B & (C ^ D) ^ D) + 0x53380D13UL + w[ 3]; A += E; + E += S0(F) + ((F & G) | (H & (F | G))); + w[ 4] = w[ 4] + s0(w[ 5]) + w[13] + s1(w[ 2]); + D += S1(A) + (A & (B ^ C) ^ C) + 0x650A7354UL + w[ 4]; H += D; + D += S0(E) + ((E & F) | (G & (E | F))); + w[ 5] = w[ 5] + s0(w[ 6]) + w[14] + s1(w[ 3]); + C += S1(H) + (H & (A ^ B) ^ B) + 0x766A0ABBUL + w[ 5]; G += C; + C += S0(D) + ((D & E) | (F & (D | E))); + w[ 6] = w[ 6] + s0(w[ 7]) + w[15] + s1(w[ 4]); + B += S1(G) + (G & (H ^ A) ^ A) + 0x81C2C92EUL + w[ 6]; F += B; + B += S0(C) + ((C & D) | (E & (C | D))); + w[ 7] = w[ 7] + s0(w[ 8]) + w[ 0] + s1(w[ 5]); + A += S1(F) + (F & (G ^ H) ^ H) + 0x92722C85UL + w[ 7]; E += A; + A += S0(B) + ((B & C) | (D & (B | C))); + w[ 8] = w[ 8] + s0(w[ 9]) + w[ 1] + s1(w[ 6]); + H += S1(E) + (E & (F ^ G) ^ G) + 0xA2BFE8A1UL + w[ 8]; D += H; + H += S0(A) + ((A & B) | (C & (A | B))); + w[ 9] = w[ 9] + s0(w[10]) + w[ 2] + s1(w[ 7]); + G += S1(D) + (D & (E ^ F) ^ F) + 0xA81A664BUL + w[ 9]; C += G; + G += S0(H) + ((H & A) | (B & (H | A))); + w[10] = w[10] + s0(w[11]) + w[ 3] + s1(w[ 8]); + F += S1(C) + (C & (D ^ E) ^ E) + 0xC24B8B70UL + w[10]; B += F; + F += S0(G) + ((G & H) | (A & (G | H))); + w[11] = w[11] + s0(w[12]) + w[ 4] + s1(w[ 9]); + E += S1(B) + (B & (C ^ D) ^ D) + 0xC76C51A3UL + w[11]; A += E; + E += S0(F) + ((F & G) | (H & (F | G))); + w[12] = w[12] + s0(w[13]) + w[ 5] + s1(w[10]); + D += S1(A) + (A & (B ^ C) ^ C) + 0xD192E819UL + w[12]; H += D; + D += S0(E) + ((E & F) | (G & (E | F))); + w[13] = w[13] + s0(w[14]) + w[ 6] + s1(w[11]); + C += S1(H) + (H & (A ^ B) ^ B) + 0xD6990624UL + w[13]; G += C; + C += S0(D) + ((D & E) | (F & (D | E))); + w[14] = w[14] + s0(w[15]) + w[ 7] + s1(w[12]); + B += S1(G) + (G & (H ^ A) ^ A) + 0xF40E3585UL + w[14]; F += B; + B += S0(C) + ((C & D) | (E & (C | D))); + w[15] = w[15] + s0(w[ 0]) + w[ 8] + s1(w[13]); + A += S1(F) + (F & (G ^ H) ^ H) + 0x106AA070UL + w[15]; E += A; + A += S0(B) + ((B & C) | (D & (B | C))); + w[ 0] = w[ 0] + s0(w[ 1]) + w[ 9] + s1(w[14]); + H += S1(E) + (E & (F ^ G) ^ G) + 0x19A4C116UL + w[ 0]; D += H; + H += S0(A) + ((A & B) | (C & (A | B))); + w[ 1] = w[ 1] + s0(w[ 2]) + w[10] + s1(w[15]); + G += S1(D) + (D & (E ^ F) ^ F) + 0x1E376C08UL + w[ 1]; C += G; + G += S0(H) + ((H & A) | (B & (H | A))); + w[ 2] = w[ 2] + s0(w[ 3]) + w[11] + s1(w[ 0]); + F += S1(C) + (C & (D ^ E) ^ E) + 0x2748774CUL + w[ 2]; B += F; + F += S0(G) + ((G & H) | (A & (G | H))); + w[ 3] = w[ 3] + s0(w[ 4]) + w[12] + s1(w[ 1]); + E += S1(B) + (B & (C ^ D) ^ D) + 0x34B0BCB5UL + w[ 3]; A += E; + E += S0(F) + ((F & G) | (H & (F | G))); + w[ 4] = w[ 4] + s0(w[ 5]) + w[13] + s1(w[ 2]); + D += S1(A) + (A & (B ^ C) ^ C) + 0x391C0CB3UL + w[ 4]; H += D; + D += S0(E) + ((E & F) | (G & (E | F))); + w[ 5] = w[ 5] + s0(w[ 6]) + w[14] + s1(w[ 3]); + C += S1(H) + (H & (A ^ B) ^ B) + 0x4ED8AA4AUL + w[ 5]; G += C; + C += S0(D) + ((D & E) | (F & (D | E))); + w[ 6] = w[ 6] + s0(w[ 7]) + w[15] + s1(w[ 4]); + B += S1(G) + (G & (H ^ A) ^ A) + 0x5B9CCA4FUL + w[ 6]; F += B; + B += S0(C) + ((C & D) | (E & (C | D))); + w[ 7] = w[ 7] + s0(w[ 8]) + w[ 0] + s1(w[ 5]); + A += S1(F) + (F & (G ^ H) ^ H) + 0x682E6FF3UL + w[ 7]; E += A; + A += S0(B) + ((B & C) | (D & (B | C))); + w[ 8] = w[ 8] + s0(w[ 9]) + w[ 1] + s1(w[ 6]); + H += S1(E) + (E & (F ^ G) ^ G) + 0x748F82EEUL + w[ 8]; D += H; + H += S0(A) + ((A & B) | (C & (A | B))); + w[ 9] = w[ 9] + s0(w[10]) + w[ 2] + s1(w[ 7]); + G += S1(D) + (D & (E ^ F) ^ F) + 0x78A5636FUL + w[ 9]; C += G; + G += S0(H) + ((H & A) | (B & (H | A))); + w[10] = w[10] + s0(w[11]) + w[ 3] + s1(w[ 8]); + F += S1(C) + (C & (D ^ E) ^ E) + 0x84C87814UL + w[10]; B += F; + F += S0(G) + ((G & H) | (A & (G | H))); + w[11] = w[11] + s0(w[12]) + w[ 4] + s1(w[ 9]); + E += S1(B) + (B & (C ^ D) ^ D) + 0x8CC70208UL + w[11]; A += E; + E += S0(F) + ((F & G) | (H & (F | G))); + w[12] = w[12] + s0(w[13]) + w[ 5] + s1(w[10]); + D += S1(A) + (A & (B ^ C) ^ C) + 0x90BEFFFAUL + w[12]; H += D; + D += S0(E) + ((E & F) | (G & (E | F))); + w[13] = w[13] + s0(w[14]) + w[ 6] + s1(w[11]); + C += S1(H) + (H & (A ^ B) ^ B) + 0xA4506CEBUL + w[13]; G += C; + C += S0(D) + ((D & E) | (F & (D | E))); + w[14] = w[14] + s0(w[15]) + w[ 7] + s1(w[12]); + B += S1(G) + (G & (H ^ A) ^ A) + 0xBEF9A3F7UL + w[14]; F += B; + B += S0(C) + ((C & D) | (E & (C | D))); + w[15] = w[15] + s0(w[ 0]) + w[ 8] + s1(w[13]); + A += S1(F) + (F & (G ^ H) ^ H) + 0xC67178F2UL + w[15]; E += A; + A += S0(B) + ((B & C) | (D & (B | C))); + + /* update H0 - H7 */ + + H0 += A; + H1 += B; + H2 += C; + H3 += D; + H4 += E; + H5 += F; + H6 += G; + H7 += H; + + /* clear temp variables */ + + A = B = C = D = E = F = G = H = 0; + memset(w, 0, sizeof(w)); +} + + +/* ntru_crypto_sha2() + * + * This routine provides all operations for a SHA-256 hash, + * and the use of SHA-256 for DSA signing and key generation. + * It may be used to initialize, update, or complete a message digest, + * or any combination of those actions, as determined by the SHA_INIT flag, + * the in_len parameter, and the SHA_FINISH flag, respectively. + * + * When in_len == 0 (no data to hash), the parameter, in, may be NULL. + * When the SHA_FINISH flag is not set, the parameter, md, may be NULL. + * + * Initialization may be standard or use a specified initialization vector, + * and is indicated by setting the SHA_INIT flag. + * Setting init = NULL specifies standard initialization. Otherwise, init + * points to the array of eight alternate initialization 32-bit words. + * + * The hash operation can be updated with any number of input bytes, including + * zero. + * + * The hash operation can be completed with normal padding or with zero + * padding as required for parts of DSA parameter generation, and is indicated + * by setting the SHA_FINISH flag. Using zero padding, indicated by setting + * the SHA_ZERO_PAD flag, never creates an extra input block because the + * bit count is not included in the hashed data. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +uint32_t +ntru_crypto_sha2( + NTRU_CRYPTO_HASH_ALGID algid, // in - hash algorithm ID + NTRU_CRYPTO_SHA2_CTX *c, // in/out - pointer to SHA-2 context + uint32_t const *init, // in - pointer to alternate + // initialization - may be NULL + uint8_t const *in, // in - pointer to input data - + // may be NULL if in_len == 0 + uint32_t in_len, // in - number of input data bytes + uint32_t flags, // in - INIT, FINISH, zero-pad flags + uint8_t *md) // out - address for message digest - + // may be NULL if not FINISH +{ + uint32_t in_blk[16]; // input block + uint32_t space; + uint8_t *d = NULL; + + /* check error conditions */ + + if (algid != NTRU_CRYPTO_HASH_ALGID_SHA256) + SHA_RET(SHA_BAD_PARAMETER) + + if (!c || (in_len && !in) || ((flags & SHA_FINISH) && !md)) + SHA_RET(SHA_BAD_PARAMETER) + + /* initialize context if requested */ + + if (flags & SHA_INIT) { + + /* init chaining state */ + + if (!init) { // standard initialization + + c->state[0] = H0_SHA256_INIT; // standard SHA-256 init + c->state[1] = H1_SHA256_INIT; + c->state[2] = H2_SHA256_INIT; + c->state[3] = H3_SHA256_INIT; + c->state[4] = H4_SHA256_INIT; + c->state[5] = H5_SHA256_INIT; + c->state[6] = H6_SHA256_INIT; + c->state[7] = H7_SHA256_INIT; + + } else { + c->state[0] = init[0]; // alternate initialization + c->state[1] = init[1]; + c->state[2] = init[2]; + c->state[3] = init[3]; + c->state[4] = init[4]; + c->state[5] = init[5]; + c->state[6] = init[6]; + c->state[7] = init[7]; + } + + /* init bit count and number of unhashed data bytes */ + + c->num_bits_hashed[0] = 0; + c->num_bits_hashed[1] = 0; + c->unhashed_len = 0; + } + + /* determine space left in unhashed data buffer */ + + if (c->unhashed_len > 63) + SHA_RET(SHA_FAIL) + + space = 64 - c->unhashed_len; + + /* process input if it exists */ + + if (in_len) { + + /* update count of bits hashed */ + + { + uint32_t bits0, bits1; + + bits0 = in_len << 3; + bits1 = in_len >> 29; + if ((c->num_bits_hashed[0] += bits0) < bits0) + bits1++; + if ((c->num_bits_hashed[1] += bits1) < bits1) { + memset((uint8_t *) c, 0, sizeof(NTRU_CRYPTO_SHA2_CTX)); + space = 0; + memset((char *) in_blk, 0, sizeof(in_blk)); + SHA_RET(SHA_OVERFLOW) + } + } + + /* process input bytes */ + + if (in_len < space) { + + /* input does not fill block buffer: + * add input to buffer + */ + + memcpy(c->unhashed + c->unhashed_len, in, in_len); + c->unhashed_len += in_len; + + } else { + uint32_t blks; + + /* input will fill block buffer: + * fill unhashed data buffer, + * convert to block buffer, + * and process block + */ + + in_len -= space; + for (d = c->unhashed + c->unhashed_len; space; space--) + *d++ = *in++; + ntru_crypto_msbyte_2_uint32(in_blk, (uint8_t const *) c->unhashed, + 16); + sha2_blk((uint32_t const *) in_blk, c->state); + + /* process any remaining full blocks */ + + for (blks = in_len >> 6; blks--; in += 64) { + ntru_crypto_msbyte_2_uint32(in_blk, in, 16); + sha2_blk((uint32_t const *) in_blk, c->state); + } + + /* put any remaining input in the unhashed data buffer */ + + in_len &= 0x3f; + memcpy(c->unhashed, in, in_len); + c->unhashed_len = in_len; + } + } + + /* complete message digest if requested */ + + if (flags & SHA_FINISH) { + space = 64 - c->unhashed_len; + + /* check padding type */ + + if (!(flags & SHA_ZERO_PAD)) { + + /* add 0x80 padding byte to the unhashed data buffer + * (there is always space since the buffer can't be full) + */ + + d = c->unhashed + c->unhashed_len; + *d++ = 0x80; + space--; + + /* check for space for bit count */ + + if (space < 8) { + + /* no space for count: + * fill remainder of unhashed data buffer with zeros, + * convert to input block, + * process block, + * fill all but 8 bytes of unhashed data buffer with zeros + */ + + memset(d, 0, space); + ntru_crypto_msbyte_2_uint32(in_blk, + (uint8_t const *) c->unhashed, 16); + sha2_blk((uint32_t const *) in_blk, c->state); + memset(c->unhashed, 0, 56); + + } else { + + /* fill unhashed data buffer with zeros, + * leaving space for bit count + */ + + for (space -= 8; space; space--) + *d++ = 0; + } + + /* convert partially filled unhashed data buffer to input block and + * add bit count to input block + */ + + ntru_crypto_msbyte_2_uint32(in_blk, (uint8_t const *) c->unhashed, + 14); + in_blk[14] = c->num_bits_hashed[1]; + in_blk[15] = c->num_bits_hashed[0]; + + } else { + + /* pad unhashed data buffer with zeros and no bit count and + * convert to input block + */ + + memset(c->unhashed + c->unhashed_len, 0, space); + ntru_crypto_msbyte_2_uint32(in_blk, (uint8_t const *) c->unhashed, + 16); + } + + /* process last block */ + + sha2_blk((uint32_t const *) in_blk, c->state); + + /* copy result to message digest buffer */ + + ntru_crypto_uint32_2_msbyte(md, c->state, 8); + + /* clear context and stack variables */ + + memset((uint8_t *) c, 0, sizeof(NTRU_CRYPTO_SHA2_CTX)); + space = 0; + memset((char *) in_blk, 0, sizeof(in_blk)); + } + + SHA_RET(SHA_OK) +} + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha2.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha2.h new file mode 100644 index 000000000..8b0de65b3 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha2.h @@ -0,0 +1,104 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_crypto_sha2.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_sha2.h + * + * Contents: Definitions and declarations for the SHA-256 implementation. + * + *****************************************************************************/ + +#ifndef NTRU_CRYPTO_SHA2_H +#define NTRU_CRYPTO_SHA2_H + + +#include "ntru_crypto_platform.h" +#include "ntru_crypto_sha.h" + + +/************************* + * structure definitions * + *************************/ + +/* SHA-256 context structure */ + +typedef struct { + uint32_t state[8]; /* chaining state */ + uint32_t num_bits_hashed[2]; /* number of bits hashed */ + uint8_t unhashed[64]; /* input data not yet hashed */ + uint32_t unhashed_len; /* number of bytes of unhashed input data */ +} NTRU_CRYPTO_SHA2_CTX; + + +/************************* + * function declarations * + *************************/ + +/* ntru_crypto_sha2() + * + * This routine provides all operations for a SHA-256 hash, + * and the use of SHA-256 for DSA signing and key generation. + * It may be used to initialize, update, or complete a message digest, + * or any combination of those actions, as determined by the SHA_INIT flag, + * the in_len parameter, and the SHA_FINISH flag, respectively. + * + * When in_len == 0 (no data to hash), the parameter, in, may be NULL. + * When the SHA_FINISH flag is not set, the parameter, md, may be NULL. + * + * Initialization may be standard or use a specified initialization vector, + * and is indicated by setting the SHA_INIT flag. + * Setting init = NULL specifies standard initialization. Otherwise, init + * points to the array of eight alternate initialization 32-bit words. + * + * The hash operation can be updated with any number of input bytes, including + * zero. + * + * The hash operation can be completed with normal padding or with zero + * padding as required for parts of DSA parameter generation, and is indicated + * by setting the SHA_FINISH flag. Using zero padding, indicated by setting + * the SHA_ZERO_PAD flag, never creates an extra input block because the + * bit count is not included in the hashed data. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +extern uint32_t +ntru_crypto_sha2( + NTRU_CRYPTO_HASH_ALGID algid, /* in - hash algorithm ID */ + NTRU_CRYPTO_SHA2_CTX *c, /* in/out - pointer to SHA-2 context */ + uint32_t const *init, /* in - pointer to alternate */ + /* initialization - may be NULL */ + uint8_t const *in, /* in - pointer to input data - + may be NULL if in_len == 0 */ + uint32_t in_len, /* in - number of input data bytes */ + uint32_t flags, /* in - INIT, FINISH, zero-pad flags */ + uint8_t *md); /* out - address for message digest - + may be NULL if not FINISH */ + + +#endif /* NTRU_CRYPTO_SHA2_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha256.c b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha256.c new file mode 100644 index 000000000..5eba06430 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha256.c @@ -0,0 +1,140 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_sha256.c is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + +/****************************************************************************** + * + * File: ntru_crypto_sha256.c + * + * Contents: Routines implementing the SHA-256 hash calculations. + * + *****************************************************************************/ + + +#include <stdlib.h> +#include "ntru_crypto_sha256.h" + + +/* ntru_crypto_sha256_init + * + * This routine performs standard initialization of the SHA-256 state. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + */ + +uint32_t +ntru_crypto_sha256_init( + NTRU_CRYPTO_SHA2_CTX *c) /* in/out - pointer to SHA-2 context */ +{ + return ntru_crypto_sha2(NTRU_CRYPTO_HASH_ALGID_SHA256, c, NULL, NULL, 0, + SHA_INIT, NULL); +} + + +/* ntru_crypto_sha256_update + * + * This routine processes input data and updates the SHA-256 hash calculation. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +uint32_t +ntru_crypto_sha256_update( + NTRU_CRYPTO_SHA2_CTX *c, /* in/out - pointer to SHA-2 context */ + uint8_t const *data, /* in - pointer to input data */ + uint32_t data_len) /* in - no. of bytes of input data */ +{ + return ntru_crypto_sha2(NTRU_CRYPTO_HASH_ALGID_SHA256, c, NULL, data, + data_len, SHA_DATA_ONLY, NULL); +} + + +/* ntru_crypto_sha256_final + * + * This routine completes the SHA-256 hash calculation and returns the + * message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +uint32_t +ntru_crypto_sha256_final( + NTRU_CRYPTO_SHA2_CTX *c, /* in/out - pointer to SHA-2 context */ + uint8_t *md) /* out - address for message digest */ +{ + return ntru_crypto_sha2(NTRU_CRYPTO_HASH_ALGID_SHA256, c, NULL, NULL, 0, + SHA_FINISH, md); +} + + +/* ntru_crypto_sha256_final_zero_pad + * + * This routine completes the SHA-256 hash calculation using zero padding + * and returns the message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +uint32_t +ntru_crypto_sha256_final_zero_pad( + NTRU_CRYPTO_SHA2_CTX *c, /* in/out - pointer to SHA-2 context */ + uint8_t *md) /* out - address for message digest */ +{ + return ntru_crypto_sha2(NTRU_CRYPTO_HASH_ALGID_SHA256, c, NULL, NULL, 0, + SHA_FINISH | SHA_ZERO_PAD, md); +} + + +/* ntru_crypto_sha256_digest + * + * This routine computes a SHA-256 message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +uint32_t +ntru_crypto_sha256_digest( + uint8_t const *data, // in - pointer to input data + uint32_t data_len, // in - number of bytes of input data + uint8_t *md) // out - address for message digest +{ + NTRU_CRYPTO_SHA2_CTX c; + + return ntru_crypto_sha2(NTRU_CRYPTO_HASH_ALGID_SHA256, &c, NULL, data, + data_len, SHA_INIT | SHA_FINISH, md); +} + diff --git a/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha256.h b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha256.h new file mode 100644 index 000000000..db4e85747 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_crypto/ntru_crypto_sha256.h @@ -0,0 +1,149 @@ +/****************************************************************************** + * NTRU Cryptography Reference Source Code + * Copyright (c) 2009-2013, by Security Innovation, Inc. All rights reserved. + * + * ntru_crypto_sha256.h is a component of ntru-crypto. + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + *****************************************************************************/ + + +/****************************************************************************** + * + * File: ntru_crypto_sha256.h + * + * Contents: Definitions and declarations for the SHA-256 implementation. + * + *****************************************************************************/ + +#ifndef CRYPTO_SHA256_H +#define CRYPTO_SHA256_H + + +#include "ntru_crypto_platform.h" +#include "ntru_crypto_sha2.h" + + +/****************************************** + * macros needed for generic hash objects * + ******************************************/ + +#define SHA_256_CTX_LEN sizeof(NTRU_CRYPTO_SHA2_CTX) + /* no. bytes in SHA-2 + ctx */ +#define SHA_256_BLK_LEN 64 /* 64 bytes in input + block */ +#define SHA_256_MD_LEN 32 /* 32 bytes in msg + digest */ +#define SHA_256_INIT_FN &ntru_crypto_sha256_init /* init function */ +#define SHA_256_UPDATE_FN &ntru_crypto_sha256_update /* update function */ +#define SHA_256_FINAL_FN &ntru_crypto_sha256_final /* final function */ +#define SHA_256_FINAL_ZERO_PAD_FN \ + &ntru_crypto_sha256_final_zero_pad + /* final function using + zero padding */ +#define SHA_256_DIGEST_FN &ntru_crypto_sha256_digest /* digest function */ + + +/************************* + * function declarations * + *************************/ + +/* ntru_crypto_sha256_init + * + * This routine performs standard initialization of the SHA-256 state. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + */ + +extern uint32_t +ntru_crypto_sha256_init( + NTRU_CRYPTO_SHA2_CTX *c); /* in/out - pointer to SHA-2 context */ + + +/* ntru_crypto_sha256_update + * + * This routine processes input data and updates the SHA-256 hash calculation. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +extern uint32_t +ntru_crypto_sha256_update( + NTRU_CRYPTO_SHA2_CTX *c, /* in/out - pointer to SHA-2 context */ + uint8_t const *data, /* in - pointer to input data */ + uint32_t data_len); /* in - no. of bytes of input data */ + + +/* ntru_crypto_sha256_final + * + * This routine completes the SHA-256 hash calculation and returns the + * message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +extern uint32_t +ntru_crypto_sha256_final( + NTRU_CRYPTO_SHA2_CTX *c, /* in/out - pointer to SHA-2 context */ + uint8_t *md); /* out - address for message digest */ + + +/* ntru_crypto_sha256_final_zero_pad + * + * This routine completes the SHA-256 hash calculation using zero padding + * and returns the message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +extern uint32_t +ntru_crypto_sha256_final_zero_pad( + NTRU_CRYPTO_SHA2_CTX *c, /* in/out - pointer to SHA-2 context */ + uint8_t *md); /* out - address for message digest */ + + +/* ntru_crypto_sha256_digest + * + * This routine computes a SHA-256 message digest. + * + * Returns SHA_OK on success. + * Returns SHA_FAIL with corrupted context. + * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed. + * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed. + */ + +extern uint32_t +ntru_crypto_sha256_digest( + uint8_t const *data, // in - pointer to input data + uint32_t data_len, // in - number of bytes of input data + uint8_t *md); // out - address for message digest + + +#endif /* CRYPTO_SHA256_H */ diff --git a/src/libstrongswan/plugins/ntru/ntru_ke.c b/src/libstrongswan/plugins/ntru/ntru_ke.c new file mode 100644 index 000000000..18f3b4cb4 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_ke.c @@ -0,0 +1,314 @@ +/* + * 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_plugin.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; + +/** + * 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 ID + */ + NTRU_ENCRYPT_PARAM_SET_ID param_set_id; + + /** + * 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; + + /** + * Deterministic Random Bit Generator + */ + DRBG_HANDLE 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) + { + 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 */ + 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; + 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 (ntru_crypto_drbg_generate(this->drbg, this->strength, + this->shared_secret.len, this->shared_secret.ptr) != DRBG_OK) + { + DBG1(DBG_LIB, "generation of shared secret failed"); + chunk_free(&this->shared_secret); + return; + } + + /* 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); + this->computed = TRUE; + + /* 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) +{ + if (ntru_crypto_drbg_uninstantiate(this->drbg) != DRBG_OK) + { + DBG1(DBG_LIB, "error uninstantiating DRBG"); + } + 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; + char personalization_str[] = "strongSwan NTRU-KE"; + NTRU_ENCRYPT_PARAM_SET_ID param_set_id; + DRBG_HANDLE drbg; + u_int32_t strength; + + /** + * We are selecting the X9.98 / IEEE 1363.1 parameter sets + * which balance speed and bandwidth + */ + switch (group) + { + case NTRU_112_BIT: + strength = 112; + /* param_set_id = NTRU_EES541EP1; */ + param_set_id = NTRU_EES401EP2; + break; + case NTRU_128_BIT: + strength = 128; + /* param_set_id = NTRU_EES613EP1; */ + param_set_id = NTRU_EES439EP1; + break; + case NTRU_192_BIT: + strength = 192; + /* param_set_id = NTRU_EES887EP1; */ + param_set_id = NTRU_EES593EP1; + break; + case NTRU_256_BIT: + strength = 256; + /* param_set_id = NTRU_EES1171EP1; */ + param_set_id = NTRU_EES743EP1; + break; + default: + return NULL; + } + + if (ntru_crypto_drbg_instantiate(strength, + personalization_str, strlen(personalization_str), + (ENTROPY_FN) &ntru_plugin_get_entropy, &drbg) != DRBG_OK) + { + DBG1(DBG_LIB, "error instantiating DRBG at %u bit security", strength); + return NULL; + } + else + { + DBG2(DBG_LIB, "instantiated DRBG at %u bit security", strength); + } + + 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_id = param_set_id, + .strength = strength, + .drbg = drbg, + ); + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/ntru/ntru_ke.h b/src/libstrongswan/plugins/ntru/ntru_ke.h new file mode 100644 index 000000000..b8bbf5e54 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_ke.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +/** + * @defgroup ntru_ke ntru_ke + * @{ @ingroup ntru_p + */ + +#ifndef NTRU_KE_H_ +#define NTRU_KE_H_ + +typedef struct ntru_ke_t ntru_ke_t; + +#include <library.h> + +/** + * Implementation of a key exchange algorithm using NTRU encryption + */ +struct ntru_ke_t { + + /** + * Implements diffie_hellman_t interface. + */ + diffie_hellman_t dh; +}; + +/** + * Creates a new ntru_ke_t object. + * + * @param group NTRU group number to use + * @param g not used + * @param p not used + * @return ntru_ke_t object, NULL if not supported + */ +ntru_ke_t *ntru_ke_create(diffie_hellman_group_t group, chunk_t g, chunk_t p); + +#endif /** NTRU_KE_H_ @}*/ + diff --git a/src/libstrongswan/plugins/ntru/ntru_plugin.c b/src/libstrongswan/plugins/ntru/ntru_plugin.c new file mode 100644 index 000000000..4ec6bc3df --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_plugin.c @@ -0,0 +1,147 @@ +/* + * 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_plugin.h" +#include "ntru_ke.h" + +#include <library.h> +#include <utils/debug.h> + +typedef struct private_ntru_plugin_t private_ntru_plugin_t; + +rng_t *rng; + +bool ntru_plugin_get_entropy(ENTROPY_CMD cmd, uint8_t *out) +{ + switch (cmd) + { + case INIT: + return TRUE; + case GET_NUM_BYTES_PER_BYTE_OF_ENTROPY: + /* Here we return the number of bytes needed from the entropy + * source to obtain 8 bits of entropy. Maximum is 8. + */ + if (!out) + { + return FALSE; + } + *out = 1; /* this is a perfectly random source */ + return TRUE; + case GET_BYTE_OF_ENTROPY: + if (!out) + { + return FALSE; + } + if (!rng || !rng->get_bytes(rng, 1, out)) + { + return FALSE; + } + DBG2(DBG_LIB, "read one byte of entropy"); + return TRUE; + default: + return FALSE; + } +} + +/** + * Create/Destroy True Random Generator + */ +static bool create_random(private_ntru_plugin_t *this, + plugin_feature_t *feature, bool reg, void *data) +{ + if (reg) + { + rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE); + if (!rng) + { + return FALSE; + } + } + else + { + rng->destroy(rng); + } + return TRUE; +} + +/** + * private data of ntru_plugin + */ +struct private_ntru_plugin_t { + + /** + * public functions + */ + ntru_plugin_t public; +}; + +METHOD(plugin_t, get_name, char*, + private_ntru_plugin_t *this) +{ + return "ntru"; +} + +METHOD(plugin_t, get_features, int, + private_ntru_plugin_t *this, plugin_feature_t *features[]) +{ + int count = 0; + + static plugin_feature_t f_ke[] = { + PLUGIN_REGISTER(DH, ntru_ke_create), + PLUGIN_PROVIDE(DH, NTRU_112_BIT), + PLUGIN_PROVIDE(DH, NTRU_128_BIT), + PLUGIN_PROVIDE(DH, NTRU_192_BIT), + PLUGIN_PROVIDE(DH, NTRU_256_BIT), + }; + static plugin_feature_t f_rng[] = { + PLUGIN_CALLBACK((plugin_feature_callback_t)create_random, NULL), + PLUGIN_PROVIDE(CUSTOM, "ntru-rng"), + PLUGIN_DEPENDS(RNG, RNG_TRUE), + }; + static plugin_feature_t f[countof(f_ke) + countof(f_rng)] = {}; + + plugin_features_add(f, f_ke, countof(f_ke), &count); + plugin_features_add(f, f_rng, countof(f_rng), &count); + + *features = f; + return count; +} + +METHOD(plugin_t, destroy, void, + private_ntru_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *ntru_plugin_create() +{ + private_ntru_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + ); + + + return &this->public.plugin; +} diff --git a/src/libstrongswan/plugins/ntru/ntru_plugin.h b/src/libstrongswan/plugins/ntru/ntru_plugin.h new file mode 100644 index 000000000..0fa701213 --- /dev/null +++ b/src/libstrongswan/plugins/ntru/ntru_plugin.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/** + * @defgroup ntru_p ntru + * @ingroup plugins + * + * @defgroup ntru_plugin ntru_plugin + * @{ @ingroup ntru_p + */ + +#ifndef NTRU_PLUGIN_H_ +#define NTRU_PLUGIN_H_ + +#include <plugins/plugin.h> + +#include "ntru_crypto/ntru_crypto_drbg.h" + +typedef struct ntru_plugin_t ntru_plugin_t; + +/** + * Plugin implementing NTRU-base key exchange + */ +struct ntru_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +/** + * Return true random bytes + * + * @param cmd command to be executed + * @param out output variable + * @result return code + */ +bool ntru_plugin_get_entropy(ENTROPY_CMD cmd, uint8_t *out); + +#endif /** NTRU_PLUGIN_H_ @}*/ diff --git a/testing/scripts/recipes/013_strongswan.mk b/testing/scripts/recipes/013_strongswan.mk index 85f80fe5b..646986a32 100644 --- a/testing/scripts/recipes/013_strongswan.mk +++ b/testing/scripts/recipes/013_strongswan.mk @@ -79,7 +79,8 @@ CONFIG_OPTS = \ --enable-cmd \ --enable-libipsec \ --enable-kernel-libipsec \ - --enable-tkm + --enable-tkm \ + --enable-ntru export ADA_PROJECT_PATH=/usr/local/ada/lib/gnat |