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& 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 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 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 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; }