aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorlloyd <[email protected]>2013-03-27 16:10:55 +0000
committerlloyd <[email protected]>2013-03-27 16:10:55 +0000
commite7d24d7884025c2051450a9c9d9ce0f944a8fa4a (patch)
tree1fb4af6e8541c7ee8cef757799fcb73eb56ed339 /src
parent35ac296082030fffde867cbac768815efe271522 (diff)
Add an AEAD_Filter that wraps an AEAD_Mode, plus various bug fixes.
Diffstat (limited to 'src')
-rw-r--r--src/aead/aead.h6
-rw-r--r--src/aead/eax/eax.cpp14
-rw-r--r--src/aead/gcm/gcm.cpp18
-rw-r--r--src/aead/ocb/ocb.cpp35
-rw-r--r--src/engine/core_engine/core_modes.cpp38
-rw-r--r--src/filters/aead_filt/aead_filt.cpp92
-rw-r--r--src/filters/aead_filt/aead_filt.h52
-rw-r--r--src/filters/aead_filt/info.txt6
8 files changed, 210 insertions, 51 deletions
diff --git a/src/aead/aead.h b/src/aead/aead.h
index af6f0e76a..736de85e1 100644
--- a/src/aead/aead.h
+++ b/src/aead/aead.h
@@ -57,6 +57,12 @@ class AEAD_Mode : public SymmetricAlgorithm
*/
virtual secure_vector<byte> start(const byte nonce[], size_t nonce_len) = 0;
+ template<typename Alloc>
+ secure_vector<byte> start_vec(const std::vector<byte, Alloc>& nonce)
+ {
+ return start(&nonce[0], nonce.size());
+ }
+
/**
* Update (encrypt or decrypt) some data. Input must be in size
* update_granularity() byte blocks.
diff --git a/src/aead/eax/eax.cpp b/src/aead/eax/eax.cpp
index 8a7287062..fa0496f42 100644
--- a/src/aead/eax/eax.cpp
+++ b/src/aead/eax/eax.cpp
@@ -119,7 +119,7 @@ void EAX_Encryption::finish(secure_vector<byte>& buffer)
xor_buf(data_mac, m_nonce_mac, data_mac.size());
xor_buf(data_mac, m_ad_mac, data_mac.size());
- buffer += data_mac;
+ buffer += std::make_pair(&data_mac[0], tag_size());
}
void EAX_Decryption::update(secure_vector<byte>& buffer)
@@ -133,15 +133,15 @@ void EAX_Decryption::finish(secure_vector<byte>& buffer)
BOTAN_ASSERT(buffer.size() >= tag_size(),
"Have the tag as part of final input");
- const size_t input_length = buffer.size() - tag_size();
+ const size_t remaining = buffer.size() - tag_size();
- if(input_length) // handle any remaining input
+ if(remaining) // handle any remaining input
{
- m_cmac->update(&buffer[0], buffer.size());
- m_ctr->cipher(&buffer[0], &buffer[0], buffer.size());
+ m_cmac->update(&buffer[0], remaining);
+ m_ctr->cipher(&buffer[0], &buffer[0], remaining);
}
- const byte* included_tag = &buffer[input_length];
+ const byte* included_tag = &buffer[remaining];
secure_vector<byte> mac = m_cmac->final();
mac ^= m_nonce_mac;
@@ -149,6 +149,8 @@ void EAX_Decryption::finish(secure_vector<byte>& buffer)
if(!same_mem(&mac[0], included_tag, tag_size()))
throw Integrity_Failure("EAX tag check failed");
+
+ buffer.resize(remaining);
}
}
diff --git a/src/aead/gcm/gcm.cpp b/src/aead/gcm/gcm.cpp
index 628dcc270..a067d162e 100644
--- a/src/aead/gcm/gcm.cpp
+++ b/src/aead/gcm/gcm.cpp
@@ -27,6 +27,8 @@ gcm_multiply(const secure_vector<byte>& x,
u64bit Z[2] = { 0, 0 };
+ // Both CLMUL and SSE2 versions would be useful
+
for(size_t i = 0; i != 2; ++i)
{
u64bit X = load_be<u64bit>(&x[0], i);
@@ -192,7 +194,7 @@ void GCM_Encryption::finish(secure_vector<byte>& buffer)
m_mac ^= m_enc_y0;
- buffer += m_mac;
+ buffer += std::make_pair(&m_mac[0], tag_size());
}
void GCM_Decryption::update(secure_vector<byte>& buffer)
@@ -207,22 +209,26 @@ void GCM_Decryption::finish(secure_vector<byte>& buffer)
BOTAN_ASSERT(buffer.size() >= tag_size(),
"Have the tag as part of final input");
+ const size_t remaining = buffer.size() - tag_size();
+
// handle any final input before the tag
- if(size_t input_length = buffer.size() - tag_size())
+ if(remaining)
{
- ghash_update(m_H, m_mac, &buffer[0], input_length);
- m_ctr->cipher(&buffer[0], &buffer[0], input_length);
- m_text_len += input_length;
+ ghash_update(m_H, m_mac, &buffer[0], remaining);
+ m_ctr->cipher(&buffer[0], &buffer[0], remaining);
+ m_text_len += remaining;
}
ghash_finalize(m_H, m_mac, m_ad_len, m_text_len);
m_mac ^= m_enc_y0;
- const byte* included_tag = &buffer[buffer.size() - tag_size()];
+ const byte* included_tag = &buffer[remaining];
if(!same_mem(&m_mac[0], included_tag, tag_size()))
throw Integrity_Failure("GCM tag check failed");
+
+ buffer.resize(remaining);
}
}
diff --git a/src/aead/ocb/ocb.cpp b/src/aead/ocb/ocb.cpp
index 5bd42766f..50b33960f 100644
--- a/src/aead/ocb/ocb.cpp
+++ b/src/aead/ocb/ocb.cpp
@@ -11,9 +11,6 @@
#include <botan/internal/bit_ops.h>
#include <algorithm>
-#include <botan/hex.h>
-#include <iostream>
-
namespace Botan {
// Has to be in Botan namespace so unique_ptr can reference it
@@ -377,33 +374,34 @@ void OCB_Decryption::finish(secure_vector<byte>& buffer)
{
BOTAN_ASSERT(buffer.size() >= tag_size(), "We have the tag");
- if(const size_t remaining_ctext = buffer.size() - tag_size())
+ const size_t remaining = buffer.size() - tag_size();
+
+ if(remaining)
{
- const size_t final_full_blocks = remaining_ctext / BS;
- const size_t remainder_bytes = remaining_ctext - (final_full_blocks * BS);
+ const size_t final_full_blocks = remaining / BS;
+ const size_t final_bytes = remaining - (final_full_blocks * BS);
decrypt(&buffer[0], final_full_blocks);
- if(remainder_bytes)
+ if(final_bytes)
{
- BOTAN_ASSERT(remainder_bytes < BS, "Only a partial block left");
+ BOTAN_ASSERT(final_bytes < BS, "Only a partial block left");
- byte* remainder = &buffer[buffer.size() - remainder_bytes];
+ byte* remainder = &buffer[remaining - final_bytes];
m_offset ^= m_L->star(); // Offset_*
secure_vector<byte> pad(BS);
m_cipher->encrypt(m_offset, pad); // P_*
- xor_buf(&remainder[0], &pad[0], remainder_bytes);
+ xor_buf(&remainder[0], &pad[0], final_bytes);
- xor_buf(&m_checksum[0], &remainder[0], remainder_bytes);
- m_checksum[remainder_bytes] ^= 0x80;
+ xor_buf(&m_checksum[0], &remainder[0], final_bytes);
+ m_checksum[final_bytes] ^= 0x80;
}
}
- const byte* included_tag = &buffer[buffer.size() - tag_size()];
-
+ // compute the mac
secure_vector<byte> mac = m_offset;
mac ^= m_checksum;
mac ^= m_L->dollar();
@@ -412,12 +410,19 @@ void OCB_Decryption::finish(secure_vector<byte>& buffer)
mac ^= m_ad_hash;
+ // reset state
zeroise(m_checksum);
zeroise(m_offset);
m_block_index = 0;
- if(!same_mem(&mac[0], included_tag, m_tag_size))
+ // compare mac
+ const byte* included_tag = &buffer[remaining];
+
+ if(!same_mem(&mac[0], included_tag, tag_size()))
throw Integrity_Failure("OCB tag check failed");
+
+ // remove tag from end of message
+ buffer.resize(remaining);
}
}
diff --git a/src/engine/core_engine/core_modes.cpp b/src/engine/core_engine/core_modes.cpp
index b30097eaa..588c5d7a2 100644
--- a/src/engine/core_engine/core_modes.cpp
+++ b/src/engine/core_engine/core_modes.cpp
@@ -36,20 +36,26 @@
#include <botan/ctr.h>
#endif
-#if defined(BOTAN_HAS_EAX)
+#if defined(BOTAN_HAS_XTS)
+ #include <botan/xts.h>
+#endif
+
+#if defined(BOTAN_HAS_AEAD_FILTER)
+
+#include <botan/aead_filt.h>
+
+#if defined(BOTAN_HAS_AEAD_EAX)
#include <botan/eax.h>
#endif
-#if defined(BOTAN_HAS_OCB)
+#if defined(BOTAN_HAS_AEAD_OCB)
#include <botan/ocb.h>
#endif
-#if defined(BOTAN_HAS_GCM)
+#if defined(BOTAN_HAS_AEAD_GCM)
#include <botan/gcm.h>
#endif
-#if defined(BOTAN_HAS_XTS)
- #include <botan/xts.h>
#endif
namespace Botan {
@@ -135,26 +141,30 @@ Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher,
#endif
}
-#if defined(BOTAN_HAS_OCB)
+#if defined(BOTAN_HAS_AEAD_FILTER)
+
+#if defined(BOTAN_HAS_AEAD_OCB)
if(mode == "OCB")
{
if(direction == ENCRYPTION)
- return new OCB_Encryption(block_cipher->clone(), 16);
+ return new AEAD_Filter(new OCB_Encryption(block_cipher->clone(), 16));
else
- return new OCB_Decryption(block_cipher->clone(), 16);
+ return new AEAD_Filter(new OCB_Decryption(block_cipher->clone(), 16));
}
#endif
-#if defined(BOTAN_HAS_GCM)
+#if defined(BOTAN_HAS_AEAD_GCM)
if(mode == "GCM")
{
if(direction == ENCRYPTION)
- return new GCM_Encryption(block_cipher->clone(), 16);
+ return new AEAD_Filter(new GCM_Encryption(block_cipher->clone(), 16));
else
- return new GCM_Decryption(block_cipher->clone(), 16);
+ return new AEAD_Filter(new GCM_Decryption(block_cipher->clone(), 16));
}
#endif
+#endif
+
#if defined(BOTAN_HAS_XTS)
if(mode == "XTS")
{
@@ -189,13 +199,13 @@ Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher,
}
#endif
-#if defined(BOTAN_HAS_EAX)
+#if defined(BOTAN_HAS_AEAD_EAX)
if(mode_name == "EAX")
{
if(direction == ENCRYPTION)
- return new EAX_Encryption(block_cipher->clone(), bits);
+ return new AEAD_Filter(new EAX_Encryption(block_cipher->clone(), bits / 8));
else
- return new EAX_Decryption(block_cipher->clone(), bits);
+ return new AEAD_Filter(new EAX_Decryption(block_cipher->clone(), bits / 8));
}
#endif
}
diff --git a/src/filters/aead_filt/aead_filt.cpp b/src/filters/aead_filt/aead_filt.cpp
new file mode 100644
index 000000000..a3c465a8f
--- /dev/null
+++ b/src/filters/aead_filt/aead_filt.cpp
@@ -0,0 +1,92 @@
+/*
+* Filter interface for AEAD modes
+* (C) 2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/aead_filt.h>
+
+namespace Botan {
+
+AEAD_Filter::AEAD_Filter(AEAD_Mode* aead) :
+ Buffered_Filter(aead->update_granularity(),
+ aead->minimum_final_size()),
+ m_aead(aead)
+ {
+ }
+
+std::string AEAD_Filter::name() const
+ {
+ return m_aead->name();
+ }
+
+void AEAD_Filter::Nonce_State::update(const InitializationVector& iv)
+ {
+ m_nonce = unlock(iv.bits_of());
+ m_fresh_nonce = true;
+ }
+
+std::vector<byte> AEAD_Filter::Nonce_State::get()
+ {
+ BOTAN_ASSERT(m_fresh_nonce, "The nonce is fresh for this message");
+
+ m_fresh_nonce = false;
+ return m_nonce;
+ }
+
+void AEAD_Filter::set_associated_data(const byte ad[], size_t ad_len)
+ {
+ m_aead->set_associated_data(ad, ad_len);
+ }
+
+void AEAD_Filter::set_iv(const InitializationVector& iv)
+ {
+ m_nonce.update(iv);
+ }
+
+void AEAD_Filter::set_key(const SymmetricKey& key)
+ {
+ m_aead->set_key(key);
+ }
+
+Key_Length_Specification AEAD_Filter::key_spec() const
+ {
+ return m_aead->key_spec();
+ }
+
+bool AEAD_Filter::valid_iv_length(size_t length) const
+ {
+ return m_aead->valid_nonce_length(length);
+ }
+
+void AEAD_Filter::write(const byte input[], size_t input_length)
+ {
+ Buffered_Filter::write(input, input_length);
+ }
+
+void AEAD_Filter::end_msg()
+ {
+ Buffered_Filter::end_msg();
+ }
+
+void AEAD_Filter::start_msg()
+ {
+ send(m_aead->start_vec(m_nonce.get()));
+ }
+
+void AEAD_Filter::buffered_block(const byte input[], size_t input_length)
+ {
+ secure_vector<byte> buf(input, input + input_length);
+ m_aead->update(buf);
+ send(buf);
+ }
+
+void AEAD_Filter::buffered_final(const byte input[], size_t input_length)
+ {
+ secure_vector<byte> buf(input, input + input_length);
+ m_aead->finish(buf);
+ send(buf);
+ }
+
+}
diff --git a/src/filters/aead_filt/aead_filt.h b/src/filters/aead_filt/aead_filt.h
index 77818c17e..590a60655 100644
--- a/src/filters/aead_filt/aead_filt.h
+++ b/src/filters/aead_filt/aead_filt.h
@@ -1,20 +1,29 @@
/*
-* Interface for AEAD modes
+* Filter interface for AEAD modes
* (C) 2013 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
-#ifndef BOTAN_AEAD_H__
-#define BOTAN_AEAD_H__
+#ifndef BOTAN_AEAD_FILTER_H__
+#define BOTAN_AEAD_FILTER_H__
#include <botan/key_filt.h>
+#include <botan/buf_filt.h>
+#include <botan/aead.h>
+#include <memory>
namespace Botan {
-class BOTAN_DLL AEAD_Filter : public Keyed_Filter
+/**
+* Filter interface for AEAD modes like EAX and GCM
+*/
+class BOTAN_DLL AEAD_Filter : public Keyed_Filter,
+ private Buffered_Filter
{
public:
+ AEAD_Filter(AEAD_Mode* aead);
+
/**
* Set associated data that is not included in the ciphertext but
* that should be authenticated. Must be called after set_key
@@ -23,14 +32,39 @@ class BOTAN_DLL AEAD_Filter : public Keyed_Filter
* @param ad the associated data
* @param ad_len length of add in bytes
*/
- virtual void set_associated_data(const byte ad[], size_t ad_len) = 0;
+ void set_associated_data(const byte ad[], size_t ad_len);
+
+ void set_iv(const InitializationVector& iv) override;
+
+ void set_key(const SymmetricKey& key) override;
+
+ Key_Length_Specification key_spec() const override;
- virtual void set_nonce(const byte nonce[], size_t nonce_len) = 0;
+ bool valid_iv_length(size_t length) const override;
- void set_iv(const InitializationVector& iv) override
+ std::string name() const override;
+
+ private:
+ void write(const byte input[], size_t input_length) override;
+ void start_msg() override;
+ void end_msg() override;
+
+ void buffered_block(const byte input[], size_t input_length) override;
+ void buffered_final(const byte input[], size_t input_length) override;
+
+ class Nonce_State
{
- set_nonce(iv.begin(), iv.length());
- }
+ public:
+ void update(const InitializationVector& iv);
+ std::vector<byte> get();
+ private:
+ bool m_fresh_nonce = false;
+ std::vector<byte> m_nonce;
+ };
+
+ Nonce_State m_nonce;
+ std::unique_ptr<AEAD_Mode> m_aead;
+
};
}
diff --git a/src/filters/aead_filt/info.txt b/src/filters/aead_filt/info.txt
index b43aab2f6..7df9cc619 100644
--- a/src/filters/aead_filt/info.txt
+++ b/src/filters/aead_filt/info.txt
@@ -1 +1,5 @@
-define AEAD
+define AEAD_FILTER
+
+<requires>
+aead
+</requires>