diff options
author | lloyd <[email protected]> | 2013-03-16 22:23:59 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2013-03-16 22:23:59 +0000 |
commit | 158b20308dcc5c81e712e2e496fa0a5944e484a4 (patch) | |
tree | b797fed9a06ba62f57b4c6d771d389c493f6ab0c | |
parent | 01d1a8f734b9912301e4c0b6504c5ffa1d09e27a (diff) |
Working GCM. Add support for AEAD modes in self tests
-rw-r--r-- | checks/bench.cpp | 29 | ||||
-rw-r--r-- | checks/validate.cpp | 3 | ||||
-rw-r--r-- | checks/validate.dat | 91 | ||||
-rw-r--r-- | src/filters/modes/gcm/gcm.cpp | 113 | ||||
-rw-r--r-- | src/filters/modes/gcm/gcm.h | 6 | ||||
-rw-r--r-- | src/selftest/selftest.cpp | 40 | ||||
-rw-r--r-- | src/stream/stream_cipher.h | 4 |
7 files changed, 172 insertions, 114 deletions
diff --git a/checks/bench.cpp b/checks/bench.cpp index f7ddc5650..96afd7d87 100644 --- a/checks/bench.cpp +++ b/checks/bench.cpp @@ -62,46 +62,23 @@ const std::string algos[] = { "Luby-Rackoff(SHA-512)", /* Cipher modes */ - "TripleDES/CBC/PKCS7", - "TripleDES/CBC/CTS", - "TripleDES/CTR-BE", - "TripleDES/EAX", - "TripleDES/OFB", - "TripleDES/CFB(64)", - "TripleDES/CFB(32)", - "TripleDES/CFB(16)", - "TripleDES/CFB(8)", - "AES-128/CBC/PKCS7", - "AES-128/CBC/CTS", "AES-128/CTR-BE", "AES-128/EAX", "AES-128/OCB", - "AES-128/OFB", + "AES-128/GCM", "AES-128/XTS", - "AES-128/CFB(128)", - "AES-128/CFB(64)", - "AES-128/CFB(32)", - "AES-128/CFB(16)", - "AES-128/CFB(8)", "Serpent/CBC/PKCS7", - "Serpent/CBC/CTS", "Serpent/CTR-BE", "Serpent/EAX", - "Serpent/OFB", + "Serpent/OCB", + "Serpent/GCM", "Serpent/XTS", - "Serpent/CFB(128)", - "Serpent/CFB(64)", - "Serpent/CFB(32)", - "Serpent/CFB(16)", - "Serpent/CFB(8)", /* Stream ciphers */ "ARC4", "Salsa20", - "Turing", - "WiderWake4+1-BE", /* Checksums */ "Adler32", diff --git a/checks/validate.cpp b/checks/validate.cpp index 60fd729e3..7ae2fba29 100644 --- a/checks/validate.cpp +++ b/checks/validate.cpp @@ -442,6 +442,9 @@ bool failed_test(const std::string& algo, if(params.size() > 3) vars["iv"] = params[3]; + if(params.size() > 4) + vars["ad"] = params[4]; + Algorithm_Factory& af = global_state().algorithm_factory(); const auto results = algorithm_kat_detailed(algo, vars, af); diff --git a/checks/validate.dat b/checks/validate.dat index affd59c7c..e7526e817 100644 --- a/checks/validate.dat +++ b/checks/validate.dat @@ -26292,19 +26292,94 @@ C61A0851AB4E515D11525B92E2B9D850:C825FC7C4D539DC74887CECC70884F37 F956B879EC7F807F1FCB482B53623671:E64F90B4619D93137E6237929EABF297 [AES-128/GCM] -#:58E2FCCEFA7E3061367F1D57A4E7455A:\ -#00000000000000000000000000000000:000000000000000000000000 +:58E2FCCEFA7E3061367F1D57A4E7455A:\ +00000000000000000000000000000000:000000000000000000000000 00000000000000000000000000000000:\ 0388DACE60B6A392F328C2B971B2FE78AB6E47D42CEC13BDF53A67B21257BDDF:\ 00000000000000000000000000000000:000000000000000000000000 -#D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A72\ -#1C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B391AAFD255:\ -#42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E\ -#21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091473F5985\ -#4D5C2AF327CD64A62CF35ABD2BA6FAB4:\ -#FEFFE9928665731C6D6A8F9467308308:CAFEBABEFACEDBADDECAF888 +D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A72\ +1C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B391AAFD255:\ +42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E\ +21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091473F5985\ +4D5C2AF327CD64A62CF35ABD2BA6FAB4:\ +FEFFE9928665731C6D6A8F9467308308:CAFEBABEFACEDBADDECAF888 + +D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A72\ +1C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39:\ +42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E\ +21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091\ +5BC94FBC3221A5DB94FAE95AE7121A47:\ +FEFFE9928665731C6D6A8F9467308308:\ +CAFEBABEFACEDBADDECAF888:\ +FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2 + +D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A72\ +1C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39:\ +61353B4C2806934A777FF51FA22A4755699B2A714FCDC6F83766E5F97B6C7423\ +73806900E49F24B22B097544D4896B424989B5E1EBAC0F07C23F4598\ +3612D2E79E3B0785561BE14AACA2FCCB:\ +FEFFE9928665731C6D6A8F9467308308:\ +CAFEBABEFACEDBAD:\ +FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2 + +D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A72\ +1C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39:\ +8CE24998625615B603A033ACA13FB894BE9112A5C3A211A8BA262A3CCA7E2CA7\ +01E4A9A4FBA43C90CCDCB281D48C7C6FD62875D2ACA417034C34AEE5\ +619CC5AEFFFE0BFA462AF43C1699D050:\ +FEFFE9928665731C6D6A8F9467308308:\ +9313225DF88406E555909C5AFF5269AA6A7A9538534F7DA1E4C303D2A318A728\ +C3C0C95156809539FCF0E2429A6B525416AEDBF5A0DE6A57A637B39B:\ +FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2 + +# From Crypto++ 5.6.1 +006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\ +130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\ +006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\ +130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\ +006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\ +130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\ +006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\ +130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\ +006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\ +130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\ +006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\ +130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\ +006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\ +130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\ +006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\ +130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\ +006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\ +130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\ +006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\ +130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\ +006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\ +130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710:\ +BD70C168B0D4371B0A85B4B5D65D92569B17\ +F9A3D0A25B9F608E2C34621CF4D37357845431E04E585CDAAD7527BF8A2426DEEF451320C78D5EF0\ +9F5B11A8B8C700CD329A3D4CDED92C20F6BF28CB3627681C5B0AF2B5692CC7EC9049008ACBBD127A\ +9CD8DEF00425697E0BCF67E05AEE70EA1A5D7EE95E3B88FBAF3C196AAAECB73E09BDF057AF701A02\ +42394BCC104FF4F75F15D287325FCFFDB7E7FF3A939A80A6A3A9D7570E6EF6AD0BBE6E291338938D\ +2FEBBC7D5EE95CD73E752ACD48915DCAE0A0807E6F4B2ADADBD945667318264EF7D8C2ECC0B8FB67\ +A43614C5F5EA51CADD4AEE91DC371A7FC5A3B4581D1D9DD99608CD2BB0338F82933C19F5B8EBAD6B\ +BA583835FBD29136302BAC163F86CA9E3E6F3B5BFDEFAB3E4B019190AE2EBC0B71034EA9BF882879\ +139FFE76DD997F6729425F3D5C5392762C245769D18CC963C92211B71F564203AFBF68626C083303\ +1D449B02DFA5C0F09FAFCE951FE35F4AD8122AB682A4AF28931113F75615E12DB05DD9247973F1C6\ +057666848C13EDE41192F38948366D468D84CAF896EFF724082D2BAB2376E2813B41A014999B0EE7\ +377758715D9554926AB3514EEB96A0ABD501D94A05692D858190D5AD307CEB6E6C8A63841A8257BE\ +C2527C4B937840AA51292E15834AB801F0275A6A4B1B6E969B7A7FCE217D6F823CDE1760F847E8F4\ +6CBDE152A24F2319EC2A7089D2954259D30332089FF928034391D1B0B8AFD7C8A5D4F8E0DAB5883C\ +A7D581F78E4848DC3B01E5F2A5C01BA8910D0F144BC494E29450271174B866868EE8DC6B0DD396ED\ +9D72F83DE3BB6DE6FEBC64178961E011D0D746C2CE3A0FBD05CDF8FA79AC03E94C88368BD903E142\ +7FCFC30C9D100E220B4CB9B7BA242DA49D334E930B6C4EB877D1DF2C0F8CF4AF7813E2F295929707\ +19846FC52A47FCE6E71DC5E58FC5F49C91BDE56B7A2A68CFA994D6BFA5357A8403A2B37C69A6A0A4\ +35E4AB4C9E450473AF0CDFDBCC238A2DD7\ +4FEA89D75727E82B3A9F9EEB5E217A3E:\ +2B7E151628AED2A6ABF7158809CF4F3C:\ +F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF + [AES-128/XTS] # Vectors are from IEEE P1619 D11 diff --git a/src/filters/modes/gcm/gcm.cpp b/src/filters/modes/gcm/gcm.cpp index c88a90cdf..527310069 100644 --- a/src/filters/modes/gcm/gcm.cpp +++ b/src/filters/modes/gcm/gcm.cpp @@ -10,64 +10,45 @@ #include <botan/internal/xor_buf.h> #include <botan/loadstor.h> -#include <iostream> -#include <botan/hex.h> - namespace Botan { -void dump(const std::string& name, const byte x[], size_t x_len) - { - std::cout << name << " = " << hex_encode(x, x_len) << "\n"; - } - -void dump(const std::string& name, const secure_vector<byte>& x) - { - dump(name, &x[0], x.size()); - } - -bool rightshift(secure_vector<byte>& x) - { - byte carry = 0; - - for(size_t i = 0; i != x.size(); ++i) - { - byte carry2 = x[i] & 1; - x[i] = (x[i] >> 1) | (carry << 7); - carry = carry2; - } - - return carry; - } - -bool get_bit(const secure_vector<byte>& x, size_t bit) - { - const byte b = x[16 - (bit / 8)]; - - return (b >> (bit % 8)) & 0x01; - } - secure_vector<byte> gcm_multiply(const secure_vector<byte>& x, const secure_vector<byte>& y) { - secure_vector<byte> z(x.size()); - secure_vector<byte> v = x; + static const u64bit R = 0xE100000000000000; + + u64bit V[2] = { + load_be<u64bit>(&y[0], 0), + load_be<u64bit>(&y[0], 1) + }; + + u64bit Z[2] = { 0, 0 }; - for(size_t i = 0; i != 128; ++i) + for(size_t i = 0; i != 2; ++i) { - if(get_bit(y, i)) - z ^= v; + u64bit X = load_be<u64bit>(&x[0], i); - const bool highbit = get_bit(v, 127); + for(size_t j = 0; j != 64; ++j) + { + if(X >> 63) + { + Z[0] ^= V[0]; + Z[1] ^= V[1]; + } - const bool carry = rightshift(v); - BOTAN_ASSERT(carry == highbit, "That makes sense"); + const u64bit r = (V[1] & 1) ? R : 0; - if(highbit) - v[0] ^= 0xE1; + V[1] = (V[0] << 63) | (V[1] >> 1); + V[0] = (V[0] >> 1) ^ r; + + X <<= 1; + } } - return z; + secure_vector<byte> out(16); + store_be<u64bit>(&out[0], Z[0], Z[1]); + return out; } void ghash_update(const secure_vector<byte>& H, @@ -76,10 +57,6 @@ void ghash_update(const secure_vector<byte>& H, { const size_t BS = 16; - dump("H", H); - - dump("ghash-in", ghash); - /* This assumes if less than block size input then we're just on the final block and should pad with zeros @@ -88,14 +65,10 @@ void ghash_update(const secure_vector<byte>& H, { const size_t to_proc = std::min(length, BS); - dump("input", input, to_proc); - xor_buf(&ghash[0], &input[0], to_proc); ghash = gcm_multiply(ghash, H); - dump("X", ghash); - input += to_proc; length -= to_proc; } @@ -107,9 +80,7 @@ void ghash_finalize(const secure_vector<byte>& H, { secure_vector<byte> final_block(16); store_be<u64bit>(&final_block[0], 8*ad_len, 8*text_len); - dump("lens", final_block); ghash_update(H, ghash, &final_block[0], final_block.size()); - dump("final ghash", ghash); } /* @@ -118,10 +89,14 @@ void ghash_finalize(const secure_vector<byte>& H, GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting) : Buffered_Filter(cipher->parallel_bytes(), decrypting ? tag_size : 0), m_tag_size(tag_size), m_cipher_name(cipher->name()), - m_H(16), m_H_ad(16), m_H_current(16), + m_H(16), m_H_ad(16), m_mac(16), m_ad_len(0), m_text_len(0), m_ctr_buf(8 * cipher->parallel_bytes()) { + if(cipher->block_size() != BS) + throw std::invalid_argument("OCB requires a 128 bit cipher so cannot be used with " + + cipher->name()); + m_ctr.reset(new CTR_BE(cipher)); // CTR_BE takes ownership of cipher if(m_tag_size < 8 || m_tag_size > 16) @@ -142,7 +117,7 @@ void GCM_Mode::set_key(const SymmetricKey& key) { m_ctr->set_key(key); - const std::vector<byte> zeros(16); + const std::vector<byte> zeros(BS); m_ctr->set_iv(&zeros[0], zeros.size()); zeroise(m_H); @@ -165,7 +140,7 @@ void GCM_Mode::set_associated_data(const byte ad[], size_t ad_len) */ void GCM_Mode::set_nonce(const byte nonce[], size_t nonce_len) { - secure_vector<byte> y0(16); + secure_vector<byte> y0(BS); if(nonce_len == 12) { @@ -180,8 +155,8 @@ void GCM_Mode::set_nonce(const byte nonce[], size_t nonce_len) m_ctr->set_iv(&y0[0], y0.size()); - m_y0_cipher.resize(16); - m_ctr->cipher(&m_y0_cipher[0], &m_y0_cipher[0], m_y0_cipher.size()); + m_enc_y0.resize(BS); + m_ctr->encipher(m_enc_y0); } /* @@ -190,7 +165,7 @@ void GCM_Mode::set_nonce(const byte nonce[], size_t nonce_len) void GCM_Mode::start_msg() { m_text_len = 0; - m_H_current = m_H_ad; + m_mac = m_H_ad; } /* @@ -218,7 +193,7 @@ void GCM_Encryption::buffered_block(const byte input[], size_t length) size_t copied = std::min<size_t>(length, m_ctr_buf.size()); m_ctr->cipher(input, &m_ctr_buf[0], copied); - ghash_update(m_H, m_H_current, &m_ctr_buf[0], copied); + ghash_update(m_H, m_mac, &m_ctr_buf[0], copied); m_text_len += copied; send(m_ctr_buf, copied); @@ -232,11 +207,11 @@ void GCM_Encryption::buffered_final(const byte input[], size_t input_length) { buffered_block(input, input_length); - ghash_finalize(m_H, m_H_current, m_ad_len, m_text_len); + ghash_finalize(m_H, m_mac, m_ad_len, m_text_len); - m_H_current ^= m_y0_cipher; + m_mac ^= m_enc_y0; - send(m_H_current, m_tag_size); + send(m_mac, m_tag_size); } void GCM_Decryption::buffered_block(const byte input[], size_t length) @@ -245,7 +220,7 @@ void GCM_Decryption::buffered_block(const byte input[], size_t length) { size_t copied = std::min<size_t>(length, m_ctr_buf.size()); - ghash_update(m_H, m_H_current, &input[0], copied); + ghash_update(m_H, m_mac, &input[0], copied); m_ctr->cipher(input, &m_ctr_buf[0], copied); m_text_len += copied; @@ -266,11 +241,11 @@ void GCM_Decryption::buffered_final(const byte input[], size_t input_length) if(input_length) // handle any remaining input buffered_block(input, input_length); - ghash_finalize(m_H, m_H_current, m_ad_len, m_text_len); + ghash_finalize(m_H, m_mac, m_ad_len, m_text_len); - m_H_current ^= m_y0_cipher; + m_mac ^= m_enc_y0; - if(!same_mem(&m_H_current[0], included_tag, m_tag_size)) + if(!same_mem(&m_mac[0], included_tag, m_tag_size)) throw Integrity_Failure("GCM tag check failed"); } diff --git a/src/filters/modes/gcm/gcm.h b/src/filters/modes/gcm/gcm.h index 3d00577aa..fa13597ce 100644 --- a/src/filters/modes/gcm/gcm.h +++ b/src/filters/modes/gcm/gcm.h @@ -41,14 +41,16 @@ class BOTAN_DLL GCM_Mode : public AEAD_Mode, protected: GCM_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting); + static const size_t BS = 16; + const size_t m_tag_size; const std::string m_cipher_name; std::unique_ptr<StreamCipher> m_ctr; secure_vector<byte> m_H; secure_vector<byte> m_H_ad; - secure_vector<byte> m_H_current; - secure_vector<byte> m_y0_cipher; + secure_vector<byte> m_mac; + secure_vector<byte> m_enc_y0; size_t m_ad_len, m_text_len; secure_vector<byte> m_ctr_buf; diff --git a/src/selftest/selftest.cpp b/src/selftest/selftest.cpp index 4be0fa4cf..e291a8e9d 100644 --- a/src/selftest/selftest.cpp +++ b/src/selftest/selftest.cpp @@ -1,12 +1,14 @@ /* * Startup Self Tests -* (C) 1999-2007 Jack Lloyd +* (C) 1999-2007,2013 Jack Lloyd * * Distributed under the terms of the Botan license */ #include <botan/selftest.h> #include <botan/filters.h> +#include <botan/aead.h> +#include <botan/hex.h> #include <botan/internal/core_engine.h> #include <botan/internal/stl_util.h> @@ -23,17 +25,24 @@ std::string test_filter_kat(Filter* filter, const std::string& input, const std::string& expected) { - Pipe pipe(new Hex_Decoder, filter, new Hex_Encoder); - pipe.process_msg(input); + try + { + Pipe pipe(new Hex_Decoder, filter, new Hex_Encoder); + pipe.process_msg(input); - const std::string got = pipe.read_all_as_string(); + const std::string got = pipe.read_all_as_string(); - const bool same = (got == expected); + const bool same = (got == expected); - if(same) - return "passed"; - else - return (std::string("got ") + got + " expected " + expected); + if(same) + return "passed"; + else + return (std::string("got ") + got + " expected " + expected); + } + catch(std::exception& e) + { + return std::string("exception ") + e.what(); + } } } @@ -117,6 +126,19 @@ algorithm_kat_detailed(const SCAN_Name& algo_name, else if(!dec->valid_iv_length(0)) throw Invalid_IV_Length(algo, iv.length()); +#if defined(BOTAN_HAS_AEAD) + + if(AEAD_Mode* enc_aead = dynamic_cast<AEAD_Mode*>(enc)) + { + const std::vector<byte> ad = hex_decode(search_map(vars, std::string("ad"))); + + enc_aead->set_associated_data(&ad[0], ad.size()); + + if(AEAD_Mode* dec_aead = dynamic_cast<AEAD_Mode*>(dec)) + dec_aead->set_associated_data(&ad[0], ad.size()); + } +#endif + all_results[provider + " (encrypt)"] = test_filter_kat(enc, input, output); all_results[provider + " (decrypt)"] = test_filter_kat(dec, output, input); } diff --git a/src/stream/stream_cipher.h b/src/stream/stream_cipher.h index 301e71f07..231414589 100644 --- a/src/stream/stream_cipher.h +++ b/src/stream/stream_cipher.h @@ -34,6 +34,10 @@ class BOTAN_DLL StreamCipher : public SymmetricAlgorithm void cipher1(byte buf[], size_t len) { cipher(buf, buf, len); } + template<typename Alloc> + void encipher(std::vector<byte, Alloc>& inout) + { cipher(&inout[0], &inout[0], inout.size()); } + /** * Resync the cipher using the IV * @param iv the initialization vector |