aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/relnotes/1_11_10.rst7
-rw-r--r--src/lib/pubkey/mce/info.txt1
-rw-r--r--src/lib/pubkey/mce/mce_overbeck_cca2.cpp182
-rw-r--r--src/lib/pubkey/mce/mce_overbeck_cca2.h46
-rw-r--r--src/tests/test_mceliece.cpp124
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;
}
}