/* * (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 #include #include #include #include #include #include #include #if defined(BOTAN_HAS_MCEIES) #include #endif #endif namespace Botan_Tests { namespace { #if defined(BOTAN_HAS_MCELIECE) std::vector hash_bytes(const byte b[], size_t len, const std::string& hash_fn = "SHA-256") { std::unique_ptr hash(Botan::HashFunction::create(hash_fn)); hash->update(b, len); std::vector r(hash->output_length()); hash->final(r.data()); return r; } template std::vector hash_bytes(const std::vector& v) { return hash_bytes(v.data(), v.size()); } class McEliece_Keygen_Encrypt_Test : public Text_Based_Test { public: McEliece_Keygen_Encrypt_Test() : Text_Based_Test("McEliece", "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 keygen_seed = get_req_bin(vars, "McElieceSeed"); const std::vector fprint_pub = get_req_bin(vars, "PublicKeyFingerprint"); const std::vector fprint_priv = get_req_bin(vars, "PrivateKeyFingerprint"); const std::vector encrypt_seed = get_req_bin(vars, "EncryptPRNGSeed"); const std::vector ciphertext = get_req_bin(vars, "Ciphertext"); const std::vector shared_key = get_req_bin(vars, "SharedKey"); const size_t keygen_n = get_req_sz(vars, "KeyN"); const size_t keygen_t = get_req_sz(vars, "KeyT"); Botan::HMAC_DRBG rng("HMAC(SHA-384)"); rng.add_entropy(keygen_seed.data(), keygen_seed.size()); Botan::McEliece_PrivateKey mce_priv(rng, keygen_n, keygen_t); Test::Result result("McEliece keygen"); result.test_eq("public key fingerprint", hash_bytes(mce_priv.x509_subject_public_key()), fprint_pub); result.test_eq("private key fingerprint", hash_bytes(mce_priv.pkcs8_private_key()), fprint_priv); rng.clear(); rng.add_entropy(encrypt_seed.data(), encrypt_seed.size()); Botan::McEliece_KEM_Encryptor kem_enc(mce_priv); Botan::McEliece_KEM_Decryptor kem_dec(mce_priv); const auto kem = kem_enc.encrypt(rng); result.test_eq("ciphertext", kem.first, ciphertext); result.test_eq("encrypt shared", kem.second, shared_key); result.test_eq("decrypt shared", kem_dec.decrypt_vec(kem.first), shared_key); return result; } }; BOTAN_REGISTER_TEST("mce_keygen", McEliece_Keygen_Encrypt_Test); class McEliece_Tests : public Test { public: std::string fingerprint(const Botan::Private_Key& key, const std::string& hash_algo = "SHA-256") { std::unique_ptr hash(Botan::HashFunction::create(hash_algo)); if(!hash) throw Test_Error("Hash " + hash_algo + " not available"); hash->update(key.pkcs8_private_key()); return Botan::hex_encode(hash->final()); } std::string fingerprint(const Botan::Public_Key& key, const std::string& hash_algo = "SHA-256") { std::unique_ptr hash(Botan::HashFunction::create(hash_algo)); if(!hash) throw Test_Error("Hash " + hash_algo + " not available"); hash->update(key.x509_subject_public_key()); return Botan::hex_encode(hash->final()); } std::vector run() override { size_t params__n__t_min_max[] = { 256, 5, 15, 512, 5, 33, 1024, 15, 35, 2048, 33, 50, 2960, 50, 56, 6624, 110, 115 }; std::vector results; for(size_t i = 0; i < sizeof(params__n__t_min_max)/sizeof(params__n__t_min_max[0]); i+=3) { const size_t code_length = params__n__t_min_max[i]; const size_t min_t = params__n__t_min_max[i+1]; const size_t max_t = params__n__t_min_max[i+2]; for(size_t t = min_t; t <= max_t; ++t) { Botan::McEliece_PrivateKey sk1(Test::rng(), code_length, t); const Botan::McEliece_PublicKey& pk1 = sk1; const std::vector pk_enc = pk1.x509_subject_public_key(); const Botan::secure_vector sk_enc = sk1.pkcs8_private_key(); Botan::McEliece_PublicKey pk(pk_enc); Botan::McEliece_PrivateKey sk(sk_enc); Test::Result result("McEliece keygen"); 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); results.push_back(result); results.push_back(test_kem(sk, pk)); #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"); Botan::McEliece_KEM_Encryptor pub_op(pk); Botan::McEliece_KEM_Decryptor priv_op(sk); for(size_t i = 0; i <= Test::soak_level(); i++) { const std::pair,Botan::secure_vector > ciphertext__sym_key = pub_op.encrypt(Test::rng()); const Botan::secure_vector& ciphertext = ciphertext__sym_key.first; const Botan::secure_vector& sym_key_encr = ciphertext__sym_key.second; const Botan::secure_vector sym_key_decr = priv_op.decrypt(ciphertext.data(), ciphertext.size()); result.test_eq("same key", sym_key_decr, sym_key_encr); } 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"); for(size_t i = 0; i <= Test::soak_level(); ++i) { uint8_t ad[8]; Botan::store_be(static_cast(i), ad); const size_t ad_len = sizeof(ad); const Botan::secure_vector pt = Test::rng().random_vec(Test::rng().next_byte()); const Botan::secure_vector ct = mceies_encrypt(pk, pt.data(), pt.size(), ad, ad_len, Test::rng()); const Botan::secure_vector dec = mceies_decrypt(sk, ct.data(), ct.size(), ad, ad_len); result.test_eq("decrypted ok", dec, pt); Botan::secure_vector 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& e) { result.test_note("AEAD rejected manipulated ciphertext"); } catch(std::exception& e) { result.test_failure("AEAD rejected manipulated ciphertext with unexpected error", e.what()); } } } return result; } #endif }; BOTAN_REGISTER_TEST("mceliece", McEliece_Tests); #endif } }