aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--checks/ocb.cpp149
-rw-r--r--doc/relnotes/1_11_5.rst2
-rw-r--r--src/modes/aead/ocb/ocb.cpp3
-rw-r--r--src/modes/aead/ocb/ocb.h2
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<byte> ocb_encrypt(const SymmetricKey& key,
+
+std::vector<byte> ocb_decrypt(const SymmetricKey& key,
const std::vector<byte>& 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<AEAD_Mode> 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<byte> buf(pt, pt+pt_len);
+ secure_vector<byte> buf(ct, ct+ct_len);
ocb.finish(buf, 0);
return unlock(buf);
}
-std::vector<byte> ocb_decrypt(const SymmetricKey& key,
+std::vector<byte> ocb_encrypt(const SymmetricKey& key,
const std::vector<byte>& 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<byte> buf(ct, ct+ct_len);
+ secure_vector<byte> buf(pt, pt+pt_len);
ocb.finish(buf, 0);
+ try
+ {
+ std::vector<byte> 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<byte> 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<byte> empty;
std::vector<byte> N(12);
@@ -99,120 +107,20 @@ void test_ocb_long_filters()
const std::vector<byte> S(i);
N[11] = i;
- const std::vector<byte> C1 = ocb_encrypt(ocb, N, S, S);
- const std::vector<byte> C2 = ocb_encrypt(ocb, N, S, empty);
- const std::vector<byte> 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<byte> 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<byte> empty;
- std::vector<byte> N(12);
- std::vector<byte> C;
-
- for(size_t i = 0; i != 128; ++i)
- {
- const std::vector<byte> S(i);
- N[11] = i;
-
- const std::vector<byte> C1 = ocb_encrypt(key, N, S, S);
- const std::vector<byte> C2 = ocb_encrypt(key, N, S, empty);
- const std::vector<byte> 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<byte> 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<byte> 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<byte> 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
*/