Test::Result run_one_test(const std::string& type, const VarMap& vars) override { const std::vector<uint8_t> dn_bits1 = get_req_bin(vars, "DN1"); const std::vector<uint8_t> dn_bits2 = get_req_bin(vars, "DN2"); const bool dn_same = (type == "Equal"); Test::Result result("X509_DN comparisons"); try { Botan::X509_DN dn1; Botan::BER_Decoder bd1(dn_bits1); dn1.decode_from(bd1); Botan::X509_DN dn2; Botan::BER_Decoder bd2(dn_bits2); dn2.decode_from(bd2); const bool compared_same = (dn1 == dn2); result.test_eq("Comparison matches expected", dn_same, compared_same); } catch(Botan::Exception& e) { result.test_failure(e.what()); } return result; }
Test::Result PK_Signature_Verification_Test::run_one_test(const std::string&, const VarMap& vars) { const std::vector<uint8_t> message = get_req_bin(vars, "Msg"); const std::vector<uint8_t> signature = get_req_bin(vars, "Signature"); const std::string padding = get_opt_str(vars, "Padding", default_padding(vars)); std::unique_ptr<Botan::Public_Key> pubkey = load_public_key(vars); Test::Result result(algo_name() + "/" + padding + " signature verification"); for(auto&& verify_provider : possible_pk_providers()) { std::unique_ptr<Botan::PK_Verifier> verifier; try { verifier.reset(new Botan::PK_Verifier(*pubkey, padding, Botan::IEEE_1363, verify_provider)); result.test_eq("correct signature valid", verifier->verify_message(message, signature), true); check_invalid_signatures(result, *verifier, message, signature); } catch(Botan::Lookup_Error&) { result.test_note("Skipping verifying with " + verify_provider); } } return result; }
Test::Result PK_Signature_Generation_Test::run_one_test(const std::string&, const VarMap& vars) { const std::vector<uint8_t> message = get_req_bin(vars, "Msg"); const std::vector<uint8_t> signature = get_req_bin(vars, "Signature"); const std::string padding = get_opt_str(vars, "Padding", default_padding(vars)); std::unique_ptr<Botan::RandomNumberGenerator> rng; if(vars.count("Nonce")) { rng.reset(new Fixed_Output_RNG(get_req_bin(vars, "Nonce"))); } Test::Result result(algo_name() + "/" + padding + " signature generation"); std::unique_ptr<Botan::Private_Key> privkey = load_private_key(vars); std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(Botan::X509::BER_encode(*privkey))); Botan::PK_Signer signer(*privkey, padding); Botan::PK_Verifier verifier(*pubkey, padding); const std::vector<uint8_t> generated_signature = signer.sign_message(message, rng ? *rng : Test::rng()); result.test_eq("generated signature matches KAT", generated_signature, signature); result.test_eq("generated signature valid", verifier.verify_message(message, generated_signature), true); check_invalid_signatures(result, verifier, message, signature); result.test_eq("correct signature valid", verifier.verify_message(message, signature), true); return result; }
Test::Result PK_Encryption_Decryption_Test::run_one_test(const std::string&, const VarMap& vars) { const std::vector<uint8_t> plaintext = get_req_bin(vars, "Msg"); const std::vector<uint8_t> ciphertext = get_req_bin(vars, "Ciphertext"); const std::string padding = get_opt_str(vars, "Padding", default_padding(vars)); std::unique_ptr<Botan::RandomNumberGenerator> kat_rng; if(vars.count("Nonce")) { kat_rng.reset(new Fixed_Output_RNG(get_req_bin(vars, "Nonce"))); } Test::Result result(algo_name() + "/" + padding + " decryption"); std::unique_ptr<Botan::Private_Key> privkey = load_private_key(vars); // instead slice the private key to work around elgamal test inputs //std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(Botan::X509::BER_encode(*privkey))); Botan::PK_Encryptor_EME encryptor(*privkey, padding); result.test_eq("encryption", encryptor.encrypt(plaintext, kat_rng ? *kat_rng : Test::rng()), ciphertext); Botan::PK_Decryptor_EME decryptor(*privkey, padding); result.test_eq("decryption", decryptor.decrypt(ciphertext), plaintext); check_invalid_ciphertexts(result, decryptor, plaintext, ciphertext); return result; }
Test::Result PK_Signature_NonVerification_Test::run_one_test(const std::string& pad_hdr, const VarMap& vars) { const std::string padding = choose_padding(vars, pad_hdr); const std::vector<uint8_t> message = get_req_bin(vars, "Msg"); std::unique_ptr<Botan::Public_Key> pubkey = load_public_key(vars); const std::vector<uint8_t> invalid_signature = get_req_bin(vars, "InvalidSignature"); Test::Result result(algo_name() + "/" + padding + " verify invalid signature"); for(auto const& verify_provider : possible_providers(algo_name())) { std::unique_ptr<Botan::PK_Verifier> verifier; try { verifier.reset(new Botan::PK_Verifier(*pubkey, padding, Botan::IEEE_1363, verify_provider)); result.test_eq("incorrect signature rejected", verifier->verify_message(message, invalid_signature), false); } catch(Botan::Lookup_Error&) { result.test_note("Skipping verifying with " + verify_provider); } } return result; }
Test::Result PK_KEM_Test::run_one_test(const std::string&, const VarMap& vars) { const std::vector<uint8_t> K = get_req_bin(vars, "K"); const std::vector<uint8_t> C0 = get_req_bin(vars, "C0"); const std::vector<uint8_t> salt = get_opt_bin(vars, "Salt"); const std::string kdf = get_req_str(vars, "KDF"); Test::Result result(algo_name() + "/" + kdf + " KEM"); std::unique_ptr<Botan::Private_Key> privkey = load_private_key(vars); const Botan::Public_Key& pubkey = *privkey; const size_t desired_key_len = K.size(); std::unique_ptr<Botan::PK_KEM_Encryptor> enc; try { enc.reset(new Botan::PK_KEM_Encryptor(pubkey, Test::rng(), kdf)); } catch(Botan::Lookup_Error&) { result.test_note("Skipping due to missing KDF: " + kdf); return result; } Fixed_Output_RNG fixed_output_rng(get_req_bin(vars, "R")); Botan::secure_vector<uint8_t> produced_encap_key, shared_key; enc->encrypt(produced_encap_key, shared_key, desired_key_len, fixed_output_rng, salt); result.test_eq("C0 matches", produced_encap_key, C0); result.test_eq("K matches", shared_key, K); std::unique_ptr<Botan::PK_KEM_Decryptor> dec; try { dec.reset(new Botan::PK_KEM_Decryptor(*privkey, Test::rng(), kdf)); } catch(Botan::Lookup_Error& e) { result.test_note("Skipping test", e.what()); return result; } const Botan::secure_vector<uint8_t> decr_shared_key = dec->decrypt(C0.data(), C0.size(), desired_key_len, salt.data(), salt.size()); result.test_eq("decrypted K matches", decr_shared_key, K); return result; }
Test::Result run_one_test(const std::string&, const VarMap& vars) override { const std::vector<uint8_t> secret = get_req_bin(vars, "Secret"); const std::vector<uint8_t> basepoint = get_req_bin(vars, "Basepoint"); const std::vector<uint8_t> expected = get_req_bin(vars, "Out"); std::vector<uint8_t> got(32); Botan::curve25519_donna(got.data(), secret.data(), basepoint.data()); Test::Result result("Curve25519 scalarmult"); result.test_eq("basemult", got, expected); return result; }
Test::Result run_one_test(const std::string& hash_algo, const VarMap& vars) override { Test::Result result("TOTP " + hash_algo); std::unique_ptr<Botan::HashFunction> hash_test = Botan::HashFunction::create(hash_algo); if(!hash_test) return {result}; const std::vector<uint8_t> key = get_req_bin(vars, "Key"); const size_t otp = get_req_sz(vars, "OTP"); const size_t digits = get_req_sz(vars, "Digits"); const size_t timestep = get_req_sz(vars, "Timestep"); const std::string timestamp = get_req_str(vars, "Timestamp"); Botan::TOTP totp(key, hash_algo, digits, timestep); std::chrono::system_clock::time_point time = from_timestring(timestamp); std::chrono::system_clock::time_point later_time = time + std::chrono::seconds(timestep); std::chrono::system_clock::time_point too_late = time + std::chrono::seconds(2*timestep); result.test_eq("TOTP generate", totp.generate_totp(time), otp); result.test_eq("TOTP verify valid", totp.verify_totp(otp, time, 0), true); result.test_eq("TOTP verify invalid", totp.verify_totp(otp ^ 1, time, 0), false); result.test_eq("TOTP verify time slip", totp.verify_totp(otp, later_time, 0), false); result.test_eq("TOTP verify time slip allowed", totp.verify_totp(otp, later_time, 1), true); result.test_eq("TOTP verify time slip out of range", totp.verify_totp(otp, too_late, 1), false); return result; }
Test::Result PK_Key_Agreement_Test::run_one_test(const std::string& header, const VarMap& vars) { const std::vector<uint8_t> shared = get_req_bin(vars, "K"); const std::string kdf = get_opt_str(vars, "KDF", default_kdf(vars)); Test::Result result(algo_name() + "/" + kdf + (header.empty() ? header : " " + header) + " key agreement"); std::unique_ptr<Botan::Private_Key> privkey = load_our_key(header, vars); const std::vector<uint8_t> pubkey = load_their_key(header, vars); const size_t key_len = get_opt_sz(vars, "OutLen", 0); for(auto&& provider : possible_pk_providers()) { std::unique_ptr<Botan::PK_Key_Agreement> kas; try { kas.reset(new Botan::PK_Key_Agreement(*privkey, kdf, provider)); result.test_eq(provider, "agreement", kas->derive_key(key_len, pubkey).bits_of(), shared); } catch(Botan::Lookup_Error&) { //result.test_note("Skipping key agreement with with " + provider); } } return result; }
Test::Result run_one_test(const std::string& algo, const VarMap& vars) override { const std::vector<uint8_t> key = get_req_bin(vars, "Key"); const std::vector<uint8_t> input = get_req_bin(vars, "In"); const std::vector<uint8_t> expected = get_req_bin(vars, "Out"); const std::vector<uint8_t> nonce = get_opt_bin(vars, "Nonce"); const size_t seek = get_opt_sz(vars, "Seek", 0); Test::Result result(algo); const std::vector<std::string> providers = Botan::StreamCipher::providers(algo); if(providers.empty()) { result.note_missing("block cipher " + algo); return result; } for(auto&& provider: providers) { std::unique_ptr<Botan::StreamCipher> cipher(Botan::StreamCipher::create(algo, provider)); if(!cipher) { result.note_missing(algo + " from " + provider); continue; } result.test_eq(provider, cipher->name(), algo); cipher->set_key(key); if(nonce.size()) cipher->set_iv(nonce.data(), nonce.size()); if (seek != 0) cipher->seek(seek); std::vector<uint8_t> buf = input; cipher->encrypt(buf); result.test_eq(provider, "encrypt", buf, expected); } return result; }
Test::Result PK_Signature_Verification_Test::run_one_test(const std::string&, const VarMap& vars) { const std::vector<uint8_t> message = get_req_bin(vars, "Msg"); const std::vector<uint8_t> signature = get_req_bin(vars, "Signature"); const std::string padding = get_opt_str(vars, "Padding", default_padding(vars)); std::unique_ptr<Botan::Public_Key> pubkey = load_public_key(vars); Test::Result result(algo_name() + "/" + padding + " signature verification"); Botan::PK_Verifier verifier(*pubkey, padding); result.test_eq("correct signature valid", verifier.verify_message(message, signature), true); check_invalid_signatures(result, verifier, message, signature); return result; }
Test::Result run_one_test(const std::string&, const VarMap& vars) override { const Botan::BigInt modulus = get_req_bn(vars, "Mod"); const Botan::BigInt input = get_req_bn(vars, "In"); const Botan::BigInt expected = get_req_bn(vars, "Out"); const std::vector<uint8_t> key = get_req_bin(vars, "Key"); const std::vector<uint8_t> tweak = get_req_bin(vars, "Tweak"); Test::Result result("FPE_FE1"); const Botan::BigInt got = Botan::FPE::fe1_encrypt(modulus, input, key, tweak); result.test_eq("ciphertext", got, expected); const Botan::BigInt decry = Botan::FPE::fe1_decrypt(modulus, got, key, tweak); result.test_eq("decrypted", decry, input); return result; }
Test::Result run_one_test(const std::string& algo, const VarMap& vars) override { const std::vector<uint8_t> key = get_req_bin(vars, "Key"); const std::vector<uint8_t> nonce = get_opt_bin(vars, "Nonce"); const std::vector<uint8_t> input = get_req_bin(vars, "In"); const std::vector<uint8_t> expected = get_req_bin(vars, "Out"); Test::Result result(algo); std::unique_ptr<Botan::Cipher_Mode> enc(Botan::get_cipher_mode(algo, Botan::ENCRYPTION)); std::unique_ptr<Botan::Cipher_Mode> dec(Botan::get_cipher_mode(algo, Botan::DECRYPTION)); if(!enc || !dec) { result.note_missing(algo); return result; } result.test_eq("mode not authenticated", enc->authenticated(), false); enc->set_key(key); enc->start(nonce); Botan::secure_vector<uint8_t> buf(input.begin(), input.end()); // TODO: should first update if possible enc->finish(buf); result.test_eq("encrypt", buf, expected); buf.assign(expected.begin(), expected.end()); dec->set_key(key); dec->start(nonce); dec->finish(buf); result.test_eq("decrypt", buf, input); return result; }
Test::Result PK_Key_Agreement_Test::run_one_test(const std::string&, const VarMap& vars) { const std::vector<uint8_t> shared = get_req_bin(vars, "K"); const std::string kdf = get_opt_str(vars, "KDF", default_kdf(vars)); Test::Result result(algo_name() + "/" + kdf + " key agreement"); std::unique_ptr<Botan::Private_Key> privkey = load_our_key(vars); const std::vector<uint8_t> pubkey = load_their_key(vars); const size_t key_len = get_opt_sz(vars, "OutLen", 0); Botan::PK_Key_Agreement kas(*privkey, kdf); result.test_eq("agreement", kas.derive_key(key_len, pubkey).bits_of(), shared); return result; }
Test::Result run_one_test(const std::string& hash_algo, const VarMap& vars) override { Test::Result result("HOTP " + hash_algo); std::unique_ptr<Botan::HashFunction> hash_test = Botan::HashFunction::create(hash_algo); if(!hash_test) return {result}; const std::vector<uint8_t> key = get_req_bin(vars, "Key"); const size_t otp = get_req_sz(vars, "OTP"); const uint64_t counter = get_req_sz(vars, "Counter"); const size_t digits = get_req_sz(vars, "Digits"); Botan::HOTP hotp(key, hash_algo, digits); result.test_eq("OTP", hotp.generate_hotp(counter), otp); std::pair<bool, uint64_t> otp_res = hotp.verify_hotp(otp, counter, 0); result.test_eq("OTP verify result", otp_res.first, true); result.confirm("OTP verify next counter", otp_res.second == counter + 1); // Test invalid OTP otp_res = hotp.verify_hotp(otp + 1, counter, 0); result.test_eq("OTP verify result", otp_res.first, false); result.confirm("OTP verify next counter", otp_res.second == counter); // Test invalid OTP with long range otp_res = hotp.verify_hotp(otp + 1, counter, 100); result.test_eq("OTP verify result", otp_res.first, false); result.confirm("OTP verify next counter", otp_res.second == counter); // Test valid OTP with long range otp_res = hotp.verify_hotp(otp, counter - 90, 100); result.test_eq("OTP verify result", otp_res.first, true); result.confirm("OTP verify next counter", otp_res.second == counter + 1); return result; }
Test::Result run_one_test(const std::string& algo, const VarMap& vars) override { const std::vector<uint8_t> key = get_req_bin(vars, "Key"); const std::vector<uint8_t> input = get_req_bin(vars, "In"); const std::vector<uint8_t> expected = get_req_bin(vars, "Out"); Test::Result result(algo); const std::vector<std::string> providers = Botan::BlockCipher::providers(algo); if(providers.empty()) { result.note_missing("block cipher " + algo); return result; } for(auto&& provider_ask : providers) { std::unique_ptr<Botan::BlockCipher> cipher(Botan::BlockCipher::create(algo, provider_ask)); if(!cipher) { result.test_failure("Cipher " + algo + " supported by " + provider_ask + " but not found"); continue; } const std::string provider(cipher->provider()); result.test_is_nonempty("provider", provider); result.test_eq(provider, cipher->name(), algo); result.test_gte(provider, cipher->parallelism(), 1); result.test_gte(provider, cipher->block_size(), 8); result.test_gte(provider, cipher->parallel_bytes(), cipher->block_size() * cipher->parallelism()); // Test to make sure clear() resets what we need it to cipher->set_key(Test::rng().random_vec(cipher->key_spec().minimum_keylength())); Botan::secure_vector<byte> garbage = Test::rng().random_vec(cipher->block_size()); cipher->encrypt(garbage); cipher->clear(); cipher->set_key(key); // Test that clone works and does not affect parent object std::unique_ptr<Botan::BlockCipher> clone(cipher->clone()); result.confirm("Clone has different pointer", cipher.get() != clone.get()); result.test_eq("Clone has same name", cipher->name(), clone->name()); clone->set_key(Test::rng().random_vec(cipher->maximum_keylength())); // have called set_key on clone: process input values std::vector<uint8_t> buf = input; cipher->encrypt(buf); result.test_eq(provider, "encrypt", buf, expected); // always decrypt expected ciphertext vs what we produced above buf = expected; cipher->decrypt(buf); cipher->clear(); result.test_eq(provider, "decrypt", buf, input); } return result; }
Test::Result run_one_test(const std::string& algo, const VarMap& vars) override { const std::vector<uint8_t> key = get_req_bin(vars, "Key"); const std::vector<uint8_t> expected = get_req_bin(vars, "Out"); const std::vector<uint8_t> nonce = get_opt_bin(vars, "Nonce"); const size_t seek = get_opt_sz(vars, "Seek", 0); std::vector<uint8_t> input = get_opt_bin(vars, "In"); if(input.empty()) input.resize(expected.size()); Test::Result result(algo); const std::vector<std::string> providers = provider_filter(Botan::StreamCipher::providers(algo)); if(providers.empty()) { result.note_missing("block cipher " + algo); return result; } for(auto&& provider_ask : providers) { std::unique_ptr<Botan::StreamCipher> cipher(Botan::StreamCipher::create(algo, provider_ask)); if(!cipher) { result.test_failure("Stream " + algo + " supported by " + provider_ask + " but not found"); continue; } const std::string provider(cipher->provider()); result.test_is_nonempty("provider", provider); result.test_eq(provider, cipher->name(), algo); cipher->set_key(key); if(nonce.size()) { if(!cipher->valid_iv_length(nonce.size())) throw Test_Error("Invalid nonce for " + algo); cipher->set_iv(nonce.data(), nonce.size()); } else { /* * If no nonce was set then implicitly the cipher is using a * null/empty nonce. Call set_iv with such a nonce to make sure * set_iv accepts it. */ if(!cipher->valid_iv_length(0)) throw Test_Error("Stream cipher " + algo + " requires nonce but none provided"); cipher->set_iv(nullptr, 0); } if (seek != 0) cipher->seek(seek); // Test that clone works and does not affect parent object std::unique_ptr<Botan::StreamCipher> clone(cipher->clone()); result.confirm("Clone has different pointer", cipher.get() != clone.get()); result.test_eq("Clone has same name", cipher->name(), clone->name()); clone->set_key(Test::rng().random_vec(cipher->maximum_keylength())); std::vector<uint8_t> buf = input; cipher->encrypt(buf); cipher->clear(); result.test_eq(provider, "encrypt", buf, expected); } return result; }
Test::Result PK_Signature_Generation_Test::run_one_test(const std::string&, const VarMap& vars) { const std::vector<uint8_t> message = get_req_bin(vars, "Msg"); const std::vector<uint8_t> signature = get_req_bin(vars, "Signature"); const std::string padding = get_opt_str(vars, "Padding", default_padding(vars)); Test::Result result(algo_name() + "/" + padding + " signature generation"); std::unique_ptr<Botan::Private_Key> privkey = load_private_key(vars); std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(Botan::X509::BER_encode(*privkey))); for(auto&& sign_provider : possible_pk_providers()) { std::unique_ptr<Botan::PK_Signer> signer; try { signer.reset(new Botan::PK_Signer(*privkey, padding, Botan::IEEE_1363, sign_provider)); } catch(Botan::Lookup_Error&) { //result.test_note("Skipping signing with " + sign_provider); continue; } std::unique_ptr<Botan::RandomNumberGenerator> rng; if(vars.count("Nonce")) { rng.reset(new Fixed_Output_RNG(get_req_bin(vars, "Nonce"))); } const std::vector<uint8_t> generated_signature = signer->sign_message(message, rng ? *rng : Test::rng()); if(sign_provider == "base") { result.test_eq("generated signature matches KAT", generated_signature, signature); } for(auto&& verify_provider : possible_pk_providers()) { std::unique_ptr<Botan::PK_Verifier> verifier; try { verifier.reset(new Botan::PK_Verifier(*pubkey, padding, Botan::IEEE_1363, verify_provider)); } catch(Botan::Lookup_Error&) { //result.test_note("Skipping verifying with " + verify_provider); continue; } if(!result.test_eq("generated signature valid", verifier->verify_message(message, generated_signature), true)) { result.test_failure("generated signature", generated_signature); } check_invalid_signatures(result, *verifier, message, signature); result.test_eq("KAT signature valid", verifier->verify_message(message, signature), true); } } return result; }
Test::Result PK_Encryption_Decryption_Test::run_one_test(const std::string& pad_hdr, const VarMap& vars) { const std::vector<uint8_t> plaintext = get_req_bin(vars, "Msg"); const std::vector<uint8_t> ciphertext = get_req_bin(vars, "Ciphertext"); const std::string padding = choose_padding(vars, pad_hdr); Test::Result result(algo_name() + (padding.empty() ? padding : "/" + padding) + " decryption"); std::unique_ptr<Botan::Private_Key> privkey = load_private_key(vars); // instead slice the private key to work around elgamal test inputs //std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(Botan::X509::BER_encode(*privkey))); Botan::Public_Key* pubkey = privkey.get(); std::vector<std::unique_ptr<Botan::PK_Decryptor>> decryptors; for(auto const& dec_provider : possible_providers(algo_name())) { std::unique_ptr<Botan::PK_Decryptor> decryptor; try { decryptor.reset(new Botan::PK_Decryptor_EME(*privkey, Test::rng(), padding, dec_provider)); } catch(Botan::Lookup_Error&) { continue; } Botan::secure_vector<uint8_t> decrypted; try { decrypted = decryptor->decrypt(ciphertext); } catch(Botan::Exception& e) { result.test_failure("Failed to decrypt KAT ciphertext", e.what()); } result.test_eq(dec_provider, "decryption of KAT", decrypted, plaintext); check_invalid_ciphertexts(result, *decryptor, plaintext, ciphertext); } for(auto const& enc_provider : possible_providers(algo_name())) { std::unique_ptr<Botan::PK_Encryptor> encryptor; try { encryptor.reset(new Botan::PK_Encryptor_EME(*pubkey, Test::rng(), padding, enc_provider)); } catch(Botan::Lookup_Error&) { continue; } std::unique_ptr<Botan::RandomNumberGenerator> kat_rng; if(vars.count("Nonce")) { kat_rng.reset(test_rng(get_req_bin(vars, "Nonce"))); } if(padding == "Raw") { /* Hack for RSA with no padding since sometimes one more bit will fit in but maximum_input_size rounds down to nearest byte */ result.test_lte("Input within accepted bounds", plaintext.size(), encryptor->maximum_input_size() + 1); } else { result.test_lte("Input within accepted bounds", plaintext.size(), encryptor->maximum_input_size()); } const std::vector<uint8_t> generated_ciphertext = encryptor->encrypt(plaintext, kat_rng ? *kat_rng : Test::rng()); if(enc_provider == "base") { result.test_eq(enc_provider, "generated ciphertext matches KAT", generated_ciphertext, ciphertext); } else if(generated_ciphertext != ciphertext) { for(std::unique_ptr<Botan::PK_Decryptor>& dec : decryptors) { result.test_eq("decryption of generated ciphertext", dec->decrypt(generated_ciphertext), plaintext); } } } return result; }
Test::Result PK_Encryption_Decryption_Test::run_one_test(const std::string&, const VarMap& vars) { const std::vector<uint8_t> plaintext = get_req_bin(vars, "Msg"); const std::vector<uint8_t> ciphertext = get_req_bin(vars, "Ciphertext"); const std::string padding = get_opt_str(vars, "Padding", default_padding(vars)); Test::Result result(algo_name() + "/" + padding + " decryption"); std::unique_ptr<Botan::Private_Key> privkey = load_private_key(vars); // instead slice the private key to work around elgamal test inputs //std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(Botan::X509::BER_encode(*privkey))); Botan::Public_Key* pubkey = privkey.get(); for(auto&& enc_provider : possible_pk_providers()) { std::unique_ptr<Botan::PK_Encryptor> encryptor; try { encryptor.reset(new Botan::PK_Encryptor_EME(*pubkey, padding, enc_provider)); } catch(Botan::Lookup_Error&) { //result.test_note("Skipping encryption with provider " + enc_provider); continue; } std::unique_ptr<Botan::RandomNumberGenerator> kat_rng; if(vars.count("Nonce")) { kat_rng.reset(new Fixed_Output_RNG(get_req_bin(vars, "Nonce"))); } const std::vector<uint8_t> generated_ciphertext = encryptor->encrypt(plaintext, kat_rng ? *kat_rng : Test::rng()); if(enc_provider == "base") { result.test_eq("generated ciphertext matches KAT", generated_ciphertext, ciphertext); } for(auto&& dec_provider : possible_pk_providers()) { std::unique_ptr<Botan::PK_Decryptor> decryptor; try { decryptor.reset(new Botan::PK_Decryptor_EME(*privkey, padding, dec_provider)); } catch(Botan::Lookup_Error&) { //result.test_note("Skipping decryption with provider " + dec_provider); continue; } result.test_eq("decryption of KAT", decryptor->decrypt(ciphertext), plaintext); check_invalid_ciphertexts(result, *decryptor, plaintext, ciphertext); result.test_eq("decryption of generated ciphertext", decryptor->decrypt(generated_ciphertext), plaintext); } } return result; }
Test::Result PK_Signature_Generation_Test::run_one_test(const std::string& pad_hdr, const VarMap& vars) { const std::vector<uint8_t> message = get_req_bin(vars, "Msg"); const std::vector<uint8_t> signature = get_req_bin(vars, "Signature"); const std::string padding = choose_padding(vars, pad_hdr); Test::Result result(algo_name() + "/" + padding + " signature generation"); std::unique_ptr<Botan::Private_Key> privkey; try { privkey = load_private_key(vars); } catch(Botan::Lookup_Error& e) { result.note_missing(e.what()); return result; } std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(Botan::X509::BER_encode(*privkey))); std::vector<std::unique_ptr<Botan::PK_Verifier>> verifiers; for(auto const& verify_provider : possible_providers(algo_name())) { std::unique_ptr<Botan::PK_Verifier> verifier; try { verifier.reset(new Botan::PK_Verifier(*pubkey, padding, Botan::IEEE_1363, verify_provider)); } catch(Botan::Lookup_Error&) { //result.test_note("Skipping verifying with " + verify_provider); continue; } result.test_eq("KAT signature valid", verifier->verify_message(message, signature), true); check_invalid_signatures(result, *verifier, message, signature); verifiers.push_back(std::move(verifier)); } for(auto const& sign_provider : possible_providers(algo_name())) { std::unique_ptr<Botan::RandomNumberGenerator> rng; if(vars.count("Nonce")) { rng.reset(test_rng(get_req_bin(vars, "Nonce"))); } std::unique_ptr<Botan::PK_Signer> signer; std::vector<uint8_t> generated_signature; try { signer.reset(new Botan::PK_Signer(*privkey, Test::rng(), padding, Botan::IEEE_1363, sign_provider)); generated_signature = signer->sign_message(message, rng ? *rng : Test::rng()); } catch(Botan::Lookup_Error&) { //result.test_note("Skipping signing with " + sign_provider); continue; } if(sign_provider == "base") { result.test_eq("generated signature matches KAT", generated_signature, signature); } else if(generated_signature != signature) { for(std::unique_ptr<Botan::PK_Verifier>& verifier : verifiers) { if(!result.test_eq("generated signature valid", verifier->verify_message(message, generated_signature), true)) { result.test_failure("generated signature", generated_signature); } } } } return result; }
Test::Result run_one_test(const std::string& algo, const VarMap& vars) override { const std::vector<uint8_t> key = get_req_bin(vars, "Key"); const std::vector<uint8_t> expected = get_req_bin(vars, "Out"); const std::vector<uint8_t> nonce = get_opt_bin(vars, "Nonce"); const size_t seek = get_opt_sz(vars, "Seek", 0); std::vector<uint8_t> input = get_opt_bin(vars, "In"); if(input.empty()) { input.resize(expected.size()); } Test::Result result(algo); const std::vector<std::string> providers = provider_filter(Botan::StreamCipher::providers(algo)); if(providers.empty()) { result.note_missing("block cipher " + algo); return result; } for(auto const& provider_ask : providers) { std::unique_ptr<Botan::StreamCipher> cipher(Botan::StreamCipher::create(algo, provider_ask)); if(!cipher) { result.test_failure("Stream " + algo + " supported by " + provider_ask + " but not found"); continue; } const std::string provider(cipher->provider()); result.test_is_nonempty("provider", provider); result.test_eq(provider, cipher->name(), algo); try { std::vector<uint8_t> buf(128); cipher->cipher1(buf.data(), buf.size()); result.test_failure("Was able to encrypt without a key being set"); } catch(Botan::Invalid_State&) { result.test_success("Trying to encrypt with no key set fails"); } try { cipher->seek(0); result.test_failure("Was able to seek without a key being set"); } catch(Botan::Invalid_State&) { result.test_success("Trying to seek with no key set fails"); } catch(Botan::Not_Implemented&) { result.test_success("Trying to seek failed because not implemented"); } cipher->set_key(key); /* Test invalid nonce sizes. this assumes no implemented cipher supports a nonce of 65000 */ const size_t large_nonce_size = 65000; result.confirm("Stream cipher does not support very large nonce", cipher->valid_iv_length(large_nonce_size) == false); result.test_throws("Throws if invalid nonce size given", [&]() { cipher->set_iv(nullptr, large_nonce_size); }); if(nonce.size()) { if(!cipher->valid_iv_length(nonce.size())) { throw Test_Error("Invalid nonce for " + algo); } cipher->set_iv(nonce.data(), nonce.size()); } else { /* * If no nonce was set then implicitly the cipher is using a * null/empty nonce. Call set_iv with such a nonce to make sure * set_iv accepts it. */ if(!cipher->valid_iv_length(0)) { throw Test_Error("Stream cipher " + algo + " requires nonce but none provided"); } cipher->set_iv(nullptr, 0); } if(seek != 0) { cipher->seek(seek); } // Test that clone works and does not affect parent object std::unique_ptr<Botan::StreamCipher> clone(cipher->clone()); result.confirm("Clone has different pointer", cipher.get() != clone.get()); result.test_eq("Clone has same name", cipher->name(), clone->name()); clone->set_key(Test::rng().random_vec(cipher->maximum_keylength())); { std::vector<uint8_t> buf = input; cipher->encrypt(buf); result.test_eq(provider, "encrypt", buf, expected); } cipher->clear(); try { std::vector<uint8_t> buf(128); cipher->cipher1(buf.data(), buf.size()); result.test_failure("Was able to encrypt without a key being set (after clear)"); } catch(Botan::Invalid_State&) { result.test_success("Trying to encrypt with no key set (after clear) fails"); } } return result; }
Test::Result run_one_test(const std::string& algo, const VarMap& vars) override { const std::vector<uint8_t> key = get_req_bin(vars, "Key"); const std::vector<uint8_t> nonce = get_opt_bin(vars, "Nonce"); const std::vector<uint8_t> input = get_req_bin(vars, "In"); const std::vector<uint8_t> expected = get_req_bin(vars, "Out"); Test::Result result(algo); const std::vector<std::string> providers = possible_providers(algo); if(providers.empty()) { result.note_missing("cipher mode " + algo); return result; } for(auto&& provider_ask : providers) { std::unique_ptr<Botan::Cipher_Mode> enc(Botan::get_cipher_mode( algo, Botan::ENCRYPTION, provider_ask)); std::unique_ptr<Botan::Cipher_Mode> dec(Botan::get_cipher_mode( algo, Botan::DECRYPTION, provider_ask)); if(!enc || !dec) { result.note_missing(algo); return result; } result.test_is_nonempty("provider", enc->provider()); result.test_eq("name", enc->name(), algo); result.test_eq("mode not authenticated", enc->authenticated(), false); // Test to make sure reset() resets what we need it to enc->set_key(mutate_vec(key)); Botan::secure_vector<uint8_t> garbage = Test::rng().random_vec(enc->update_granularity()); enc->start(mutate_vec(nonce)); enc->update(garbage); enc->reset(); enc->set_key(key); enc->start(nonce); Botan::secure_vector<uint8_t> buf(input.begin(), input.end()); // TODO: should first update if possible enc->finish(buf); result.test_eq("encrypt", buf, expected); // additionally test process() if possible size_t update_granularity = enc->update_granularity(); size_t input_length = input.size(); size_t min_final_bytes = enc->minimum_final_size(); if(input_length > (update_granularity + min_final_bytes)) { // reset state first enc->reset(); enc->start(nonce); buf.assign(input.begin(), input.end()); // we can process at max input_length const size_t max_blocks_to_process = (input_length - min_final_bytes) / update_granularity; const size_t bytes_to_process = max_blocks_to_process * update_granularity; const size_t bytes_written = enc->process(buf.data(), bytes_to_process); result.test_eq("correct number of bytes processed", bytes_written, bytes_to_process); enc->finish(buf, bytes_to_process); result.test_eq("encrypt", buf, expected); } // decryption buf.assign(expected.begin(), expected.end()); // Test to make sure reset() resets what we need it to dec->set_key(mutate_vec(key)); garbage = Test::rng().random_vec(dec->update_granularity()); dec->start(mutate_vec(nonce)); dec->update(garbage); dec->reset(); dec->set_key(key); dec->start(nonce); dec->finish(buf); result.test_eq("decrypt", buf, input); // additionally test process() if possible update_granularity = dec->update_granularity(); input_length = expected.size(); min_final_bytes = dec->minimum_final_size(); if(input_length > (update_granularity + min_final_bytes)) { // reset state first dec->reset(); dec->start(nonce); buf.assign(expected.begin(), expected.end()); // we can process at max input_length const size_t max_blocks_to_process = (input_length - min_final_bytes) / update_granularity; const size_t bytes_to_process = max_blocks_to_process * update_granularity; const size_t bytes_written = dec->process(buf.data(), bytes_to_process); result.test_eq("correct number of bytes processed", bytes_written, bytes_to_process); dec->finish(buf, bytes_to_process); result.test_eq("decrypt", buf, input); } enc->clear(); dec->clear(); } return result; }