Z-Botan-0.1.1.0: third_party/botan/src/tests/test_mceliece.cpp
/*
* (C) 2014 cryptosource GmbH
* (C) 2014 Falko Strenzke fstrenzke@cryptosource.de
* (C) 2014,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include "tests.h"
#if defined(BOTAN_HAS_MCELIECE)
#include <botan/mceliece.h>
#include <botan/pubkey.h>
#include <botan/loadstor.h>
#include <botan/hash.h>
#include <botan/hex.h>
#if defined(BOTAN_HAS_HMAC_DRBG)
#include <botan/hmac_drbg.h>
#endif
#if defined(BOTAN_HAS_MCEIES)
#include <botan/mceies.h>
#endif
#endif
namespace Botan_Tests {
namespace {
#if defined(BOTAN_HAS_MCELIECE)
#if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_32) && defined(BOTAN_HAS_SHA2_64)
class McEliece_Keygen_Encrypt_Test final : public Text_Based_Test
{
public:
McEliece_Keygen_Encrypt_Test()
: Text_Based_Test("pubkey/mce.vec",
"McElieceSeed,KeyN,KeyT,PublicKeyFingerprint,PrivateKeyFingerprint,"
"EncryptPRNGSeed,SharedKey,Ciphertext",
"") {}
Test::Result run_one_test(const std::string&, const VarMap& vars) override
{
const std::vector<uint8_t> keygen_seed = vars.get_req_bin("McElieceSeed");
const std::vector<uint8_t> fprint_pub = vars.get_req_bin("PublicKeyFingerprint");
const std::vector<uint8_t> fprint_priv = vars.get_req_bin("PrivateKeyFingerprint");
const std::vector<uint8_t> encrypt_seed = vars.get_req_bin("EncryptPRNGSeed");
const std::vector<uint8_t> ciphertext = vars.get_req_bin("Ciphertext");
const std::vector<uint8_t> shared_key = vars.get_req_bin("SharedKey");
const size_t keygen_n = vars.get_req_sz("KeyN");
const size_t keygen_t = vars.get_req_sz("KeyT");
Test::Result result("McEliece keygen");
result.start_timer();
if(Test::run_long_tests() == false && keygen_n > 3072)
{
result.test_note("Skipping because long");
return result;
}
Botan::HMAC_DRBG rng("SHA-384");
rng.initialize_with(keygen_seed.data(), keygen_seed.size());
Botan::McEliece_PrivateKey mce_priv(rng, keygen_n, keygen_t);
result.test_eq("public key fingerprint", hash_bytes(mce_priv.public_key_bits()), fprint_pub);
result.test_eq("private key fingerprint", hash_bytes(mce_priv.private_key_bits()), fprint_priv);
rng.clear();
rng.initialize_with(encrypt_seed.data(), encrypt_seed.size());
try
{
Botan::PK_KEM_Encryptor kem_enc(mce_priv, Test::rng(), "KDF1(SHA-512)");
Botan::PK_KEM_Decryptor kem_dec(mce_priv, Test::rng(), "KDF1(SHA-512)");
Botan::secure_vector<uint8_t> encap_key, prod_shared_key;
kem_enc.encrypt(encap_key, prod_shared_key, 64, rng);
Botan::secure_vector<uint8_t> dec_shared_key = kem_dec.decrypt(encap_key.data(), encap_key.size(), 64);
result.test_eq("ciphertext", encap_key, ciphertext);
result.test_eq("encrypt shared", prod_shared_key, shared_key);
result.test_eq("decrypt shared", dec_shared_key, shared_key);
}
catch(Botan::Lookup_Error&)
{
}
result.end_timer();
return result;
}
private:
std::vector<uint8_t> hash_bytes(const uint8_t b[], size_t len, const std::string& hash_fn = "SHA-256")
{
std::unique_ptr<Botan::HashFunction> hash(Botan::HashFunction::create(hash_fn));
hash->update(b, len);
std::vector<uint8_t> r(hash->output_length());
hash->final(r.data());
return r;
}
template<typename A>
std::vector<uint8_t> hash_bytes(const std::vector<uint8_t, A>& v)
{
return hash_bytes(v.data(), v.size());
}
};
BOTAN_REGISTER_TEST("mce_keygen", McEliece_Keygen_Encrypt_Test);
#endif
#if defined(BOTAN_HAS_SHA2_32)
class McEliece_Tests final : public Test
{
public:
std::string fingerprint(const Botan::Private_Key& key, const std::string& hash_algo = "SHA-256")
{
std::unique_ptr<Botan::HashFunction> hash(Botan::HashFunction::create(hash_algo));
if(!hash)
{
throw Test_Error("Hash " + hash_algo + " not available");
}
hash->update(key.private_key_bits());
return Botan::hex_encode(hash->final());
}
std::string fingerprint(const Botan::Public_Key& key, const std::string& hash_algo = "SHA-256")
{
std::unique_ptr<Botan::HashFunction> hash(Botan::HashFunction::create(hash_algo));
if(!hash)
{
throw Test_Error("Hash " + hash_algo + " not available");
}
hash->update(key.public_key_bits());
return Botan::hex_encode(hash->final());
}
std::vector<Test::Result> run() override
{
struct keygen_params { size_t code_length, t_min, t_max; };
const keygen_params param_sets[] =
{
{ 256, 5, 15 },
{ 512, 5, 33 },
{ 1024, 15, 35 },
{ 2048, 33, 50 },
{ 6624, 110, 115 }
};
std::vector<Test::Result> results;
for(size_t i = 0; i < sizeof(param_sets) / sizeof(param_sets[0]); ++i)
{
if(Test::run_long_tests() == false && param_sets[i].code_length >= 2048)
{
continue;
}
for(size_t t = param_sets[i].t_min; t <= param_sets[i].t_max; ++t)
{
Test::Result result("McEliece keygen");
result.start_timer();
Botan::McEliece_PrivateKey sk1(Test::rng(), param_sets[i].code_length, t);
const Botan::McEliece_PublicKey& pk1 = sk1;
const std::vector<uint8_t> pk_enc = pk1.public_key_bits();
const Botan::secure_vector<uint8_t> sk_enc = sk1.private_key_bits();
Botan::McEliece_PublicKey pk(pk_enc);
Botan::McEliece_PrivateKey sk(sk_enc);
result.test_eq("decoded public key equals original", fingerprint(pk1), fingerprint(pk));
result.test_eq("decoded private key equals original", fingerprint(sk1), fingerprint(sk));
result.test_eq("key validation passes", sk.check_key(Test::rng(), false), true);
result.end_timer();
result.end_timer();
results.push_back(result);
#if defined(BOTAN_HAS_KDF2)
results.push_back(test_kem(sk, pk));
#endif
#if defined(BOTAN_HAS_MCEIES)
results.push_back(test_mceies(sk, pk));
#endif
}
}
return results;
}
private:
Test::Result test_kem(const Botan::McEliece_PrivateKey& sk,
const Botan::McEliece_PublicKey& pk)
{
Test::Result result("McEliece KEM");
result.start_timer();
Botan::PK_KEM_Encryptor enc_op(pk, Test::rng(), "KDF2(SHA-256)");
Botan::PK_KEM_Decryptor dec_op(sk, Test::rng(), "KDF2(SHA-256)");
const size_t trials = (Test::run_long_tests() ? 30 : 10);
for(size_t i = 0; i < trials; i++)
{
Botan::secure_vector<uint8_t> salt = Test::rng().random_vec(i);
Botan::secure_vector<uint8_t> encap_key, shared_key;
enc_op.encrypt(encap_key, shared_key, 64, Test::rng(), salt);
Botan::secure_vector<uint8_t> shared_key2 = dec_op.decrypt(encap_key, 64, salt);
result.test_eq("same key", shared_key, shared_key2);
}
result.end_timer();
return result;
}
#if defined(BOTAN_HAS_MCEIES)
Test::Result test_mceies(const Botan::McEliece_PrivateKey& sk,
const Botan::McEliece_PublicKey& pk)
{
Test::Result result("McEliece IES");
result.start_timer();
for(size_t i = 0; i <= 10; ++i)
{
uint8_t ad[8];
Botan::store_be(static_cast<uint64_t>(i), ad);
const size_t ad_len = sizeof(ad);
const Botan::secure_vector<uint8_t> pt = Test::rng().random_vec(Test::rng().next_byte());
const Botan::secure_vector<uint8_t> ct = mceies_encrypt(pk, pt.data(), pt.size(), ad, ad_len, Test::rng());
const Botan::secure_vector<uint8_t> dec = mceies_decrypt(sk, ct.data(), ct.size(), ad, ad_len);
result.test_eq("decrypted ok", dec, pt);
Botan::secure_vector<uint8_t> bad_ct = ct;
for(size_t j = 0; j != 3; ++j)
{
bad_ct = mutate_vec(ct, true);
try
{
mceies_decrypt(sk, bad_ct.data(), bad_ct.size(), ad, ad_len);
result.test_failure("AEAD decrypted manipulated ciphertext");
result.test_note("Manipulated text was " + Botan::hex_encode(bad_ct));
}
catch(Botan::Integrity_Failure&)
{
result.test_note("AEAD rejected manipulated ciphertext");
}
catch(std::exception& e)
{
result.test_failure("AEAD rejected manipulated ciphertext with unexpected error", e.what());
}
}
}
result.end_timer();
return result;
}
#endif
};
BOTAN_REGISTER_TEST("mceliece", McEliece_Tests);
#endif
#endif
}
}