aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/aead/aead.h87
-rw-r--r--src/aead/eax/eax.cpp156
-rw-r--r--src/aead/eax/eax.h105
-rw-r--r--src/aead/eax/info.txt (renamed from src/filters/aead/eax/info.txt)2
-rw-r--r--src/aead/gcm/gcm.cpp (renamed from src/filters/aead/gcm/gcm.cpp)139
-rw-r--r--src/aead/gcm/gcm.h100
-rw-r--r--src/aead/gcm/info.txt (renamed from src/filters/aead/gcm/info.txt)2
-rw-r--r--src/aead/info.txt1
-rw-r--r--src/aead/ocb/info.txt (renamed from src/filters/aead/ocb/info.txt)2
-rw-r--r--src/aead/ocb/ocb.cpp (renamed from src/filters/aead/ocb/ocb.cpp)232
-rw-r--r--src/aead/ocb/ocb.h (renamed from src/filters/aead/ocb/ocb.h)57
-rw-r--r--src/engine/core_engine/core_modes.cpp38
-rw-r--r--src/filters/aead/aead_filt.h38
-rw-r--r--src/filters/aead/eax/eax.cpp183
-rw-r--r--src/filters/aead/eax/eax.h130
-rw-r--r--src/filters/aead/gcm/gcm.h101
-rw-r--r--src/filters/aead/info.txt1
-rw-r--r--src/filters/aead_filt/aead_filt.cpp105
-rw-r--r--src/filters/aead_filt/aead_filt.h72
-rw-r--r--src/filters/aead_filt/info.txt5
-rw-r--r--src/selftest/info.txt1
-rw-r--r--src/selftest/selftest.cpp18
-rw-r--r--src/utils/parsing.cpp2
23 files changed, 882 insertions, 695 deletions
diff --git a/src/aead/aead.h b/src/aead/aead.h
new file mode 100644
index 000000000..736de85e1
--- /dev/null
+++ b/src/aead/aead.h
@@ -0,0 +1,87 @@
+/*
+* Interface for AEAD modes
+* (C) 2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_AEAD_MODE_H__
+#define BOTAN_AEAD_MODE_H__
+
+#include <botan/sym_algo.h>
+
+namespace Botan {
+
+/**
+* Interface for AEAD (Authenticated Encryption with Associated Data)
+* modes. These modes provide both encryption and message
+* authentication, and can authenticate additional per-message data
+* which is not included in the ciphertext (for instance a sequence
+* number).
+*/
+class AEAD_Mode : public SymmetricAlgorithm
+ {
+ public:
+ /**
+ * @return size of required blocks to update
+ */
+ virtual size_t update_granularity() const = 0;
+
+ /**
+ * @return required minimium size to finalize() - may be any
+ * length larger than this.
+ */
+ virtual size_t minimum_final_size() const = 0;
+
+ /**
+ * Set associated data that is not included in the ciphertext but
+ * that should be authenticated. Must be called after set_key
+ * and before end_msg.
+ *
+ * Unless reset by another call, the associated data is kept
+ * between messages. Thus, if the AD does not change, calling
+ * once (after set_key) is the optimum.
+ *
+ * @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;
+
+ virtual bool valid_nonce_length(size_t) const = 0;
+
+ /**
+ * Begin processing a message.
+ *
+ * @param nonce the per message nonce
+ * @param nonce_len length of nonce
+ */
+ 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.
+ * @param blocks in/out paramter which will possibly be resized
+ */
+ virtual void update(secure_vector<byte>& blocks) = 0;
+
+ /**
+ * Complete processing of a message. For decryption, may throw an exception
+ * due to authentication failure.
+ *
+ * @param final_block in/out parameter which must be at least
+ * minimum_final_size() bytes, and will be set to any final output
+ */
+ virtual void finish(secure_vector<byte>& final_block) = 0;
+
+ virtual ~AEAD_Mode() {}
+ };
+
+}
+
+#endif
diff --git a/src/aead/eax/eax.cpp b/src/aead/eax/eax.cpp
new file mode 100644
index 000000000..fa0496f42
--- /dev/null
+++ b/src/aead/eax/eax.cpp
@@ -0,0 +1,156 @@
+/*
+* EAX Mode Encryption
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/eax.h>
+#include <botan/cmac.h>
+#include <botan/ctr.h>
+#include <botan/parsing.h>
+#include <botan/internal/xor_buf.h>
+#include <algorithm>
+
+namespace Botan {
+
+namespace {
+
+/*
+* EAX MAC-based PRF
+*/
+secure_vector<byte> eax_prf(byte tag, size_t block_size,
+ MessageAuthenticationCode& mac,
+ const byte in[], size_t length)
+ {
+ for(size_t i = 0; i != block_size - 1; ++i)
+ mac.update(0);
+ mac.update(tag);
+ mac.update(in, length);
+ return mac.final();
+ }
+
+}
+
+/*
+* EAX_Mode Constructor
+*/
+EAX_Mode::EAX_Mode(BlockCipher* cipher, size_t tag_size) :
+ m_tag_size(tag_size),
+ m_cipher(cipher),
+ m_ctr(new CTR_BE(m_cipher->clone())),
+ m_cmac(new CMAC(m_cipher->clone()))
+ {
+ if(tag_size < 8 || tag_size > m_cmac->output_length())
+ throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size));
+ }
+
+void EAX_Mode::clear()
+ {
+ m_cipher.reset();
+ m_ctr.reset();
+ m_cmac.reset();
+ zeroise(m_ad_mac);
+ zeroise(m_nonce_mac);
+ }
+
+std::string EAX_Mode::name() const
+ {
+ return (m_cipher->name() + "/EAX");
+ }
+
+size_t EAX_Mode::update_granularity() const
+ {
+ return 8 * m_cipher->parallel_bytes();
+ }
+
+Key_Length_Specification EAX_Mode::key_spec() const
+ {
+ return m_cipher->key_spec();
+ }
+
+/*
+* Set the EAX key
+*/
+void EAX_Mode::key_schedule(const byte key[], size_t length)
+ {
+ /*
+ * These could share the key schedule, which is one nice part of EAX,
+ * but it's much easier to ignore that here...
+ */
+ m_ctr->set_key(key, length);
+ m_cmac->set_key(key, length);
+
+ m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0);
+ }
+
+/*
+* Set the EAX associated data
+*/
+void EAX_Mode::set_associated_data(const byte ad[], size_t length)
+ {
+ m_ad_mac = eax_prf(1, block_size(), *m_cmac, ad, length);
+ }
+
+secure_vector<byte> EAX_Mode::start(const byte nonce[], size_t nonce_len)
+ {
+ m_nonce_mac = eax_prf(0, block_size(), *m_cmac, nonce, nonce_len);
+
+ m_ctr->set_iv(&m_nonce_mac[0], m_nonce_mac.size());
+
+ for(size_t i = 0; i != block_size() - 1; ++i)
+ m_cmac->update(0);
+ m_cmac->update(2);
+
+ return secure_vector<byte>();
+ }
+
+void EAX_Encryption::update(secure_vector<byte>& buffer)
+ {
+ m_ctr->cipher(&buffer[0], &buffer[0], buffer.size());
+ m_cmac->update(&buffer[0], buffer.size());
+ }
+
+void EAX_Encryption::finish(secure_vector<byte>& buffer)
+ {
+ update(buffer);
+
+ secure_vector<byte> data_mac = m_cmac->final();
+ xor_buf(data_mac, m_nonce_mac, data_mac.size());
+ xor_buf(data_mac, m_ad_mac, data_mac.size());
+
+ buffer += std::make_pair(&data_mac[0], tag_size());
+ }
+
+void EAX_Decryption::update(secure_vector<byte>& buffer)
+ {
+ m_cmac->update(&buffer[0], buffer.size());
+ m_ctr->cipher(&buffer[0], &buffer[0], buffer.size());
+ }
+
+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 remaining = buffer.size() - tag_size();
+
+ if(remaining) // handle any remaining input
+ {
+ m_cmac->update(&buffer[0], remaining);
+ m_ctr->cipher(&buffer[0], &buffer[0], remaining);
+ }
+
+ const byte* included_tag = &buffer[remaining];
+
+ secure_vector<byte> mac = m_cmac->final();
+ mac ^= m_nonce_mac;
+ mac ^= m_ad_mac;
+
+ if(!same_mem(&mac[0], included_tag, tag_size()))
+ throw Integrity_Failure("EAX tag check failed");
+
+ buffer.resize(remaining);
+ }
+
+}
diff --git a/src/aead/eax/eax.h b/src/aead/eax/eax.h
new file mode 100644
index 000000000..f3562f755
--- /dev/null
+++ b/src/aead/eax/eax.h
@@ -0,0 +1,105 @@
+/*
+* EAX Mode
+* (C) 1999-2007,2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_EAX_H__
+#define BOTAN_EAX_H__
+
+#include <botan/aead.h>
+#include <botan/block_cipher.h>
+#include <botan/stream_cipher.h>
+#include <botan/mac.h>
+#include <memory>
+
+namespace Botan {
+
+/**
+* EAX base class
+*/
+class BOTAN_DLL EAX_Mode : public AEAD_Mode
+ {
+ public:
+ secure_vector<byte> start(const byte nonce[], size_t nonce_len) override;
+
+ void set_associated_data(const byte ad[], size_t ad_len) override;
+
+ std::string name() const override;
+
+ size_t update_granularity() const;
+
+ Key_Length_Specification key_spec() const override;
+
+ // EAX supports arbitrary nonce lengths
+ bool valid_nonce_length(size_t) const override { return true; }
+
+ void clear();
+ protected:
+ void key_schedule(const byte key[], size_t length) override;
+
+ /**
+ * @param cipher the cipher to use
+ * @param tag_size is how big the auth tag will be
+ */
+ EAX_Mode(BlockCipher* cipher, size_t tag_size);
+
+ size_t tag_size() const { return m_tag_size; }
+
+ size_t block_size() const { return m_cipher->block_size(); }
+
+ size_t m_tag_size;
+
+ std::unique_ptr<BlockCipher> m_cipher;
+ std::unique_ptr<StreamCipher> m_ctr;
+ std::unique_ptr<MessageAuthenticationCode> m_cmac;
+
+ secure_vector<byte> m_ad_mac;
+
+ secure_vector<byte> m_nonce_mac;
+ };
+
+/**
+* EAX Encryption
+*/
+class BOTAN_DLL EAX_Encryption : public EAX_Mode
+ {
+ public:
+ /**
+ * @param cipher a 128-bit block cipher
+ * @param tag_size is how big the auth tag will be
+ */
+ EAX_Encryption(BlockCipher* cipher, size_t tag_size = 16) :
+ EAX_Mode(cipher, tag_size) {}
+
+ size_t minimum_final_size() const override { return 0; }
+
+ void update(secure_vector<byte>& blocks) override;
+
+ void finish(secure_vector<byte>& final_block) override;
+ };
+
+/**
+* EAX Decryption
+*/
+class BOTAN_DLL EAX_Decryption : public EAX_Mode
+ {
+ public:
+ /**
+ * @param cipher a 128-bit block cipher
+ * @param tag_size is how big the auth tag will be
+ */
+ EAX_Decryption(BlockCipher* cipher, size_t tag_size = 16) :
+ EAX_Mode(cipher, tag_size) {}
+
+ size_t minimum_final_size() const override { return tag_size(); }
+
+ void update(secure_vector<byte>& blocks) override;
+
+ void finish(secure_vector<byte>& final_block) override;
+ };
+
+}
+
+#endif
diff --git a/src/filters/aead/eax/info.txt b/src/aead/eax/info.txt
index 09d92e724..94924e682 100644
--- a/src/filters/aead/eax/info.txt
+++ b/src/aead/eax/info.txt
@@ -1,4 +1,4 @@
-define EAX
+define AEAD_EAX
<requires>
block
diff --git a/src/filters/aead/gcm/gcm.cpp b/src/aead/gcm/gcm.cpp
index 32a763df7..a067d162e 100644
--- a/src/filters/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);
@@ -90,12 +92,11 @@ void ghash_finalize(const secure_vector<byte>& H,
/*
* GCM_Mode Constructor
*/
-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()),
+GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) :
+ m_tag_size(tag_size),
+ m_cipher_name(cipher->name()),
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())
+ m_ad_len(0), m_text_len(0)
{
if(cipher->block_size() != BS)
throw std::invalid_argument("OCB requires a 128 bit cipher so cannot be used with " +
@@ -107,9 +108,35 @@ GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting) :
throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size));
}
-void GCM_Mode::set_key(const SymmetricKey& key)
+void GCM_Mode::clear()
+ {
+ zeroise(m_H);
+ zeroise(m_H_ad);
+ zeroise(m_mac);
+ zeroise(m_enc_y0);
+ m_ad_len = 0;
+ m_text_len = 0;
+ m_ctr.reset();
+ }
+
+std::string GCM_Mode::name() const
+ {
+ return (m_cipher_name + "/GCM");
+ }
+
+size_t GCM_Mode::update_granularity() const
+ {
+ return 4096; // CTR-BE's internal block size
+ }
+
+Key_Length_Specification GCM_Mode::key_spec() const
+ {
+ return m_ctr->key_spec();
+ }
+
+void GCM_Mode::key_schedule(const byte key[], size_t keylen)
{
- m_ctr->set_key(key);
+ m_ctr->set_key(key, keylen);
const std::vector<byte> zeros(BS);
m_ctr->set_iv(&zeros[0], zeros.size());
@@ -118,9 +145,6 @@ void GCM_Mode::set_key(const SymmetricKey& key)
m_ctr->cipher(&m_H[0], &m_H[0], m_H.size());
}
-/*
-* Set the GCM associated data
-*/
void GCM_Mode::set_associated_data(const byte ad[], size_t ad_len)
{
zeroise(m_H_ad);
@@ -129,10 +153,7 @@ void GCM_Mode::set_associated_data(const byte ad[], size_t ad_len)
m_ad_len = ad_len;
}
-/*
-* Set the GCM nonce
-*/
-void GCM_Mode::set_nonce(const byte nonce[], size_t nonce_len)
+secure_vector<byte> GCM_Mode::start(const byte nonce[], size_t nonce_len)
{
secure_vector<byte> y0(BS);
@@ -151,97 +172,63 @@ void GCM_Mode::set_nonce(const byte nonce[], size_t nonce_len)
m_enc_y0.resize(BS);
m_ctr->encipher(m_enc_y0);
- }
-/*
-* Do setup at the start of each message
-*/
-void GCM_Mode::start_msg()
- {
m_text_len = 0;
m_mac = m_H_ad;
- }
-/*
-* Return the name of this cipher mode
-*/
-std::string GCM_Mode::name() const
- {
- return (m_cipher_name + "/GCM");
- }
-
-void GCM_Mode::write(const byte input[], size_t length)
- {
- Buffered_Filter::write(input, length);
+ return secure_vector<byte>();
}
-void GCM_Mode::end_msg()
+void GCM_Encryption::update(secure_vector<byte>& buffer)
{
- Buffered_Filter::end_msg();
+ m_ctr->cipher(&buffer[0], &buffer[0], buffer.size());
+ ghash_update(m_H, m_mac, &buffer[0], buffer.size());
+ m_text_len += buffer.size();
}
-void GCM_Encryption::buffered_block(const byte input[], size_t length)
+void GCM_Encryption::finish(secure_vector<byte>& buffer)
{
- while(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_mac, &m_ctr_buf[0], copied);
- m_text_len += copied;
-
- send(m_ctr_buf, copied);
-
- input += copied;
- length -= copied;
- }
- }
-
-void GCM_Encryption::buffered_final(const byte input[], size_t input_length)
- {
- buffered_block(input, input_length);
+ update(buffer);
ghash_finalize(m_H, m_mac, m_ad_len, m_text_len);
m_mac ^= m_enc_y0;
- send(m_mac, m_tag_size);
+ buffer += std::make_pair(&m_mac[0], tag_size());
}
-void GCM_Decryption::buffered_block(const byte input[], size_t length)
+void GCM_Decryption::update(secure_vector<byte>& buffer)
{
- while(length)
- {
- size_t copied = std::min<size_t>(length, m_ctr_buf.size());
-
- ghash_update(m_H, m_mac, &input[0], copied);
- m_ctr->cipher(input, &m_ctr_buf[0], copied);
- m_text_len += copied;
-
- send(m_ctr_buf, copied);
-
- input += copied;
- length -= copied;
- }
+ ghash_update(m_H, m_mac, &buffer[0], buffer.size());
+ m_ctr->cipher(&buffer[0], &buffer[0], buffer.size());
+ m_text_len += buffer.size();
}
-void GCM_Decryption::buffered_final(const byte input[], size_t input_length)
+void GCM_Decryption::finish(secure_vector<byte>& buffer)
{
- BOTAN_ASSERT(input_length >= m_tag_size, "Have the tag as part of final input");
+ BOTAN_ASSERT(buffer.size() >= tag_size(),
+ "Have the tag as part of final input");
- const byte* included_tag = &input[input_length - m_tag_size];
- input_length -= m_tag_size;
+ const size_t remaining = buffer.size() - tag_size();
- if(input_length) // handle any remaining input
- buffered_block(input, input_length);
+ // handle any final input before the tag
+ if(remaining)
+ {
+ 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;
- if(!same_mem(&m_mac[0], included_tag, m_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/gcm/gcm.h b/src/aead/gcm/gcm.h
new file mode 100644
index 000000000..cf7d94ced
--- /dev/null
+++ b/src/aead/gcm/gcm.h
@@ -0,0 +1,100 @@
+/*
+* GCM Mode
+* (C) 2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_GCM_H__
+#define BOTAN_GCM_H__
+
+#include <botan/aead.h>
+#include <botan/block_cipher.h>
+#include <botan/stream_cipher.h>
+#include <memory>
+
+namespace Botan {
+
+/**
+* GCM Mode
+*/
+class BOTAN_DLL GCM_Mode : public AEAD_Mode
+ {
+ public:
+ secure_vector<byte> start(const byte nonce[], size_t nonce_len) override;
+
+ void set_associated_data(const byte ad[], size_t ad_len) override;
+
+ std::string name() const override;
+
+ size_t update_granularity() const;
+
+ Key_Length_Specification key_spec() const override;
+
+ // GCM supports arbitrary nonce lengths
+ bool valid_nonce_length(size_t) const override { return true; }
+
+ void clear();
+ protected:
+ void key_schedule(const byte key[], size_t length) override;
+
+ GCM_Mode(BlockCipher* cipher, size_t tag_size);
+
+ size_t tag_size() const { return m_tag_size; }
+
+ 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_mac;
+ secure_vector<byte> m_enc_y0;
+ size_t m_ad_len, m_text_len;
+ };
+
+/**
+* GCM Encryption
+*/
+class BOTAN_DLL GCM_Encryption : public GCM_Mode
+ {
+ public:
+ /**
+ * @param cipher the 128 bit block cipher to use
+ * @param tag_size is how big the auth tag will be
+ */
+ GCM_Encryption(BlockCipher* cipher, size_t tag_size = 16) :
+ GCM_Mode(cipher, tag_size) {}
+
+ size_t minimum_final_size() const override { return 0; }
+
+ void update(secure_vector<byte>& blocks) override;
+
+ void finish(secure_vector<byte>& final_block) override;
+ };
+
+/**
+* GCM Decryption
+*/
+class BOTAN_DLL GCM_Decryption : public GCM_Mode
+ {
+ public:
+ /**
+ * @param cipher the 128 bit block cipher to use
+ * @param tag_size is how big the auth tag will be
+ */
+ GCM_Decryption(BlockCipher* cipher, size_t tag_size = 16) :
+ GCM_Mode(cipher, tag_size) {}
+
+ size_t minimum_final_size() const override { return tag_size(); }
+
+ void update(secure_vector<byte>& blocks) override;
+
+ void finish(secure_vector<byte>& final_block) override;
+ };
+
+}
+
+#endif
diff --git a/src/filters/aead/gcm/info.txt b/src/aead/gcm/info.txt
index 52e677a03..698cd0803 100644
--- a/src/filters/aead/gcm/info.txt
+++ b/src/aead/gcm/info.txt
@@ -1,4 +1,4 @@
-define GCM
+define AEAD_GCM
<requires>
block
diff --git a/src/aead/info.txt b/src/aead/info.txt
new file mode 100644
index 000000000..c2985ea85
--- /dev/null
+++ b/src/aead/info.txt
@@ -0,0 +1 @@
+define AEAD_MODES
diff --git a/src/filters/aead/ocb/info.txt b/src/aead/ocb/info.txt
index 0ee41681d..8d6a93ed9 100644
--- a/src/filters/aead/ocb/info.txt
+++ b/src/aead/ocb/info.txt
@@ -1,4 +1,4 @@
-define OCB
+define AEAD_OCB
<requires>
block
diff --git a/src/filters/aead/ocb/ocb.cpp b/src/aead/ocb/ocb.cpp
index eb10b6e9f..50b33960f 100644
--- a/src/filters/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
@@ -59,13 +56,10 @@ class Nonce_State
secure_vector<byte> update_nonce(const byte nonce[],
size_t nonce_len);
-
- bool fresh_nonce() { bool b = false; std::swap(b, m_fresh); return b; }
private:
const BlockCipher& m_cipher;
secure_vector<byte> m_last_nonce;
secure_vector<byte> m_stretch;
- bool m_fresh = false;
};
secure_vector<byte>
@@ -109,7 +103,6 @@ Nonce_State::update_nonce(const byte nonce[], size_t nonce_len)
offset[i] |= (m_stretch[i+shift_bytes+1] >> (8-shift_bits));
}
- m_fresh = true;
return offset;
}
@@ -163,16 +156,16 @@ secure_vector<byte> ocb_hash(const L_computer& L,
}
-OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting) :
- Buffered_Filter(cipher->parallel_bytes(), decrypting ? tag_size : 0),
- m_cipher(cipher), m_tag_size(tag_size),
+OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size) :
+ m_cipher(cipher),
+ m_tag_size(tag_size),
m_ad_hash(BS), m_offset(BS), m_checksum(BS)
{
if(m_cipher->block_size() != BS)
throw std::invalid_argument("OCB requires a 128 bit cipher so cannot be used with " +
m_cipher->name());
- if(m_tag_size != 16) // 64, 96 bits also supported
+ if(m_tag_size != 16) // fixme: 64, 96 bits also supported
throw std::invalid_argument("OCB cannot produce a " + std::to_string(m_tag_size) +
" byte tag");
@@ -180,53 +173,65 @@ OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting) :
OCB_Mode::~OCB_Mode() { /* for unique_ptr destructor */ }
-std::string OCB_Mode::name() const
+void OCB_Mode::clear()
{
- return m_cipher->name() + "/OCB"; // include tag size
+ m_cipher.reset();
+ m_L.reset();
+ zeroise(m_ad_hash);
+ zeroise(m_offset);
+ zeroise(m_checksum);
}
-void OCB_Mode::set_key(const SymmetricKey& key)
+bool OCB_Mode::valid_nonce_length(size_t length) const
{
- m_cipher->set_key(key);
- m_L.reset(new L_computer(*m_cipher));
- m_nonce_state.reset(new Nonce_State(*m_cipher));
+ return (length > 0 && length < 16);
}
-void OCB_Mode::set_nonce(const byte nonce[], size_t nonce_len)
+std::string OCB_Mode::name() const
{
- if(!valid_iv_length(nonce_len))
- throw Invalid_IV_Length(name(), nonce_len);
+ return m_cipher->name() + "/OCB"; // include tag size
+ }
- BOTAN_ASSERT(m_nonce_state, "A key was set");
+size_t OCB_Mode::update_granularity() const
+ {
+ return 8 * m_cipher->parallel_bytes();
+ }
- m_offset = m_nonce_state->update_nonce(nonce, nonce_len);
+Key_Length_Specification OCB_Mode::key_spec() const
+ {
+ return m_cipher->key_spec();
}
-void OCB_Mode::start_msg()
+void OCB_Mode::key_schedule(const byte key[], size_t length)
{
- BOTAN_ASSERT(m_nonce_state->fresh_nonce(), "Nonce state is fresh");
+ m_cipher->set_key(key, length);
+ m_L.reset(new L_computer(*m_cipher));
+ m_nonce_state.reset(new Nonce_State(*m_cipher));
}
void OCB_Mode::set_associated_data(const byte ad[], size_t ad_len)
{
+ BOTAN_ASSERT(m_L, "A key was set");
m_ad_hash = ocb_hash(*m_L, *m_cipher, &ad[0], ad_len);
}
-void OCB_Mode::write(const byte input[], size_t length)
+secure_vector<byte> OCB_Mode::start(const byte nonce[], size_t nonce_len)
{
- Buffered_Filter::write(input, length);
- }
+ if(!valid_nonce_length(nonce_len))
+ throw Invalid_IV_Length(name(), nonce_len);
-void OCB_Mode::end_msg()
- {
- Buffered_Filter::end_msg();
+ BOTAN_ASSERT(m_nonce_state, "A key was set");
+
+ m_offset = m_nonce_state->update_nonce(nonce, nonce_len);
+ zeroise(m_checksum);
+ m_block_index = 0;
+
+ return secure_vector<byte>();
}
-void OCB_Encryption::buffered_block(const byte input[], size_t input_length)
+void OCB_Encryption::encrypt(byte buffer[], size_t blocks)
{
- BOTAN_ASSERT(input_length % BS == 0, "Input length is an even number of blocks");
-
- const size_t blocks = input_length / BS;
+ const L_computer& L = *m_L; // convenient name
const size_t par_bytes = m_cipher->parallel_bytes();
@@ -234,9 +239,6 @@ void OCB_Encryption::buffered_block(const byte input[], size_t input_length)
const size_t par_blocks = par_bytes / BS;
- const L_computer& L = *m_L; // convenient name
-
- secure_vector<byte> ctext_buf(par_bytes);
secure_vector<byte> csum_accum(par_bytes);
secure_vector<byte> offsets(par_bytes);
@@ -244,27 +246,25 @@ void OCB_Encryption::buffered_block(const byte input[], size_t input_length)
while(blocks_left)
{
- const size_t to_proc = std::min(blocks_left, par_blocks);
- const size_t proc_bytes = to_proc * BS;
+ const size_t proc_blocks = std::min(blocks_left, par_blocks);
+ const size_t proc_bytes = proc_blocks * BS;
- xor_buf(&csum_accum[0], &input[0], proc_bytes);
-
- for(size_t i = 0; i != to_proc; ++i)
- {
+ for(size_t i = 0; i != proc_blocks; ++i)
+ { // could be done in parallel
m_offset ^= L(ctz(++m_block_index));
copy_mem(&offsets[BS*i], &m_offset[0], BS);
}
- copy_mem(&ctext_buf[0], &input[0], proc_bytes);
+ xor_buf(&csum_accum[0], &buffer[0], proc_bytes);
- ctext_buf ^= offsets;
- m_cipher->encrypt(ctext_buf);
- ctext_buf ^= offsets;
+ xor_buf(&buffer[0], &offsets[0], proc_bytes);
- send(ctext_buf, proc_bytes);
+ m_cipher->encrypt_n(&buffer[0], &buffer[0], proc_blocks);
- input += proc_bytes;
- blocks_left -= to_proc;
+ xor_buf(&buffer[0], &offsets[0], proc_bytes);
+
+ buffer += proc_bytes;
+ blocks_left -= proc_blocks;
}
// fold into checksum
@@ -272,31 +272,36 @@ void OCB_Encryption::buffered_block(const byte input[], size_t input_length)
m_checksum[i % BS] ^= csum_accum[i];
}
-void OCB_Encryption::buffered_final(const byte input[], size_t input_length)
+void OCB_Encryption::update(secure_vector<byte>& buffer)
{
- if(input_length >= BS)
- {
- const size_t final_blocks = input_length / BS;
- const size_t final_bytes = final_blocks * BS;
- buffered_block(input, final_bytes);
- input += final_bytes;
- input_length -= final_bytes;
- }
+ BOTAN_ASSERT(buffer.size() % BS == 0, "Input length is an even number of blocks");
- if(input_length)
+ encrypt(&buffer[0], buffer.size() / BS);
+ }
+
+void OCB_Encryption::finish(secure_vector<byte>& buffer)
+ {
+ if(!buffer.empty())
{
- BOTAN_ASSERT(input_length < BS, "Only a partial block left");
+ const size_t final_full_blocks = buffer.size() / BS;
+ const size_t remainder_bytes = buffer.size() - (final_full_blocks * BS);
- xor_buf(&m_checksum[0], &input[0], input_length);
- m_checksum[input_length] ^= 0x80;
+ encrypt(&buffer[0], final_full_blocks);
+
+ if(remainder_bytes)
+ {
+ BOTAN_ASSERT(remainder_bytes < BS, "Only a partial block left");
+ byte* remainder = &buffer[buffer.size() - remainder_bytes];
- m_offset ^= m_L->star(); // Offset_*
+ xor_buf(&m_checksum[0], &remainder[0], remainder_bytes);
+ m_checksum[remainder_bytes] ^= 0x80;
- secure_vector<byte> buf(BS);
- m_cipher->encrypt(m_offset, buf);
- xor_buf(&buf[0], &input[0], input_length);
+ m_offset ^= m_L->star(); // Offset_*
- send(buf, input_length); // final ciphertext
+ secure_vector<byte> buf(BS);
+ m_cipher->encrypt(m_offset, buf);
+ xor_buf(&remainder[0], &buf[0], remainder_bytes);
+ }
}
// now compute the tag
@@ -308,18 +313,16 @@ void OCB_Encryption::buffered_final(const byte input[], size_t input_length)
mac ^= m_ad_hash;
- send(mac);
+ buffer += mac;
zeroise(m_checksum);
zeroise(m_offset);
m_block_index = 0;
}
-void OCB_Decryption::buffered_block(const byte input[], size_t input_length)
+void OCB_Decryption::decrypt(byte buffer[], size_t blocks)
{
- BOTAN_ASSERT(input_length % BS == 0, "Input length is an even number of blocks");
-
- const size_t blocks = input_length / BS;
+ const L_computer& L = *m_L; // convenient name
const size_t par_bytes = m_cipher->parallel_bytes();
@@ -327,9 +330,6 @@ void OCB_Decryption::buffered_block(const byte input[], size_t input_length)
const size_t par_blocks = par_bytes / BS;
- const L_computer& L = *m_L; // convenient name
-
- secure_vector<byte> ptext_buf(par_bytes);
secure_vector<byte> csum_accum(par_bytes);
secure_vector<byte> offsets(par_bytes);
@@ -337,27 +337,25 @@ void OCB_Decryption::buffered_block(const byte input[], size_t input_length)
while(blocks_left)
{
- const size_t to_proc = std::min(blocks_left, par_blocks);
- const size_t proc_bytes = to_proc * BS;
+ const size_t proc_blocks = std::min(blocks_left, par_blocks);
+ const size_t proc_bytes = proc_blocks * BS;
- for(size_t i = 0; i != to_proc; ++i)
- {
+ for(size_t i = 0; i != proc_blocks; ++i)
+ { // could be done in parallel
m_offset ^= L(ctz(++m_block_index));
copy_mem(&offsets[BS*i], &m_offset[0], BS);
}
- copy_mem(&ptext_buf[0], &input[0], proc_bytes);
+ xor_buf(&buffer[0], &offsets[0], proc_bytes);
- ptext_buf ^= offsets;
- m_cipher->decrypt(ptext_buf);
- ptext_buf ^= offsets;
+ m_cipher->decrypt_n(&buffer[0], &buffer[0], proc_blocks);
- xor_buf(&csum_accum[0], &ptext_buf[0], proc_bytes);
+ xor_buf(&buffer[0], &offsets[0], proc_bytes);
- send(ptext_buf, proc_bytes);
+ xor_buf(&csum_accum[0], &buffer[0], proc_bytes);
- input += proc_bytes;
- blocks_left -= to_proc;
+ buffer += proc_bytes;
+ blocks_left -= proc_blocks;
}
// fold into checksum
@@ -365,40 +363,45 @@ void OCB_Decryption::buffered_block(const byte input[], size_t input_length)
m_checksum[i % BS] ^= csum_accum[i];
}
-void OCB_Decryption::buffered_final(const byte input[], size_t input_length)
+void OCB_Decryption::update(secure_vector<byte>& buffer)
{
- BOTAN_ASSERT(input_length >= m_tag_size, "We have the tag");
+ BOTAN_ASSERT(buffer.size() % BS == 0, "Input length is an even number of blocks");
+
+ decrypt(&buffer[0], buffer.size() / BS);
+ }
- const byte* included_tag = &input[input_length - m_tag_size];
- input_length -= m_tag_size;
+void OCB_Decryption::finish(secure_vector<byte>& buffer)
+ {
+ BOTAN_ASSERT(buffer.size() >= tag_size(), "We have the tag");
- if(input_length >= BS)
- {
- const size_t final_blocks = input_length / BS;
- const size_t final_bytes = final_blocks * BS;
- buffered_block(input, final_bytes);
- input += final_bytes;
- input_length -= final_bytes;
- }
+ const size_t remaining = buffer.size() - tag_size();
- if(input_length)
+ if(remaining)
{
- BOTAN_ASSERT(input_length < BS, "Only a partial block left");
+ const size_t final_full_blocks = remaining / BS;
+ const size_t final_bytes = remaining - (final_full_blocks * BS);
- m_offset ^= m_L->star(); // Offset_*
+ decrypt(&buffer[0], final_full_blocks);
- secure_vector<byte> buf(BS);
- m_cipher->encrypt(m_offset, buf); // P_*
+ if(final_bytes)
+ {
+ BOTAN_ASSERT(final_bytes < BS, "Only a partial block left");
+
+ byte* remainder = &buffer[remaining - final_bytes];
- xor_buf(&buf[0], &input[0], input_length);
+ m_offset ^= m_L->star(); // Offset_*
- xor_buf(&m_checksum[0], &buf[0], input_length);
- m_checksum[input_length] ^= 0x80;
+ secure_vector<byte> pad(BS);
+ m_cipher->encrypt(m_offset, pad); // P_*
- send(buf, input_length); // final plaintext
+ xor_buf(&remainder[0], &pad[0], final_bytes);
+
+ xor_buf(&m_checksum[0], &remainder[0], final_bytes);
+ m_checksum[final_bytes] ^= 0x80;
+ }
}
- // now compute the tag
+ // compute the mac
secure_vector<byte> mac = m_offset;
mac ^= m_checksum;
mac ^= m_L->dollar();
@@ -407,12 +410,19 @@ void OCB_Decryption::buffered_final(const byte input[], size_t input_length)
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/filters/aead/ocb/ocb.h b/src/aead/ocb/ocb.h
index 0a1cbcaff..9d10c2656 100644
--- a/src/filters/aead/ocb/ocb.h
+++ b/src/aead/ocb/ocb.h
@@ -8,7 +8,7 @@
#ifndef BOTAN_OCB_H__
#define BOTAN_OCB_H__
-#include <botan/aead_filt.h>
+#include <botan/aead.h>
#include <botan/block_cipher.h>
#include <botan/buf_filt.h>
#include <memory>
@@ -27,36 +27,36 @@ class Nonce_State;
* @see Free Licenses http://www.cs.ucdavis.edu/~rogaway/ocb/license.htm
* @see OCB home page http://www.cs.ucdavis.edu/~rogaway/ocb
*/
-class BOTAN_DLL OCB_Mode : public AEAD_Filter,
- private Buffered_Filter
+class BOTAN_DLL OCB_Mode : public AEAD_Mode
{
public:
- void set_key(const SymmetricKey& key) override;
-
- void set_nonce(const byte nonce[], size_t nonce_len) override;
+ secure_vector<byte> start(const byte nonce[], size_t nonce_len) override;
void set_associated_data(const byte ad[], size_t ad_len) override;
- Key_Length_Specification key_spec() const override { return m_cipher->key_spec(); }
-
std::string name() const override;
- bool valid_iv_length(size_t length) const override
- {
- return (length > 0 && length < 16);
- }
+ size_t update_granularity() const;
- ~OCB_Mode();
+ Key_Length_Specification key_spec() const override;
+
+ bool valid_nonce_length(size_t) const override;
+ void clear();
+
+ ~OCB_Mode();
protected:
+ static const size_t BS = 16; // intrinsic to OCB definition
+
/**
* @param cipher the 128-bit block cipher to use
* @param tag_size is how big the auth tag will be
- * @param decrypting true if decrypting
*/
- OCB_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting);
+ OCB_Mode(BlockCipher* cipher, size_t tag_size);
- static const size_t BS = 16; // intrinsic to OCB definition
+ void key_schedule(const byte key[], size_t length) override;
+
+ size_t tag_size() const { return m_tag_size; }
// fixme make these private
std::unique_ptr<BlockCipher> m_cipher;
@@ -68,12 +68,7 @@ class BOTAN_DLL OCB_Mode : public AEAD_Filter,
secure_vector<byte> m_ad_hash;
secure_vector<byte> m_offset;
secure_vector<byte> m_checksum;
-
private:
- void write(const byte input[], size_t input_length) override;
- void start_msg() override;
- void end_msg() override;
-
std::unique_ptr<Nonce_State> m_nonce_state;
};
@@ -85,11 +80,15 @@ class BOTAN_DLL OCB_Encryption : public OCB_Mode
* @param tag_size is how big the auth tag will be
*/
OCB_Encryption(BlockCipher* cipher, size_t tag_size = 16) :
- OCB_Mode(cipher, tag_size, false) {}
+ OCB_Mode(cipher, tag_size) {}
+ size_t minimum_final_size() const override { return 0; }
+
+ void update(secure_vector<byte>& blocks) override;
+
+ void finish(secure_vector<byte>& final_block) override;
private:
- void buffered_block(const byte input[], size_t input_length) override;
- void buffered_final(const byte input[], size_t input_length) override;
+ void encrypt(byte input[], size_t blocks);
};
class BOTAN_DLL OCB_Decryption : public OCB_Mode
@@ -100,11 +99,15 @@ class BOTAN_DLL OCB_Decryption : public OCB_Mode
* @param tag_size is how big the auth tag will be
*/
OCB_Decryption(BlockCipher* cipher, size_t tag_size = 16) :
- OCB_Mode(cipher, tag_size, true) {}
+ OCB_Mode(cipher, tag_size) {}
+
+ size_t minimum_final_size() const override { return tag_size(); }
+
+ void update(secure_vector<byte>& blocks) override;
+ void finish(secure_vector<byte>& final_block) override;
private:
- void buffered_block(const byte input[], size_t input_length) override;
- void buffered_final(const byte input[], size_t input_length) override;
+ void decrypt(byte input[], size_t blocks);
};
}
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/aead_filt.h b/src/filters/aead/aead_filt.h
deleted file mode 100644
index 77818c17e..000000000
--- a/src/filters/aead/aead_filt.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-* Interface for AEAD modes
-* (C) 2013 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_AEAD_H__
-#define BOTAN_AEAD_H__
-
-#include <botan/key_filt.h>
-
-namespace Botan {
-
-class BOTAN_DLL AEAD_Filter : public Keyed_Filter
- {
- public:
- /**
- * Set associated data that is not included in the ciphertext but
- * that should be authenticated. Must be called after set_key
- * and before end_msg.
- *
- * @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;
-
- virtual void set_nonce(const byte nonce[], size_t nonce_len) = 0;
-
- void set_iv(const InitializationVector& iv) override
- {
- set_nonce(iv.begin(), iv.length());
- }
- };
-
-}
-
-#endif
diff --git a/src/filters/aead/eax/eax.cpp b/src/filters/aead/eax/eax.cpp
deleted file mode 100644
index d4a982aaf..000000000
--- a/src/filters/aead/eax/eax.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
-* EAX Mode Encryption
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/eax.h>
-#include <botan/cmac.h>
-#include <botan/ctr.h>
-#include <botan/parsing.h>
-#include <botan/internal/xor_buf.h>
-#include <algorithm>
-
-namespace Botan {
-
-namespace {
-
-/*
-* EAX MAC-based PRF
-*/
-secure_vector<byte> eax_prf(byte tag, size_t BLOCK_SIZE,
- MessageAuthenticationCode& mac,
- const byte in[], size_t length)
- {
- for(size_t i = 0; i != BLOCK_SIZE - 1; ++i)
- mac.update(0);
- mac.update(tag);
- mac.update(in, length);
- return mac.final();
- }
-
-size_t eax_tag_size(size_t tag_size, const BlockCipher& cipher)
- {
- if(tag_size == 0)
- return cipher.block_size();
- return (tag_size / 8);
- }
-
-}
-
-/*
-* EAX_Mode Constructor
-*/
-EAX_Mode::EAX_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting) :
- Buffered_Filter(cipher->parallel_bytes(),
- decrypting ? eax_tag_size(tag_size, *cipher) : 0),
- BLOCK_SIZE(cipher->block_size()),
- TAG_SIZE(eax_tag_size(tag_size, *cipher)),
- cipher_name(cipher->name()),
- ctr_buf(DEFAULT_BUFFERSIZE)
- {
- cmac.reset(new CMAC(cipher->clone()));
- ctr.reset(new CTR_BE(cipher)); // CTR_BE takes ownership of cipher
-
- if(tag_size % 8 != 0 || TAG_SIZE == 0 || TAG_SIZE > cmac->output_length())
- throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size));
- }
-
-/*
-* Set the EAX key
-*/
-void EAX_Mode::set_key(const SymmetricKey& key)
- {
- /*
- * These could share the key schedule, which is one nice part of EAX,
- * but it's much easier to ignore that here...
- */
- ctr->set_key(key);
- cmac->set_key(key);
-
- ad_mac = eax_prf(1, BLOCK_SIZE, *cmac, nullptr, 0);
- }
-
-/*
-* Do setup at the start of each message
-*/
-void EAX_Mode::start_msg()
- {
- for(size_t i = 0; i != BLOCK_SIZE - 1; ++i)
- cmac->update(0);
- cmac->update(2);
- }
-
-/*
-* Set the EAX nonce
-*/
-void EAX_Mode::set_nonce(const byte nonce[], size_t nonce_len)
- {
- nonce_mac = eax_prf(0, BLOCK_SIZE, *cmac, nonce, nonce_len);
- ctr->set_iv(&nonce_mac[0], nonce_mac.size());
- }
-
-/*
-* Set the EAX associated data
-*/
-void EAX_Mode::set_associated_data(const byte ad[], size_t length)
- {
- ad_mac = eax_prf(1, BLOCK_SIZE, *cmac, ad, length);
- }
-
-/*
-* Return the name of this cipher mode
-*/
-std::string EAX_Mode::name() const
- {
- return (cipher_name + "/EAX");
- }
-
-void EAX_Mode::write(const byte input[], size_t length)
- {
- Buffered_Filter::write(input, length);
- }
-
-void EAX_Mode::end_msg()
- {
- Buffered_Filter::end_msg();
- }
-
-void EAX_Encryption::buffered_block(const byte input[], size_t length)
- {
- while(length)
- {
- size_t copied = std::min<size_t>(length, ctr_buf.size());
-
- ctr->cipher(input, &ctr_buf[0], copied);
- cmac->update(&ctr_buf[0], copied);
-
- send(ctr_buf, copied);
-
- input += copied;
- length -= copied;
- }
- }
-
-void EAX_Encryption::buffered_final(const byte input[], size_t input_length)
- {
- buffered_block(input, input_length);
-
- secure_vector<byte> data_mac = cmac->final();
- xor_buf(data_mac, nonce_mac, data_mac.size());
- xor_buf(data_mac, ad_mac, data_mac.size());
-
- send(data_mac, TAG_SIZE);
- }
-
-void EAX_Decryption::buffered_block(const byte input[], size_t length)
- {
- cmac->update(&input[0], length);
-
- while(length)
- {
- size_t copied = std::min<size_t>(length, ctr_buf.size());
-
- ctr->cipher(input, &ctr_buf[0], copied);
-
- send(ctr_buf, copied);
-
- input += copied;
- length -= copied;
- }
- }
-
-void EAX_Decryption::buffered_final(const byte input[], size_t input_length)
- {
- BOTAN_ASSERT(input_length >= TAG_SIZE, "Have the tag as part of final input");
-
- const byte* included_tag = &input[input_length - TAG_SIZE];
- input_length -= TAG_SIZE;
-
- if(input_length) // handle any remaining input
- buffered_block(input, input_length);
-
- secure_vector<byte> mac = cmac->final();
- mac ^= nonce_mac;
- mac ^= ad_mac;
-
- if(!same_mem(&mac[0], included_tag, TAG_SIZE))
- throw Integrity_Failure("EAX tag check failed");
- }
-
-
-}
diff --git a/src/filters/aead/eax/eax.h b/src/filters/aead/eax/eax.h
deleted file mode 100644
index cf99622a1..000000000
--- a/src/filters/aead/eax/eax.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
-* EAX Mode
-* (C) 1999-2007,2013 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_EAX_H__
-#define BOTAN_EAX_H__
-
-#include <botan/aead_filt.h>
-#include <botan/buf_filt.h>
-#include <botan/block_cipher.h>
-#include <botan/stream_cipher.h>
-#include <botan/mac.h>
-#include <memory>
-
-namespace Botan {
-
-/**
-* EAX Mode
-*/
-class BOTAN_DLL EAX_Mode : public AEAD_Filter,
- private Buffered_Filter
- {
- public:
- void set_key(const SymmetricKey& key) override;
-
- void set_nonce(const byte nonce[], size_t nonce_len) override;
-
- void set_associated_data(const byte ad[], size_t ad_len) override;
-
- std::string name() const override;
-
- Key_Length_Specification key_spec() const override { return ctr->key_spec(); }
-
- // EAX supports arbitrary IV lengths
- bool valid_iv_length(size_t) const override { return true; }
- protected:
- /**
- * @param cipher the cipher to use
- * @param tag_size is how big the auth tag will be
- */
- EAX_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting);
-
- void start_msg();
-
- /**
- * The block size of the underlying cipher
- */
- const size_t BLOCK_SIZE;
-
- /**
- * The requested tag name
- */
- const size_t TAG_SIZE;
-
- /**
- * The name of the cipher
- */
- std::string cipher_name;
-
- /**
- * The stream cipher (CTR mode)
- */
- std::unique_ptr<StreamCipher> ctr;
-
- /**
- * The MAC (CMAC)
- */
- std::unique_ptr<MessageAuthenticationCode> cmac;
-
- /**
- * The MAC of the nonce
- */
- secure_vector<byte> nonce_mac;
-
- /**
- * The MAC of the associated data
- */
- secure_vector<byte> ad_mac;
-
- /**
- * A buffer for CTR mode encryption
- */
- secure_vector<byte> ctr_buf;
- private:
- void write(const byte[], size_t);
- void end_msg();
- };
-
-/**
-* EAX Encryption
-*/
-class BOTAN_DLL EAX_Encryption : public EAX_Mode
- {
- public:
- /**
- * @param ciph the cipher to use
- * @param tag_size is how big the auth tag will be
- */
- EAX_Encryption(BlockCipher* ciph, size_t tag_size = 0) :
- EAX_Mode(ciph, tag_size, false) {}
-
- private:
- void buffered_block(const byte input[], size_t input_length) override;
- void buffered_final(const byte input[], size_t input_length) override;
- };
-
-/**
-* EAX Decryption
-*/
-class BOTAN_DLL EAX_Decryption : public EAX_Mode
- {
- public:
- /**
- * @param ciph the cipher to use
- * @param tag_size is how big the auth tag will be
- */
- EAX_Decryption(BlockCipher* cipher, size_t tag_size = 0) :
- EAX_Mode(cipher, tag_size, true) {}
-
- private:
- void buffered_block(const byte input[], size_t input_length) override;
- void buffered_final(const byte input[], size_t input_length) override;
- };
-
-}
-
-#endif
diff --git a/src/filters/aead/gcm/gcm.h b/src/filters/aead/gcm/gcm.h
deleted file mode 100644
index a04a6b8c0..000000000
--- a/src/filters/aead/gcm/gcm.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
-* GCM Mode
-* (C) 2013 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_GCM_H__
-#define BOTAN_GCM_H__
-
-#include <botan/aead_filt.h>
-#include <botan/buf_filt.h>
-#include <botan/block_cipher.h>
-#include <botan/stream_cipher.h>
-#include <memory>
-
-namespace Botan {
-
-/**
-* GCM Mode
-*/
-class BOTAN_DLL GCM_Mode : public AEAD_Filter,
- private Buffered_Filter
- {
- public:
- void set_key(const SymmetricKey& key) override;
-
- void set_nonce(const byte nonce[], size_t nonce_len) override;
-
- /**
- * @note must be called before start_msg or not at all
- */
- void set_associated_data(const byte ad[], size_t ad_len) override;
-
- Key_Length_Specification key_spec() const override { return m_ctr->key_spec(); }
-
- // GCM supports arbitrary IV lengths
- bool valid_iv_length(size_t) const override { return true; }
-
- std::string name() const override;
- 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_mac;
- secure_vector<byte> m_enc_y0;
- size_t m_ad_len, m_text_len;
- secure_vector<byte> m_ctr_buf;
-
- private:
- void write(const byte[], size_t);
- void start_msg();
- void end_msg();
- };
-
-/**
-* GCM Encryption
-*/
-class BOTAN_DLL GCM_Encryption : public GCM_Mode
- {
- public:
- /**
- * @param ciph the cipher to use
- * @param tag_size is how big the auth tag will be
- */
- GCM_Encryption(BlockCipher* ciph, size_t tag_size = 16) :
- GCM_Mode(ciph, tag_size, false) {}
-
- private:
- void buffered_block(const byte input[], size_t input_length) override;
- void buffered_final(const byte input[], size_t input_length) override;
- };
-
-/**
-* GCM Decryption
-*/
-class BOTAN_DLL GCM_Decryption : public GCM_Mode
- {
- public:
- /**
- * @param ciph the cipher to use
- * @param tag_size is how big the auth tag will be
- */
- GCM_Decryption(BlockCipher* cipher, size_t tag_size = 16) :
- GCM_Mode(cipher, tag_size, true) {}
-
- private:
- void buffered_block(const byte input[], size_t input_length) override;
- void buffered_final(const byte input[], size_t input_length) override;
- };
-
-}
-
-#endif
diff --git a/src/filters/aead/info.txt b/src/filters/aead/info.txt
deleted file mode 100644
index b43aab2f6..000000000
--- a/src/filters/aead/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-define AEAD
diff --git a/src/filters/aead_filt/aead_filt.cpp b/src/filters/aead_filt/aead_filt.cpp
new file mode 100644
index 000000000..f70b8eafe
--- /dev/null
+++ b/src/filters/aead_filt/aead_filt.cpp
@@ -0,0 +1,105 @@
+/*
+* 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;
+
+ while(input_length)
+ {
+ const size_t take = std::min(m_aead->update_granularity(), input_length);
+
+ buf.resize(take);
+ copy_mem(&buf[0], input, take);
+
+ m_aead->update(buf);
+
+ send(buf);
+
+ input += take;
+ input_length -= take;
+ }
+ }
+
+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
new file mode 100644
index 000000000..590a60655
--- /dev/null
+++ b/src/filters/aead_filt/aead_filt.h
@@ -0,0 +1,72 @@
+/*
+* Filter interface for AEAD modes
+* (C) 2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#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 {
+
+/**
+* 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
+ * and before end_msg.
+ *
+ * @param ad the associated data
+ * @param ad_len length of add in bytes
+ */
+ 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;
+
+ bool valid_iv_length(size_t length) const 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
+ {
+ 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;
+
+ };
+
+}
+
+#endif
diff --git a/src/filters/aead_filt/info.txt b/src/filters/aead_filt/info.txt
new file mode 100644
index 000000000..7df9cc619
--- /dev/null
+++ b/src/filters/aead_filt/info.txt
@@ -0,0 +1,5 @@
+define AEAD_FILTER
+
+<requires>
+aead
+</requires>
diff --git a/src/selftest/info.txt b/src/selftest/info.txt
index 1a53ea021..e4e9f28dc 100644
--- a/src/selftest/info.txt
+++ b/src/selftest/info.txt
@@ -3,5 +3,6 @@ define SELFTESTS
<requires>
algo_factory
filters
+aead_filt
core_engine
</requires>
diff --git a/src/selftest/selftest.cpp b/src/selftest/selftest.cpp
index 4be4f8751..b989d889d 100644
--- a/src/selftest/selftest.cpp
+++ b/src/selftest/selftest.cpp
@@ -12,8 +12,6 @@
#include <botan/internal/core_engine.h>
#include <botan/internal/stl_util.h>
-#include <iostream>
-
namespace Botan {
namespace {
@@ -126,18 +124,18 @@ 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)
+ const std::vector<byte> ad = hex_decode(search_map(vars, std::string("ad")));
- if(AEAD_Filter* enc_aead = dynamic_cast<AEAD_Filter*>(enc))
+ if(!ad.empty())
{
- const std::vector<byte> ad = hex_decode(search_map(vars, std::string("ad")));
-
- enc_aead->set_associated_data(&ad[0], ad.size());
+ if(AEAD_Filter* enc_aead = dynamic_cast<AEAD_Filter*>(enc))
+ {
+ enc_aead->set_associated_data(&ad[0], ad.size());
- if(AEAD_Filter* dec_aead = dynamic_cast<AEAD_Filter*>(dec))
- dec_aead->set_associated_data(&ad[0], ad.size());
+ if(AEAD_Filter* dec_aead = dynamic_cast<AEAD_Filter*>(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/utils/parsing.cpp b/src/utils/parsing.cpp
index 1e90f2f6e..486f5fdef 100644
--- a/src/utils/parsing.cpp
+++ b/src/utils/parsing.cpp
@@ -14,7 +14,7 @@ namespace Botan {
u32bit to_u32bit(const std::string& str)
{
- return std::stoul(str);
+ return std::stoul(str, nullptr);
}
/*