diff options
author | Jack Lloyd <[email protected]> | 2016-11-26 11:38:01 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-11-26 11:38:01 -0500 |
commit | 345f0881bc44b7a8344ea943e96b1dad4a8d484b (patch) | |
tree | d7d30b2e13abe660713eafed3e034ebf1494e7f8 /src | |
parent | d695dfadc0daf8290d344f82697d456fd011d153 (diff) |
Add test for various functions previously missed (T::clone, PBKDF::name, AEAD::output_length)
Fix a bug in CCM, GCM, and OCB decryption which caused `output_length(tag_size())`
to fail even though empty plaintexts are certainly defined for all three modes.
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/modes/aead/ccm/ccm.h | 2 | ||||
-rw-r--r-- | src/lib/modes/aead/gcm/gcm.h | 2 | ||||
-rw-r--r-- | src/lib/modes/aead/ocb/ocb.h | 2 | ||||
-rw-r--r-- | src/tests/data/pbkdf/pbkdf1.vec | 2 | ||||
-rw-r--r-- | src/tests/data/pbkdf/pbkdf2.vec | 8 | ||||
-rw-r--r-- | src/tests/test_aead.cpp | 4 | ||||
-rw-r--r-- | src/tests/test_block.cpp | 11 | ||||
-rw-r--r-- | src/tests/test_compression.cpp | 2 | ||||
-rw-r--r-- | src/tests/test_hash.cpp | 9 | ||||
-rw-r--r-- | src/tests/test_kdf.cpp | 5 | ||||
-rw-r--r-- | src/tests/test_mac.cpp | 9 | ||||
-rw-r--r-- | src/tests/test_pbkdf.cpp | 12 | ||||
-rw-r--r-- | src/tests/test_pubkey.cpp | 3 | ||||
-rw-r--r-- | src/tests/test_stream.cpp | 12 | ||||
-rw-r--r-- | src/tests/tests.cpp | 12 | ||||
-rw-r--r-- | src/tests/tests.h | 2 |
16 files changed, 79 insertions, 18 deletions
diff --git a/src/lib/modes/aead/ccm/ccm.h b/src/lib/modes/aead/ccm/ccm.h index 2a17595e7..9795354fc 100644 --- a/src/lib/modes/aead/ccm/ccm.h +++ b/src/lib/modes/aead/ccm/ccm.h @@ -116,7 +116,7 @@ class BOTAN_DLL CCM_Decryption final : public CCM_Mode size_t output_length(size_t input_length) const override { - BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); return input_length - tag_size(); } diff --git a/src/lib/modes/aead/gcm/gcm.h b/src/lib/modes/aead/gcm/gcm.h index 463e69a3b..65b6b0474 100644 --- a/src/lib/modes/aead/gcm/gcm.h +++ b/src/lib/modes/aead/gcm/gcm.h @@ -95,7 +95,7 @@ class BOTAN_DLL GCM_Decryption final : public GCM_Mode size_t output_length(size_t input_length) const override { - BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); return input_length - tag_size(); } diff --git a/src/lib/modes/aead/ocb/ocb.h b/src/lib/modes/aead/ocb/ocb.h index ce9d29f1b..dfdb8c18c 100644 --- a/src/lib/modes/aead/ocb/ocb.h +++ b/src/lib/modes/aead/ocb/ocb.h @@ -107,7 +107,7 @@ class BOTAN_DLL OCB_Decryption final : public OCB_Mode size_t output_length(size_t input_length) const override { - BOTAN_ASSERT(input_length > tag_size(), "Sufficient input"); + BOTAN_ASSERT(input_length >= tag_size(), "Sufficient input"); return input_length - tag_size(); } diff --git a/src/tests/data/pbkdf/pbkdf1.vec b/src/tests/data/pbkdf/pbkdf1.vec index ebcad175b..a0eeba6e5 100644 --- a/src/tests/data/pbkdf/pbkdf1.vec +++ b/src/tests/data/pbkdf/pbkdf1.vec @@ -1,4 +1,4 @@ -[PBKDF1(SHA-1)] +[PBKDF1(SHA-160)] Salt = 40AC5837560251C275AF5E30A6A3074E57CED38E Iterations = 6 Passphrase = ftlkfbxdtbjbvllvbwiw diff --git a/src/tests/data/pbkdf/pbkdf2.vec b/src/tests/data/pbkdf/pbkdf2.vec index 6a027721a..c8a5356be 100644 --- a/src/tests/data/pbkdf/pbkdf2.vec +++ b/src/tests/data/pbkdf/pbkdf2.vec @@ -1,4 +1,4 @@ -[PBKDF2(SHA-1)] +[PBKDF2(HMAC(SHA-160))] Salt = 0001020304050607 Iterations = 10000 Passphrase = @@ -59,21 +59,21 @@ Passphrase = gwrxpqxumsdsmbmhfhmfdcvlcvngzkig OutputLen = 64 Output = 4C9DB7BA24955225D5B845F65EF24EF1B0C6E86F2E39C8DDAA4B8ABD26082D1F350381FADEAEB560DC447AFC68A6B47E6EA1E7412F6CF7B2D82342FCCD11D3B4 -[PBKDF2(SHA-256)] +[PBKDF2(HMAC(SHA-256))] Salt = 0001020304050607 Iterations = 10000 Passphrase = xyz OutputLen = 48 Output = DEFD2987FA26A4672F4D16D98398432AD95E896BF619F6A6B8D4ED1FAF98E8B531B39FFB66966D0E115A6CD8E70B72D0 -[PBKDF2(SHA-384)] +[PBKDF2(HMAC(SHA-384))] Salt = 0001020304050607 Iterations = 10000 Passphrase = xyz OutputLen = 48 Output = 47A3AE920B24EDAA2BB53155808554B13FAB58DF62B81F043D9812E9F2881164DF20BBFFA54E5EE2489FA183B6718A74 -[PBKDF2(SHA-512)] +[PBKDF2(HMAC(SHA-512))] Salt = 0001020304050607 Iterations = 10000 Passphrase = xyz diff --git a/src/tests/test_aead.cpp b/src/tests/test_aead.cpp index 24352a536..ed94d75ba 100644 --- a/src/tests/test_aead.cpp +++ b/src/tests/test_aead.cpp @@ -32,6 +32,8 @@ class AEAD_Tests : public Text_Based_Test std::unique_ptr<Botan::AEAD_Mode> enc(Botan::get_aead(algo, Botan::ENCRYPTION)); + result.test_eq("AEAD encrypt output_length is correct", enc->output_length(input.size()), expected.size()); + // First some tests for reset() to make sure it resets what we need it to // set garbage values enc->set_key(mutate_vec(key)); @@ -132,6 +134,8 @@ class AEAD_Tests : public Text_Based_Test std::unique_ptr<Botan::AEAD_Mode> dec(Botan::get_aead(algo, Botan::DECRYPTION)); + result.test_eq("AEAD decrypt output_length is correct", dec->output_length(input.size()), expected.size()); + // First some tests for reset() to make sure it resets what we need it to // set garbage values dec->set_key(mutate_vec(key)); diff --git a/src/tests/test_block.cpp b/src/tests/test_block.cpp index 82ab0618d..48d6230c3 100644 --- a/src/tests/test_block.cpp +++ b/src/tests/test_block.cpp @@ -36,7 +36,7 @@ class Block_Cipher_Tests : public Text_Based_Test if(!cipher) { - result.note_missing(algo + " from " + provider_ask); + result.test_failure("Cipher " + algo + " supported by " + provider_ask + " but not found"); continue; } @@ -54,6 +54,14 @@ class Block_Cipher_Tests : public Text_Based_Test 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); @@ -67,6 +75,7 @@ class Block_Cipher_Tests : public Text_Based_Test cipher->clear(); result.test_eq(provider, "decrypt", buf, input); + } return result; diff --git a/src/tests/test_compression.cpp b/src/tests/test_compression.cpp index d8dcdb410..e5db055a5 100644 --- a/src/tests/test_compression.cpp +++ b/src/tests/test_compression.cpp @@ -75,6 +75,8 @@ class Compression_Tests : public Test continue; } + result.test_ne("Not the same name", c->name(), d->name()); + const Botan::secure_vector<uint8_t> empty; const Botan::secure_vector<uint8_t> all_zeros(text_len, 0); const Botan::secure_vector<uint8_t> random_binary = Test::rng().random_vec(text_len); diff --git a/src/tests/test_hash.cpp b/src/tests/test_hash.cpp index dc93bb4d1..2ff74d1f2 100644 --- a/src/tests/test_hash.cpp +++ b/src/tests/test_hash.cpp @@ -38,7 +38,7 @@ class Hash_Function_Tests : public Text_Based_Test if(!hash) { - result.note_missing(algo + " from " + provider_ask); + result.test_failure("Hash " + algo + " supported by " + provider_ask + " but not found"); continue; } @@ -63,12 +63,19 @@ class Hash_Function_Tests : public Text_Based_Test result.test_eq(provider, "hashing after clear", hash->final(), expected); + // TODO: feed in random pieces to fully test buffering if(input.size() > 1) { hash->update(input[0]); hash->update(&input[1], input.size() - 1); result.test_eq(provider, "hashing split", hash->final(), expected); } + + if(hash->hash_block_size() > 0) + { + // GOST-34.11 uses 32 byte block + result.test_gte("If hash_block_size is set, it is large", hash->hash_block_size(), 32); + } } return result; diff --git a/src/tests/test_kdf.cpp b/src/tests/test_kdf.cpp index 50034de0e..ec3688fef 100644 --- a/src/tests/test_kdf.cpp +++ b/src/tests/test_kdf.cpp @@ -44,6 +44,11 @@ class KDF_KAT_Tests : public Text_Based_Test result.test_eq("name", kdf->name(), kdf_name); result.test_eq("derived key", kdf->derive_key(outlen, secret, salt, label), expected); + // Test that clone works + std::unique_ptr<Botan::KDF> clone(kdf->clone()); + result.confirm("Clone has different pointer", kdf.get() != clone.get()); + result.test_eq("Clone has same name", kdf->name(), clone->name()); + return result; } diff --git a/src/tests/test_mac.cpp b/src/tests/test_mac.cpp index 33972fabc..be897143b 100644 --- a/src/tests/test_mac.cpp +++ b/src/tests/test_mac.cpp @@ -46,7 +46,7 @@ class Message_Auth_Tests : public Text_Based_Test if(!mac) { - result.note_missing(algo + " from " + provider_ask); + result.test_failure("MAC " + algo + " supported by " + provider_ask + " but not found"); continue; } @@ -72,6 +72,13 @@ class Message_Auth_Tests : public Text_Based_Test mac->start(iv); mac->update(input); + // Test that clone works and does not affect parent object + std::unique_ptr<Botan::MessageAuthenticationCode> clone(mac->clone()); + result.confirm("Clone has different pointer", mac.get() != clone.get()); + result.test_eq("Clone has same name", mac->name(), clone->name()); + clone->set_key(key); + clone->update(Test::rng().random_vec(32)); + result.test_eq(provider + " correct mac", mac->verify_mac(expected.data(), expected.size()), true); if(input.size() > 2) diff --git a/src/tests/test_pbkdf.cpp b/src/tests/test_pbkdf.cpp index 393a96243..af2cdd498 100644 --- a/src/tests/test_pbkdf.cpp +++ b/src/tests/test_pbkdf.cpp @@ -24,6 +24,12 @@ class PBKDF_KAT_Tests : public Text_Based_Test Test::Result run_one_test(const std::string& pbkdf_name, const VarMap& vars) override { + const size_t outlen = get_req_sz(vars, "OutputLen"); + const size_t iterations = get_req_sz(vars, "Iterations"); + const std::vector<uint8_t> salt = get_req_bin(vars, "Salt"); + const std::string passphrase = get_req_str(vars, "Passphrase"); + const std::vector<uint8_t> expected = get_req_bin(vars, "Output"); + Test::Result result(pbkdf_name); std::unique_ptr<Botan::PBKDF> pbkdf(Botan::PBKDF::create(pbkdf_name)); @@ -33,11 +39,7 @@ class PBKDF_KAT_Tests : public Text_Based_Test return result; } - const size_t outlen = get_req_sz(vars, "OutputLen"); - const size_t iterations = get_req_sz(vars, "Iterations"); - const std::vector<uint8_t> salt = get_req_bin(vars, "Salt"); - const std::string passphrase = get_req_str(vars, "Passphrase"); - const std::vector<uint8_t> expected = get_req_bin(vars, "Output"); + result.test_eq("Expected name", pbkdf->name(), pbkdf_name); const Botan::secure_vector<byte> derived = pbkdf->derive_key(outlen, passphrase, salt.data(), salt.size(), iterations).bits_of(); diff --git a/src/tests/test_pubkey.cpp b/src/tests/test_pubkey.cpp index 654021805..c2c1bb256 100644 --- a/src/tests/test_pubkey.cpp +++ b/src/tests/test_pubkey.cpp @@ -373,6 +373,9 @@ std::vector<Test::Result> PK_Key_Generation_Test::run() result.confirm("Key passes self tests", key.check_key(Test::rng(), true)); + result.test_gte("Key has reasonable estimated strength (lower)", key.estimated_strength(), 64); + result.test_lt("Key has reasonable estimated strength (upper)", key.estimated_strength(), 512); + // Test PEM public key round trips OK try { diff --git a/src/tests/test_stream.cpp b/src/tests/test_stream.cpp index d53777593..0af0be12c 100644 --- a/src/tests/test_stream.cpp +++ b/src/tests/test_stream.cpp @@ -47,7 +47,7 @@ class Stream_Cipher_Tests : public Text_Based_Test if(!cipher) { - result.note_missing(algo + " from " + provider_ask); + result.test_failure("Stream " + algo + " supported by " + provider_ask + " but not found"); continue; } @@ -58,6 +58,8 @@ class Stream_Cipher_Tests : public Text_Based_Test 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 @@ -67,12 +69,20 @@ class Stream_Cipher_Tests : public Text_Based_Test * 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); diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp index 1fe41428e..f922c99a6 100644 --- a/src/tests/tests.cpp +++ b/src/tests/tests.cpp @@ -264,6 +264,16 @@ bool Test::Result::test_gte(const std::string& what, size_t produced, size_t exp return test_success(); } +bool Test::Result::test_ne(const std::string& what, const std::string& str1, const std::string& str2) + { + if(str1 != str2) + { + return test_success(str1 + " != " + str2); + } + + return test_failure(who() + " " + what + " produced matching strings " + str1); + } + bool Test::Result::test_ne(const std::string& what, size_t produced, size_t expected) { if(produced != expected) @@ -272,7 +282,7 @@ bool Test::Result::test_ne(const std::string& what, size_t produced, size_t expe } std::ostringstream err; - err << who() << " " << what << " produced " << produced << " prohibited value"; + err << who() << " " << what << " produced " << produced << " unexpected value"; return test_failure(err.str()); } diff --git a/src/tests/tests.h b/src/tests/tests.h index 7d168be72..733e948ea 100644 --- a/src/tests/tests.h +++ b/src/tests/tests.h @@ -230,6 +230,8 @@ class Test bool test_ne(const std::string& what, size_t produced, size_t expected); + bool test_ne(const std::string& what, const std::string& str1, const std::string& str2); + #if defined(BOTAN_HAS_BIGINT) bool test_eq(const std::string& what, const BigInt& produced, const BigInt& expected); bool test_ne(const std::string& what, const BigInt& produced, const BigInt& expected); |