diff options
-rw-r--r-- | doc/relnotes/1_11_10.rst | 7 | ||||
-rw-r--r-- | src/lib/pubkey/mce/info.txt | 1 | ||||
-rw-r--r-- | src/lib/pubkey/mce/mce_overbeck_cca2.cpp | 182 | ||||
-rw-r--r-- | src/lib/pubkey/mce/mce_overbeck_cca2.h | 46 | ||||
-rw-r--r-- | src/tests/test_mceliece.cpp | 124 |
5 files changed, 30 insertions, 330 deletions
diff --git a/doc/relnotes/1_11_10.rst b/doc/relnotes/1_11_10.rst index 9fbf8e369..cef271e2a 100644 --- a/doc/relnotes/1_11_10.rst +++ b/doc/relnotes/1_11_10.rst @@ -4,8 +4,11 @@ Version 1.11.10, Not Yet Released * An implementation of McEliece code-based public key encryption based on INRIA's HyMES was contributed by cryptosource GmbH. The original version is LGPL but cryptosource has secured permission to release - an adaptation under a BSD license. A CCA2-secure message encoding - scheme is also included. + an adaptation under a BSD license. A CCA2-secure KEM scheme is also + included. + + The implementations is further described in + `http://www.cryptosource.de/docs/mceliece_in_botan.pdf`_. * Add support for TLS fallback signaling (draft-ietf-tls-downgrade-scsv-00). Clients will send a fallback SCSV if the version passed to the Client diff --git a/src/lib/pubkey/mce/info.txt b/src/lib/pubkey/mce/info.txt index bc4249422..c06e23b8e 100644 --- a/src/lib/pubkey/mce/info.txt +++ b/src/lib/pubkey/mce/info.txt @@ -5,7 +5,6 @@ code_based_util.h gf2m_rootfind_dcmp.h gf2m_small_m.h goppa_code.h -mce_overbeck_cca2.h mce_kem.h mceliece.h mceliece_key.h diff --git a/src/lib/pubkey/mce/mce_overbeck_cca2.cpp b/src/lib/pubkey/mce/mce_overbeck_cca2.cpp deleted file mode 100644 index 7edd2e2a3..000000000 --- a/src/lib/pubkey/mce/mce_overbeck_cca2.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/** - * (C) 2014 cryptosource GmbH - * (C) 2014 Falko Strenzke [email protected] - * - * Distributed under the terms of the Botan license - * - */ - -#include <botan/mce_overbeck_cca2.h> -#include <botan/sha2_64.h> -#include <botan/mceliece.h> -#include <botan/internal/xor_buf.h> - -namespace Botan -{ - - McEliece_Overbeck_CCA2_Public_Operation::McEliece_Overbeck_CCA2_Public_Operation(const McEliece_PublicKey& public_key) - :m_raw_pub_op(public_key, public_key.get_code_length()) - { - if(public_key.get_message_word_bit_length() < 1024) - { - // k is smaller than the minimum required length for Overbeck conversion - // using SHA-512 - throw Invalid_Argument("McEliece parameters are too small to support the Overbeck conversion with SHA-512, the dimension of the code must be at least 1024"); - } - } - - - secure_vector<byte> McEliece_Overbeck_CCA2_Public_Operation::encrypt(const byte msg[], size_t msg_len, RandomNumberGenerator& rng) - { - const u32bit k = m_raw_pub_op.max_input_bits(); - const u32bit l = 512; // output length of SHA-512 - const u32bit l_bytes = l/8; - const u32bit u1_bit_length = k - l; - const u32bit u1_length_ceil = (u1_bit_length + 7)/8; // valid lengths ensured already during construction - const McEliece_PublicKey & key = m_raw_pub_op.get_key(); - const u32bit n = key.get_code_length(); - const u32bit n_bytes_ceil = (n+7)/8; - const u32bit k_bytes_ceil = (k+7)/8; - - if(msg_len != l_bytes) - { - throw Invalid_Argument("McEliece/Overbeck message lengtth must be 64 bytes"); - } - secure_vector<byte> u1(u1_length_ceil); - rng.randomize(&u1[0], u1.size()); - // unused bits of final byte of u1 must be set to zero - u32bit used = u1_bit_length % 8; - if(used) - { - byte mask = (1 << used) - 1; - - u1[u1.size() - 1] &= mask; - } - - secure_vector<byte> u2(l_bytes); - rng.randomize(&u2[0], u2.size()); - - // compute the hash of m||u1: - SHA_512 hash; - - hash.update(msg, msg_len); - hash.update(u2); - secure_vector<byte> hash_m_u2 = hash.final(); - - //std::cout << "enc hash_m_u2 " << hex_encode(hash_m_u2) << "\n"; - - secure_vector<byte> mce_msg(k_bytes_ceil); - std::memcpy(&mce_msg[0], &hash_m_u2[0], hash_m_u2.size()); - std::memcpy(&mce_msg[hash_m_u2.size()], &u1[0], u1.size()); - -// create the error vector - secure_vector<gf2m> err_pos = create_random_error_positions(n, key.get_t(), rng); - - secure_vector<byte> err_vec = mceliece_message_parts::error_vector_from_error_positions(&err_pos[0], err_pos.size(), n); - - mceliece_message_parts parts(err_pos, mce_msg, n); - - secure_vector<byte> message_and_error_input = parts.get_concat(); - - //std::cout << "enc msg_and_error " << hex_encode(message_and_error_input) << "\n"; - //std::cout << "enc h(msg_and_error) " << hex_encode(hash.process(message_and_error_input)) << "\n"; - - secure_vector<byte> mce_ct = m_raw_pub_op.encrypt(&message_and_error_input[0], message_and_error_input.size(), rng); - - secure_vector<byte> result(n_bytes_ceil + 2*l_bytes); - - BOTAN_ASSERT(mce_ct.size() == (key.get_code_length()+7)/8, "Expected size"); - - std::memcpy(&result[0], &mce_ct[0], mce_ct.size()); - - - // z2 part of the ciphertext - SHA_512 hash2; - secure_vector<byte> hash_u1 = hash2.process(u1); - - //std::cout << "enc hash_u1 " << hex_encode(hash_u1) << "\n"; - - xor_buf(&result[mce_ct.size()], &hash_u1[0], &msg[0], l_bytes); - - // 3rd part of the overbeck ct - SHA_512 hash3; - secure_vector<byte> err_hash = hash3.process(err_vec); - - //std::cout << "enc err_hash " << hex_encode(err_hash) << "\n"; - - const u32bit z3_offs = n_bytes_ceil + l_bytes; - xor_buf(&result[z3_offs], &u2[0], &err_hash[0], l_bytes); - - return result; - } - - McEliece_Overbeck_CCA2_Private_Operation::McEliece_Overbeck_CCA2_Private_Operation(const McEliece_PrivateKey& mce_key) - :m_raw_priv_op(mce_key) - { - if(mce_key.get_dimension() < 1024) - { - // k is smaller than the minimum required length for Overbeck conversion - // using SHA-512 - throw Invalid_Argument("McEliece parameters are too small to support the Overbeck conversion with SHA-512, the dimension of the code must be at least 1024"); - } - } - - secure_vector<byte> McEliece_Overbeck_CCA2_Private_Operation::decrypt(const byte msg[], size_t msg_len) - { - - const McEliece_PrivateKey& key = m_raw_priv_op.get_key(); - const u32bit k = key.get_dimension(); - const u32bit l = 512; // output length of SHA-512 - const u32bit l_bytes = l/8; - const u32bit r_length_ceil = (k - l + 7)/8; // valid lengths ensured already during construction - const u32bit n = key.get_code_length(); - const u32bit n_bytes_ceil = (n+7)/8; - - const u32bit z2_offs = n_bytes_ceil; - const u32bit z3_offs = n_bytes_ceil + l_bytes; - - if(msg_len != (max_input_bits()+7)/8) - { - throw Invalid_Argument("wrong length of McEliece/Overbeck ciphertext"); - } - secure_vector<byte> mce_pt_and_err = m_raw_priv_op.decrypt(msg, n_bytes_ceil); - - SHA_512 hash; - //std::cout << "dec msg_and_error " << hex_encode(mce_pt_and_err) << "\n"; - //std::cout << "dec h(msg_and_error) " << hex_encode(hash.process(mce_pt_and_err)) << "\n"; - - mceliece_message_parts parts(&mce_pt_and_err[0], mce_pt_and_err.size(), n); - - secure_vector<byte> mce_pt = parts.get_message_word(); - secure_vector<byte> err_vec = parts.get_error_vector(); - - secure_vector<byte> h(l_bytes); - std::memcpy(&h[0], &mce_pt[0], l_bytes); - secure_vector<byte> r(r_length_ceil); - std::memcpy(&r[0], &mce_pt[l_bytes], r.size()); - - secure_vector<byte> hash_r = hash.process(r); - //std::cout << "dec hash_r " << hex_encode(hash_r) << "\n"; - - secure_vector<byte> m(l_bytes); - xor_buf(&m[0], &msg[z2_offs], &hash_r[0], l_bytes); - - SHA_512 hash2; - secure_vector<byte> hash_e = hash2.process(err_vec); - //std::cout << "dec hash_e " << hex_encode(hash_e) << "\n"; - xor_buf(&hash_e[0], &msg[z3_offs], l_bytes); - // hash_e now is H(e) ^ z3 = u2 - - SHA_512 hash3; - hash3.update(m); - hash3.update(hash_e); - secure_vector<byte> h_cmp = hash3.final(); - - //std::cout << "dec hash_cmp " << hex_encode(h_cmp) << "\n"; - if(h_cmp != h) - throw Integrity_Failure("McEliece/Overbeck CCA2 check failed"); - return m; - - } - -} diff --git a/src/lib/pubkey/mce/mce_overbeck_cca2.h b/src/lib/pubkey/mce/mce_overbeck_cca2.h deleted file mode 100644 index 1b9439753..000000000 --- a/src/lib/pubkey/mce/mce_overbeck_cca2.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - * (C) 2014 cryptosource GmbH - * (C) 2014 Falko Strenzke [email protected] - * - * Distributed under the terms of the Botan license - * - */ - -#ifndef __mce_overbeck_cca2__H_ -#define __mce_overbeck_cca2__H_ - -#include <botan/pk_ops.h> -#include <botan/mceliece_key.h> -#include <botan/mceliece.h> -#include <botan/types.h> -#include <botan/secmem.h> - -namespace Botan -{ -class BOTAN_DLL McEliece_Overbeck_CCA2_Public_Operation : public PK_Ops::Encryption -{ - public: - McEliece_Overbeck_CCA2_Public_Operation(const McEliece_PublicKey& public_key); - - size_t max_input_bits() const { return 512; }; - secure_vector<byte> encrypt(const byte msg[], size_t msg_len, RandomNumberGenerator&); - - private: - McEliece_Public_Operation m_raw_pub_op; -}; - -class BOTAN_DLL McEliece_Overbeck_CCA2_Private_Operation : public PK_Ops::Decryption - { - public: - McEliece_Overbeck_CCA2_Private_Operation(const McEliece_PrivateKey& mce_key); - - size_t max_input_bits() const { return (m_raw_priv_op.max_input_bits()+7)/8*8 + 2*512; }; - - -secure_vector<byte> decrypt(const byte msg[], size_t msg_len); - private: - McEliece_Private_Operation m_raw_priv_op; - }; -} - -#endif /* h-guard */ diff --git a/src/tests/test_mceliece.cpp b/src/tests/test_mceliece.cpp index dddf93b94..cb14af3f1 100644 --- a/src/tests/test_mceliece.cpp +++ b/src/tests/test_mceliece.cpp @@ -6,13 +6,11 @@ #include <botan/x509cert.h> #include <botan/oids.h> #include <botan/mceliece.h> +#include <botan/mce_kem.h> #include <botan/auto_rng.h> #include <botan/hex.h> -#include <iostream> - -#include <botan/mce_overbeck_cca2.h> -#include <botan/mce_kem.h> +#include <iostream> #include <memory> using namespace Botan; @@ -53,89 +51,6 @@ size_t test_mceliece_message_parts(RandomNumberGenerator& rng, size_t code_lengt return 0; } -size_t test_mceliece_overbeck(RandomNumberGenerator& rng, size_t code_length, size_t t ) - { - McEliece_PrivateKey sk1(rng, code_length, t); - McEliece_PublicKey pk1(*dynamic_cast<McEliece_PublicKey*>(&sk1)); - - McEliece_PublicKey pk(pk1.x509_subject_public_key()); - McEliece_PrivateKey sk(sk1.pkcs8_private_key()); - - if(sk1 != sk) - { - std::cout << "decoded McEliece private key differs from original one" << std::endl; - return 1; - } - - if(!sk.check_key(rng, false)) - { - std::cout << "error calling check key on McEliece key" << std::endl; - return 1; - } - - if(pk1 != pk) - { - std::cout << "decoded McEliece public key differs from original one" << std::endl; - return 1; - } - - McEliece_Overbeck_CCA2_Private_Operation priv_op(sk); - McEliece_Overbeck_CCA2_Public_Operation pub_op(pk ); - size_t err_cnt = 0; - - for(size_t i = 0; i < 10; i++) - { - try - { - secure_vector<byte> plaintext(64); - rng.randomize(&plaintext[0], plaintext.size() - 1); - - secure_vector<byte> ciphertext = pub_op.encrypt(&plaintext[0], plaintext.size(), rng); - secure_vector<byte> decrypted = priv_op.decrypt(&ciphertext[0], ciphertext.size() ); - - if(plaintext != decrypted) - { - std::cout << "ciphertext = " << hex_encode(ciphertext) << std::endl; - std::cout << "original plaintext = " << hex_encode(plaintext) << std::endl; - std::cout << "decrypted plaintext = " << hex_encode(decrypted) << std::endl; - - err_cnt++; - std::cout << "mce overbeck test " << i << " failed, error during encryption/decryption" << std::endl; - return err_cnt; - } - -#if 0 - // takes a long time: - for(size_t j = 0; j < code_length; j++) - { - // flip the j-th bit in the ciphertext - secure_vector<byte> wrong_ct(ciphertext); - size_t byte_pos = j/8; - size_t bit_pos = j % 8; - wrong_ct[byte_pos] ^= 1 << bit_pos; - try - { - secure_vector<byte> decrypted = priv_op.decrypt(&wrong_ct[0], wrong_ct.size()); - } - catch(const Integrity_Failure) - { - continue; - } - std::cout << "manipulation in ciphertext not detected" << std::endl; - err_cnt++; - } -#endif - } - catch(std::exception& e) - { - std::cout << e.what() << "\n"; - ++err_cnt; - } - } - - return err_cnt; - } - size_t test_mceliece_kem(RandomNumberGenerator& rng, u32bit code_length, u32bit t) { size_t fails = 0; @@ -183,6 +98,29 @@ size_t test_mceliece_kem(RandomNumberGenerator& rng, u32bit code_length, u32bit std::cout << "mce KEM test failed, error during encryption/decryption" << std::endl; ++fails; } + +#if 0 + // takes a long time: + for(size_t j = 0; j < code_length; j++) + { + // flip the j-th bit in the ciphertext + secure_vector<byte> wrong_ct(ciphertext); + size_t byte_pos = j/8; + size_t bit_pos = j % 8; + wrong_ct[byte_pos] ^= 1 << bit_pos; + try + { + secure_vector<byte> decrypted = priv_op.decrypt(&wrong_ct[0], wrong_ct.size()); + } + catch(const Integrity_Failure) + { + continue; + } + std::cout << "manipulation in ciphertext not detected" << std::endl; + err_cnt++; + } +#endif + } return fails; @@ -292,18 +230,6 @@ size_t test_mceliece() err_cnt++; } - try - { - // otherwise conversion not applicable because k=dimension would be too small - if(code_length >= 2048) - err_cnt += test_mceliece_overbeck(rng, code_length, t); - } - catch(std::exception& e) - { - std::cout << e.what(); - err_cnt++; - } - tests += 3; } } |