aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/relnotes/1_11_13.rst3
-rw-r--r--src/lib/pubkey/mceies/info.txt5
-rw-r--r--src/lib/pubkey/mceies/mceies.cpp106
-rw-r--r--src/lib/pubkey/mceies/mceies.h43
-rw-r--r--src/tests/test_mceliece.cpp156
5 files changed, 266 insertions, 47 deletions
diff --git a/doc/relnotes/1_11_13.rst b/doc/relnotes/1_11_13.rst
index b69073859..8a9ed5872 100644
--- a/doc/relnotes/1_11_13.rst
+++ b/doc/relnotes/1_11_13.rst
@@ -1,6 +1,9 @@
Version 1.11.13, Not Yet Released
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+* Add MCEIES, a McEliece-based integrated encryption system using
+ AES-256 in OCB mode for message encryption/authentication.
+
* Add DTLS-SRTP negotiation defined in RFC 5764
* Add SHA-512/256
diff --git a/src/lib/pubkey/mceies/info.txt b/src/lib/pubkey/mceies/info.txt
new file mode 100644
index 000000000..b4a25329e
--- /dev/null
+++ b/src/lib/pubkey/mceies/info.txt
@@ -0,0 +1,5 @@
+
+<requires>
+mce
+ocb
+</requires>
diff --git a/src/lib/pubkey/mceies/mceies.cpp b/src/lib/pubkey/mceies/mceies.cpp
new file mode 100644
index 000000000..0ceda2dda
--- /dev/null
+++ b/src/lib/pubkey/mceies/mceies.cpp
@@ -0,0 +1,106 @@
+/*
+* McEliece Integrated Encryption System
+* (C) 2014,2015 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/mceies.h>
+#include <botan/aead.h>
+#include <botan/mceliece.h>
+#include <botan/mce_kem.h>
+
+namespace Botan {
+
+namespace {
+
+secure_vector<byte> aead_key(const secure_vector<byte>& mk,
+ const AEAD_Mode& aead)
+ {
+ // Fold the key as required for the AEAD mode in use
+ if(aead.valid_keylength(mk.size()))
+ return mk;
+
+ secure_vector<byte> r(aead.key_spec().maximum_keylength());
+ for(size_t i = 0; i != mk.size(); ++i)
+ r[i % r.size()] ^= mk[i];
+ return r;
+ }
+
+}
+
+secure_vector<byte>
+mceies_encrypt(const McEliece_PublicKey& pubkey,
+ const secure_vector<byte>& pt,
+ byte ad[], size_t ad_len,
+ RandomNumberGenerator& rng)
+ {
+ McEliece_KEM_Encryptor kem_op(pubkey);
+
+ const std::pair<secure_vector<byte>,secure_vector<byte>> mce_ciphertext__key = kem_op.encrypt(rng);
+ const secure_vector<byte>& mce_ciphertext = mce_ciphertext__key.first;
+ const secure_vector<byte>& mce_key = mce_ciphertext__key.second;
+
+ const size_t mce_code_bytes = (pubkey.get_code_length() + 7) / 8;
+
+ BOTAN_ASSERT(mce_ciphertext.size() == mce_code_bytes, "Unexpected size");
+
+ std::unique_ptr<AEAD_Mode> aead(get_aead("AES-256/OCB", ENCRYPTION));
+ if(!aead)
+ throw std::runtime_error("mce_encrypt unable to create AEAD instance");
+
+ const size_t nonce_len = aead->default_nonce_length();
+
+ aead->set_key(aead_key(mce_key, *aead));
+ aead->set_associated_data(ad, ad_len);
+
+ const secure_vector<byte> nonce = rng.random_vec(nonce_len);
+
+ secure_vector<byte> msg(mce_ciphertext.size() + nonce.size() + pt.size());
+ copy_mem(&msg[0], &mce_ciphertext[0], mce_ciphertext.size());
+ copy_mem(&msg[mce_ciphertext.size()], &nonce[0], nonce.size());
+ copy_mem(&msg[mce_ciphertext.size() + nonce.size()], &pt[0], pt.size());
+
+ aead->start(nonce);
+ aead->finish(msg, mce_ciphertext.size() + nonce.size());
+ return msg;
+ }
+
+secure_vector<byte>
+mceies_decrypt(const McEliece_PrivateKey& privkey,
+ const secure_vector<byte>& ct,
+ byte ad[], size_t ad_len)
+ {
+ try
+ {
+ McEliece_KEM_Decryptor kem_op(privkey);
+
+ const size_t mce_code_bytes = (privkey.get_code_length() + 7) / 8;
+
+ std::unique_ptr<AEAD_Mode> aead(get_aead("AES-256/OCB", DECRYPTION));
+ if(!aead)
+ throw std::runtime_error("Unable to create AEAD instance");
+
+ const size_t nonce_len = aead->default_nonce_length();
+
+ if(ct.size() < mce_code_bytes + nonce_len + aead->tag_size())
+ throw std::runtime_error("Input message too small to be valid");
+
+ const secure_vector<byte> mce_key = kem_op.decrypt(&ct[0], mce_code_bytes);
+
+ aead->set_key(aead_key(mce_key, *aead));
+ aead->set_associated_data(ad, ad_len);
+
+ secure_vector<byte> pt(&ct[mce_code_bytes + nonce_len], &ct[ct.size()]);
+
+ aead->start(&ct[mce_code_bytes], nonce_len);
+ aead->finish(pt, 0);
+ return pt;
+ }
+ catch(std::exception& e)
+ {
+ throw std::runtime_error("mce_decrypt failed: " + std::string(e.what()));
+ }
+ }
+
+}
diff --git a/src/lib/pubkey/mceies/mceies.h b/src/lib/pubkey/mceies/mceies.h
new file mode 100644
index 000000000..7a03ca580
--- /dev/null
+++ b/src/lib/pubkey/mceies/mceies.h
@@ -0,0 +1,43 @@
+/*
+* McEliece Integrated Encryption System
+* (C) 2014,2015 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_MCEIES_H__
+#define BOTAN_MCEIES_H__
+
+#include <botan/secmem.h>
+#include <botan/rng.h>
+
+namespace Botan {
+
+class McEliece_PublicKey;
+class McEliece_PrivateKey;
+
+/**
+* McEliece Integrated Encryption System
+* Derive a shared key using MCE KEM and encrypt/authenticate the
+* plaintext and AD using AES-256 in OCB mode.
+*/
+secure_vector<byte>
+BOTAN_DLL mceies_encrypt(const McEliece_PublicKey& pubkey,
+ const secure_vector<byte>& pt,
+ byte ad[], size_t ad_len,
+ RandomNumberGenerator& rng);
+
+/**
+* McEliece Integrated Encryption System
+* Derive a shared key using MCE KEM and decrypt/authenticate the
+* ciphertext and AD using AES-256 in OCB mode.
+*/
+secure_vector<byte>
+BOTAN_DLL mceies_decrypt(const McEliece_PrivateKey& privkey,
+ const secure_vector<byte>& ct,
+ byte ad[], size_t ad_len);
+
+
+}
+
+#endif
diff --git a/src/tests/test_mceliece.cpp b/src/tests/test_mceliece.cpp
index 55dfd234d..69494f5fc 100644
--- a/src/tests/test_mceliece.cpp
+++ b/src/tests/test_mceliece.cpp
@@ -7,6 +7,8 @@
#include <botan/oids.h>
#include <botan/mceliece.h>
#include <botan/mce_kem.h>
+#include <botan/mceies.h>
+#include <botan/loadstor.h>
#include <botan/hex.h>
@@ -20,7 +22,7 @@ using namespace Botan;
namespace {
-const size_t MCE_RUNS = 10;
+const size_t MCE_RUNS = 5;
size_t test_mceliece_message_parts(RandomNumberGenerator& rng, size_t code_length, size_t error_weight)
{
@@ -51,37 +53,12 @@ size_t test_mceliece_message_parts(RandomNumberGenerator& rng, size_t code_lengt
return 0;
}
-size_t test_mceliece_kem(RandomNumberGenerator& rng, u32bit code_length, u32bit t)
+size_t test_mceliece_kem(const McEliece_PrivateKey& sk,
+ const McEliece_PublicKey& pk,
+ RandomNumberGenerator& rng)
{
size_t fails = 0;
- McEliece_PrivateKey sk1(rng, code_length, t);
- McEliece_PublicKey& pk1 = dynamic_cast<McEliece_PrivateKey&>(sk1);
-
- const std::vector<byte> pk_enc = pk1.x509_subject_public_key();
- const secure_vector<byte> sk_enc = sk1.pkcs8_private_key();
-
- McEliece_PublicKey pk(pk_enc);
- McEliece_PrivateKey sk(sk_enc);
-
- if(pk1 != pk)
- {
- std::cout << "decoded McEliece public key differs from original one" << std::endl;
- ++fails;
- }
-
- if(sk1 != sk)
- {
- std::cout << "decoded McEliece private key differs from original one" << std::endl;
- ++fails;
- }
-
- if(!sk.check_key(rng, false))
- {
- std::cout << "error calling check key on McEliece key" << std::endl;
- ++fails;
- }
-
McEliece_KEM_Encryptor pub_op(pk);
McEliece_KEM_Decryptor priv_op(sk);
@@ -126,23 +103,23 @@ size_t test_mceliece_kem(RandomNumberGenerator& rng, u32bit code_length, u32bit
return fails;
}
-size_t test_mceliece_raw(RandomNumberGenerator& rng, size_t code_length, size_t t)
+size_t test_mceliece_raw(const McEliece_PrivateKey& sk,
+ const McEliece_PublicKey& pk,
+ RandomNumberGenerator& rng)
{
- McEliece_PrivateKey sk(rng, code_length, t);
- McEliece_PublicKey* p_pk = dynamic_cast<McEliece_PublicKey*>(&sk);
-
+ const size_t code_length = pk.get_code_length();
McEliece_Private_Operation priv_op(sk);
- McEliece_Public_Operation pub_op(*p_pk, code_length );
+ McEliece_Public_Operation pub_op(pk, code_length);
size_t err_cnt = 0;
for(size_t i = 0; i != MCE_RUNS; i++)
{
- secure_vector<byte> plaintext((p_pk->get_message_word_bit_length()+7)/8);
+ secure_vector<byte> plaintext((pk.get_message_word_bit_length()+7)/8);
rng.randomize(&plaintext[0], plaintext.size() - 1);
- secure_vector<gf2m> err_pos = create_random_error_positions(p_pk->get_code_length(), p_pk->get_t(), rng);
+ secure_vector<gf2m> err_pos = create_random_error_positions(code_length, pk.get_t(), rng);
- mceliece_message_parts parts(err_pos, plaintext, p_pk->get_code_length());
+ mceliece_message_parts parts(err_pos, plaintext, code_length);
secure_vector<byte> message_and_error_input = parts.get_concat();
secure_vector<byte> ciphertext = pub_op.encrypt(&message_and_error_input[0], message_and_error_input.size(), rng);
//std::cout << "ciphertext byte length = " << ciphertext.size() << std::endl;
@@ -174,6 +151,54 @@ size_t test_mceliece_raw(RandomNumberGenerator& rng, size_t code_length, size_t
return err_cnt;
}
+size_t test_mceies(const McEliece_PrivateKey& sk,
+ const McEliece_PublicKey& pk,
+ RandomNumberGenerator& rng)
+ {
+
+ size_t fails = 0;
+
+ for(size_t i = 0; i != 5; ++i)
+ {
+ byte ad[8];
+ store_be(static_cast<u64bit>(i), ad);
+ const size_t ad_len = sizeof(ad);
+
+ const secure_vector<byte> pt = rng.random_vec(rng.next_byte());
+ const secure_vector<byte> ct = mceies_encrypt(pk, pt, ad, ad_len, rng);
+ const secure_vector<byte> dec = mceies_decrypt(sk, ct, ad, ad_len);
+
+ if(pt != dec)
+ {
+ std::cout << "MCEIES " << hex_encode(pt) << " != " << hex_encode(dec) << "\n";
+ ++fails;
+ }
+
+ secure_vector<byte> bad_ct = ct;
+ for(size_t j = 0; j != 2; ++j)
+ {
+ bad_ct = ct;
+
+ byte nonzero = 0;
+ while(nonzero == 0)
+ nonzero = rng.next_byte();
+
+ bad_ct[rng.next_byte() % bad_ct.size()] ^= nonzero;
+
+ try
+ {
+ mceies_decrypt(sk, bad_ct, ad, ad_len);
+ std::cout << "Successfully decrypted manipulated ciphertext!\n";
+ ++fails;
+ }
+ catch(std::exception& e) { /* Yay */ }
+
+ bad_ct[i] ^= nonzero;
+ }
+ }
+
+ return fails;
+ }
}
@@ -181,7 +206,7 @@ size_t test_mceliece()
{
auto& rng = test_rng();
- size_t err_cnt = 0;
+ size_t fails = 0;
size_t params__n__t_min_max[] = {
256, 5, 15,
512, 5, 33,
@@ -202,38 +227,75 @@ size_t test_mceliece()
try
{
- err_cnt += test_mceliece_message_parts(rng, code_length, t);
+ fails += test_mceliece_message_parts(rng, code_length, t);
}
catch(std::exception& e)
{
std::cout << e.what();
- err_cnt++;
+ fails++;
+ }
+
+ McEliece_PrivateKey sk1(rng, code_length, t);
+ const McEliece_PublicKey& pk1 = sk1;
+
+ const std::vector<byte> pk_enc = pk1.x509_subject_public_key();
+ const secure_vector<byte> sk_enc = sk1.pkcs8_private_key();
+
+ McEliece_PublicKey pk(pk_enc);
+ McEliece_PrivateKey sk(sk_enc);
+
+ if(pk1 != pk)
+ {
+ std::cout << "Decoded McEliece public key differs from original one" << std::endl;
+ ++fails;
+ }
+
+ if(sk1 != sk)
+ {
+ std::cout << "Decoded McEliece private key differs from original one" << std::endl;
+ ++fails;
+ }
+
+ if(!sk.check_key(rng, false))
+ {
+ std::cout << "Error calling check key on McEliece key" << std::endl;
+ ++fails;
}
try
{
- err_cnt += test_mceliece_raw(rng, code_length, t);
+ fails += test_mceliece_raw(sk, pk, rng);
}
catch(std::exception& e)
{
std::cout << e.what();
- err_cnt++;
+ fails++;
}
try
{
- err_cnt += test_mceliece_kem(rng, code_length, t);
+ fails += test_mceliece_kem(sk, pk, rng);
}
catch(std::exception& e)
{
std::cout << e.what();
- err_cnt++;
+ fails++;
}
- tests += 3;
+ try
+ {
+ fails += test_mceies(sk, pk, rng);
+ }
+ catch(std::exception& e)
+ {
+ std::cout << e.what();
+ fails++;
+ }
+
+ tests += 4;
}
}
- test_report("McEliece", tests, err_cnt);
- return err_cnt;
+ test_report("McEliece", tests, fails);
+ return fails;
}