diff options
-rw-r--r-- | doc/relnotes/1_11_13.rst | 3 | ||||
-rw-r--r-- | src/lib/pubkey/mceies/info.txt | 5 | ||||
-rw-r--r-- | src/lib/pubkey/mceies/mceies.cpp | 106 | ||||
-rw-r--r-- | src/lib/pubkey/mceies/mceies.h | 43 | ||||
-rw-r--r-- | src/tests/test_mceliece.cpp | 156 |
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; } |