From 7184de2b5dd729bcbf5a6e53feb872cc3c4a1452 Mon Sep 17 00:00:00 2001 From: lloyd Date: Mon, 26 Aug 2013 18:33:42 +0000 Subject: Support 64 and 96 bit tags in OCB, using the nonce formatting rule added in the latest CFRG internet draft. --- checks/ocb.cpp | 149 +++++++++------------------------------------ doc/relnotes/1_11_5.rst | 2 + src/modes/aead/ocb/ocb.cpp | 3 +- src/modes/aead/ocb/ocb.h | 2 +- 4 files changed, 34 insertions(+), 122 deletions(-) diff --git a/checks/ocb.cpp b/checks/ocb.cpp index abd84df7a..5cf6d9296 100644 --- a/checks/ocb.cpp +++ b/checks/ocb.cpp @@ -11,41 +11,51 @@ using namespace Botan; // something like this should be in the library -std::vector ocb_encrypt(const SymmetricKey& key, + +std::vector ocb_decrypt(const SymmetricKey& key, const std::vector& nonce, - const byte pt[], size_t pt_len, + const byte ct[], size_t ct_len, const byte ad[], size_t ad_len) { - //std::unique_ptr ocb = get_aead("AES-128/OCB", ENCRYPTION); - - OCB_Encryption ocb(new AES_128); + OCB_Decryption ocb(new AES_128); ocb.set_key(key); ocb.set_associated_data(ad, ad_len); ocb.start(&nonce[0], nonce.size()); - secure_vector buf(pt, pt+pt_len); + secure_vector buf(ct, ct+ct_len); ocb.finish(buf, 0); return unlock(buf); } -std::vector ocb_decrypt(const SymmetricKey& key, +std::vector ocb_encrypt(const SymmetricKey& key, const std::vector& nonce, - const byte ct[], size_t ct_len, + const byte pt[], size_t pt_len, const byte ad[], size_t ad_len) { - OCB_Decryption ocb(new AES_128); + OCB_Encryption ocb(new AES_128); ocb.set_key(key); ocb.set_associated_data(ad, ad_len); ocb.start(&nonce[0], nonce.size()); - secure_vector buf(ct, ct+ct_len); + secure_vector buf(pt, pt+pt_len); ocb.finish(buf, 0); + try + { + std::vector pt2 = ocb_decrypt(key, nonce, &buf[0], buf.size(), ad, ad_len); + if(pt_len != pt2.size() || !same_mem(pt, &pt2[0], pt_len)) + std::cout << "OCB failed to decrypt correctly\n"; + } + catch(std::exception& e) + { + std::cout << "OCB round trip error - " << e.what() << "\n"; + } + return unlock(buf); } @@ -82,13 +92,11 @@ std::vector ocb_encrypt(OCB_Encryption& ocb, return unlock(buf); } -void test_ocb_long_filters() +void test_ocb_long(size_t taglen, const std::string &expected) { - SymmetricKey key("00000000000000000000000000000000"); + OCB_Encryption ocb(new AES_128, taglen/8); - OCB_Encryption ocb(new AES_128); - - ocb.set_key(key); + ocb.set_key(SymmetricKey("00000000000000000000000000000000")); const std::vector empty; std::vector N(12); @@ -99,120 +107,20 @@ void test_ocb_long_filters() const std::vector S(i); N[11] = i; - const std::vector C1 = ocb_encrypt(ocb, N, S, S); - const std::vector C2 = ocb_encrypt(ocb, N, S, empty); - const std::vector C3 = ocb_encrypt(ocb, N, empty, S); - - //std::cout << "C_" << i << " = " << hex_encode(C1) << " " << hex_encode(C2) << " " << hex_encode(C3) << "\n"; - - C += C1; - C += C2; - C += C3; + C += ocb_encrypt(ocb, N, S, S); + C += ocb_encrypt(ocb, N, S, empty); + C += ocb_encrypt(ocb, N, empty, S); } - SHA_256 sha256; - sha256.update(C); - const std::string C_hash = hex_encode(sha256.final()); - const std::string expected_C_hash = "C4E5158067F49356042296B13B050DE00A120EA846073E5E0DACFD0C9F43CC65"; - - if(C_hash != expected_C_hash) - { - std::cout << "OCB-128 long test, C hashes differ\n"; - std::cout << C_hash << " !=\n" << expected_C_hash << "\n"; - } - - //std::cout << "SHA-256(C) = " << C_hash << "\n"; - N[11] = 0; const std::vector cipher = ocb_encrypt(ocb, N, empty, C); - const std::string expected = "B2B41CBF9B05037DA7F16C24A35C1C94"; - - const std::string cipher_hex = hex_encode(cipher); - - if(cipher_hex != expected) - std::cout << "OCB AES-128 long test mistmatch " << cipher_hex << " != " << expected << "\n"; - else - std::cout << "OCB AES-128 long test OK\n"; - } - -void test_ocb_long() - { - SymmetricKey key("00000000000000000000000000000000"); - - const std::vector empty; - std::vector N(12); - std::vector C; - - for(size_t i = 0; i != 128; ++i) - { - const std::vector S(i); - N[11] = i; - - const std::vector C1 = ocb_encrypt(key, N, S, S); - const std::vector C2 = ocb_encrypt(key, N, S, empty); - const std::vector C3 = ocb_encrypt(key, N, empty, S); - - //std::cout << "C_" << i << " = " << hex_encode(C1) << " " << hex_encode(C2) << " " << hex_encode(C3) << "\n"; - - C += C1; - C += C2; - C += C3; - - SHA_256 sha256; - sha256.update(C); - //std::cout << "SHA-256(C_" << i << ") = " << hex_encode(sha256.final()) << "\n"; - } - - // SHA-256 hash of C would be useful - - SHA_256 sha256; - sha256.update(C); - const std::string C_hash = hex_encode(sha256.final()); - const std::string expected_C_hash = "C4E5158067F49356042296B13B050DE00A120EA846073E5E0DACFD0C9F43CC65"; - - if(C_hash != expected_C_hash) - { - std::cout << "OCB-128 long test, C hashes differ\n"; - std::cout << C_hash << " !=\n" << expected_C_hash << "\n"; - } - - //std::cout << "SHA-256(C) = " << C_hash << "\n"; - - N[11] = 0; - const std::vector cipher = ocb_encrypt(key, N, empty, C); - - const std::string expected = "B2B41CBF9B05037DA7F16C24A35C1C94"; - const std::string cipher_hex = hex_encode(cipher); if(cipher_hex != expected) std::cout << "OCB AES-128 long test mistmatch " << cipher_hex << " != " << expected << "\n"; else std::cout << "OCB AES-128 long test OK\n"; - - try - { - const std::vector p = ocb_decrypt(key, N, cipher, C); - - BOTAN_ASSERT(p.empty(), "return plaintext is empty"); - } - catch(std::exception& e) - { - std::cout << "Error in OCB decrypt - " << e.what() << "\n"; - } - - try - { - C[0] ^= 1; - ocb_decrypt(key, N, cipher, C); - std::cout << "OCB failed to reject bad message\n"; - } - catch(std::exception& e) - { - } - - } void test_ocb() @@ -247,8 +155,9 @@ void test_ocb() std::cout << "Correct OCB message rejected - " << e.what() << "\n"; } - //test_ocb_long(); - test_ocb_long_filters(); + test_ocb_long(128, "B2B41CBF9B05037DA7F16C24A35C1C94"); + test_ocb_long(96, "1A4F0654277709A5BDA0D380"); + test_ocb_long(64, "B7ECE9D381FE437F"); } diff --git a/doc/relnotes/1_11_5.rst b/doc/relnotes/1_11_5.rst index a8125d635..48dea85e5 100644 --- a/doc/relnotes/1_11_5.rst +++ b/doc/relnotes/1_11_5.rst @@ -5,6 +5,8 @@ Version 1.11.5, Not Yet Released processing of messages is now used by all cipher modes. An adaptor filter allows them to be used in a pipe. +* The implementation of OCB mode now supports 64 and 96 bit tags + * Optimized computation of XTS tweaks, producing a substantial speedup * TLS channels now support sending a ``std::vector`` diff --git a/src/modes/aead/ocb/ocb.cpp b/src/modes/aead/ocb/ocb.cpp index 34ea4b9ad..fd66bb2e9 100644 --- a/src/modes/aead/ocb/ocb.cpp +++ b/src/modes/aead/ocb/ocb.cpp @@ -130,7 +130,7 @@ OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size) : throw std::invalid_argument("OCB requires a 128 bit cipher so cannot be used with " + m_cipher->name()); - if(m_tag_size != 16) // fixme: 64, 96 bits also supported + if(m_tag_size != 8 && m_tag_size != 12 && m_tag_size != 16) throw std::invalid_argument("OCB cannot produce a " + std::to_string(m_tag_size) + " byte tag"); @@ -188,6 +188,7 @@ OCB_Mode::update_nonce(const byte nonce[], size_t nonce_len) secure_vector nonce_buf(BS); copy_mem(&nonce_buf[BS - nonce_len], nonce, nonce_len); + nonce_buf[0] = ((tag_size() * 8) % 128) << 1; nonce_buf[BS - nonce_len - 1] = 1; const byte bottom = nonce_buf[15] & 0x3F; diff --git a/src/modes/aead/ocb/ocb.h b/src/modes/aead/ocb/ocb.h index 9eb40e2cf..b4f24f281 100644 --- a/src/modes/aead/ocb/ocb.h +++ b/src/modes/aead/ocb/ocb.h @@ -22,7 +22,7 @@ class L_computer; * that OCB is patented, but is freely licensed in some circumstances. * * @see "The OCB Authenticated-Encryption Algorithm" internet draft - http://tools.ietf.org/html/draft-irtf-cfrg-ocb-01 + http://tools.ietf.org/html/draft-irtf-cfrg-ocb-03 * @see Free Licenses http://www.cs.ucdavis.edu/~rogaway/ocb/license.htm * @see OCB home page http://www.cs.ucdavis.edu/~rogaway/ocb */ -- cgit v1.2.3