aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-09-01 13:40:26 -0400
committerJack Lloyd <[email protected]>2016-09-01 14:16:38 -0400
commit507d926da825fbc1d9d74b4517dbab47702c66b9 (patch)
tree22ac0e4a9c85fb3583d478a41ba1c46aeced5ec3
parente4656be6a8e601b64c759906bacf543388b3cf22 (diff)
Cipher_Mode API improvements
The Cipher_Mode::update API is more general than needed to just support ciphers (this is due to it previously being an API of Transform which before 8b85b780515 was Cipher_Mode's base class) Define a less general interface `process` which either processes the blocks in-place, producing exactly as much output as there was input, or (SIV/CCM case) saves the entire message for processing in `finish`. These two uses cover all current or anticipated cipher modes. Leaves `update` for compatability with existing callers; all that is needed is an inline function forwarding to `process`. Removes the return type from `start` - in all cipher implementations, this always returned an empty vector. Adds BOTAN_ARG_CHECK macro; right now BOTAN_ASSERT is being used for argument checking in some places, which is not right at all.
-rw-r--r--doc/manual/aead.rst4
-rw-r--r--src/lib/ffi/ffi.cpp2
-rw-r--r--src/lib/filters/cipher_filter.cpp2
-rw-r--r--src/lib/modes/aead/ccm/ccm.cpp51
-rw-r--r--src/lib/modes/aead/ccm/ccm.h6
-rw-r--r--src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp18
-rw-r--r--src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h6
-rw-r--r--src/lib/modes/aead/eax/eax.cpp20
-rw-r--r--src/lib/modes/aead/eax/eax.h6
-rw-r--r--src/lib/modes/aead/gcm/gcm.cpp63
-rw-r--r--src/lib/modes/aead/gcm/gcm.h6
-rw-r--r--src/lib/modes/aead/ocb/ocb.cpp113
-rw-r--r--src/lib/modes/aead/ocb/ocb.h9
-rw-r--r--src/lib/modes/aead/siv/siv.cpp13
-rw-r--r--src/lib/modes/aead/siv/siv.h4
-rw-r--r--src/lib/modes/cbc/cbc.cpp20
-rw-r--r--src/lib/modes/cbc/cbc.h6
-rw-r--r--src/lib/modes/cfb/cfb.cpp32
-rw-r--r--src/lib/modes/cfb/cfb.h6
-rw-r--r--src/lib/modes/cipher_mode.h48
-rw-r--r--src/lib/modes/ecb/ecb.cpp24
-rw-r--r--src/lib/modes/ecb/ecb.h6
-rw-r--r--src/lib/modes/stream_mode.h11
-rw-r--r--src/lib/modes/xts/xts.cpp20
-rw-r--r--src/lib/modes/xts/xts.h6
-rw-r--r--src/lib/tls/tls_record.cpp11
-rw-r--r--src/lib/utils/assert.h13
-rw-r--r--src/lib/utils/exceptn.h10
28 files changed, 243 insertions, 293 deletions
diff --git a/doc/manual/aead.rst b/doc/manual/aead.rst
index 5ab33c849..d216026bb 100644
--- a/doc/manual/aead.rst
+++ b/doc/manual/aead.rst
@@ -41,8 +41,6 @@ support a 128-bit block cipher such as AES. EAX and SIV also support
Start processing a message, using *nonce* as the unique per-message
value.
- Returns any initial data that should be emitted (for instance a header).
-
.. cpp:function:: void update(secure_vector<byte>& buffer, size_t offset = 0)
Continue processing a message. The *buffer* is an in/out parameter and
@@ -79,7 +77,7 @@ support a 128-bit block cipher such as AES. EAX and SIV also support
.. cpp:function:: size_t update_granularity() const
The AEAD interface requires :cpp:func:`update` be called with blocks of
- this size.
+ this size. This will be 1, if the mode can process any length inputs.
.. cpp:function:: size_t final_minimum_size() const
diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp
index e42f32234..e8df51fec 100644
--- a/src/lib/ffi/ffi.cpp
+++ b/src/lib/ffi/ffi.cpp
@@ -458,7 +458,7 @@ int botan_cipher_start(botan_cipher_t cipher_obj,
try
{
Botan::Cipher_Mode& cipher = safe_get(cipher_obj);
- BOTAN_ASSERT(cipher.start(nonce, nonce_len).empty(), "Ciphers have no prefix");
+ cipher.start(nonce, nonce_len);
cipher_obj->m_buf.reserve(cipher.update_granularity());
return 0;
}
diff --git a/src/lib/filters/cipher_filter.cpp b/src/lib/filters/cipher_filter.cpp
index f91cf3aa2..ed82880aa 100644
--- a/src/lib/filters/cipher_filter.cpp
+++ b/src/lib/filters/cipher_filter.cpp
@@ -85,7 +85,7 @@ void Cipher_Mode_Filter::end_msg()
void Cipher_Mode_Filter::start_msg()
{
- send(m_mode->start(m_nonce.get()));
+ m_mode->start(m_nonce.get());
}
void Cipher_Mode_Filter::buffered_block(const byte input[], size_t input_length)
diff --git a/src/lib/modes/aead/ccm/ccm.cpp b/src/lib/modes/aead/ccm/ccm.cpp
index 1f528769e..d5559bfb5 100644
--- a/src/lib/modes/aead/ccm/ccm.cpp
+++ b/src/lib/modes/aead/ccm/ccm.cpp
@@ -11,6 +11,9 @@
namespace Botan {
+// 128-bit cipher is intrinsic to CCM definition
+static const size_t CCM_BS = 16;
+
/*
* CCM_Mode Constructor
*/
@@ -19,7 +22,7 @@ CCM_Mode::CCM_Mode(BlockCipher* cipher, size_t tag_size, size_t L) :
m_L(L),
m_cipher(cipher)
{
- if(m_cipher->block_size() != BS)
+ if(m_cipher->block_size() != CCM_BS)
throw Invalid_Argument(m_cipher->name() + " cannot be used with CCM mode");
if(L < 2 || L > 8)
@@ -84,30 +87,24 @@ void CCM_Mode::set_associated_data(const byte ad[], size_t length)
m_ad_buf.push_back(get_byte(0, static_cast<u16bit>(length)));
m_ad_buf.push_back(get_byte(1, static_cast<u16bit>(length)));
m_ad_buf += std::make_pair(ad, length);
- while(m_ad_buf.size() % BS)
+ while(m_ad_buf.size() % CCM_BS)
m_ad_buf.push_back(0); // pad with zeros to full block size
}
}
-secure_vector<byte> CCM_Mode::start_raw(const byte nonce[], size_t nonce_len)
+void CCM_Mode::start_msg(const byte nonce[], size_t nonce_len)
{
if(!valid_nonce_length(nonce_len))
throw Invalid_IV_Length(name(), nonce_len);
m_nonce.assign(nonce, nonce + nonce_len);
m_msg_buf.clear();
-
- return secure_vector<byte>();
}
-void CCM_Mode::update(secure_vector<byte>& buffer, size_t offset)
+size_t CCM_Mode::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
- buffer.resize(offset); // truncate msg
+ return 0; // no output until finished
}
void CCM_Mode::encode_length(size_t len, byte out[])
@@ -131,7 +128,7 @@ void CCM_Mode::inc(secure_vector<byte>& C)
secure_vector<byte> CCM_Mode::format_b0(size_t sz)
{
- secure_vector<byte> B0(BS);
+ secure_vector<byte> B0(CCM_BS);
const byte b_flags = (m_ad_buf.size() ? 64 : 0) + (((tag_size()/2)-1) << 3) + (L()-1);
@@ -144,7 +141,7 @@ secure_vector<byte> CCM_Mode::format_b0(size_t sz)
secure_vector<byte> CCM_Mode::format_c0()
{
- secure_vector<byte> C(BS);
+ secure_vector<byte> C(CCM_BS);
const byte a_flags = L()-1;
@@ -164,31 +161,31 @@ void CCM_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
byte* buf = buffer.data() + offset;
const secure_vector<byte>& ad = ad_buf();
- BOTAN_ASSERT(ad.size() % BS == 0, "AD is block size multiple");
+ BOTAN_ASSERT(ad.size() % CCM_BS == 0, "AD is block size multiple");
const BlockCipher& E = cipher();
- secure_vector<byte> T(BS);
+ secure_vector<byte> T(CCM_BS);
E.encrypt(format_b0(sz), T);
- for(size_t i = 0; i != ad.size(); i += BS)
+ for(size_t i = 0; i != ad.size(); i += CCM_BS)
{
- xor_buf(T.data(), &ad[i], BS);
+ xor_buf(T.data(), &ad[i], CCM_BS);
E.encrypt(T);
}
secure_vector<byte> C = format_c0();
- secure_vector<byte> S0(BS);
+ secure_vector<byte> S0(CCM_BS);
E.encrypt(C, S0);
inc(C);
- secure_vector<byte> X(BS);
+ secure_vector<byte> X(CCM_BS);
const byte* buf_end = &buf[sz];
while(buf != buf_end)
{
- const size_t to_proc = std::min<size_t>(BS, buf_end - buf);
+ const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
xor_buf(T.data(), buf, to_proc);
E.encrypt(T);
@@ -217,32 +214,32 @@ void CCM_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
BOTAN_ASSERT(sz >= tag_size(), "We have the tag");
const secure_vector<byte>& ad = ad_buf();
- BOTAN_ASSERT(ad.size() % BS == 0, "AD is block size multiple");
+ BOTAN_ASSERT(ad.size() % CCM_BS == 0, "AD is block size multiple");
const BlockCipher& E = cipher();
- secure_vector<byte> T(BS);
+ secure_vector<byte> T(CCM_BS);
E.encrypt(format_b0(sz - tag_size()), T);
- for(size_t i = 0; i != ad.size(); i += BS)
+ for(size_t i = 0; i != ad.size(); i += CCM_BS)
{
- xor_buf(T.data(), &ad[i], BS);
+ xor_buf(T.data(), &ad[i], CCM_BS);
E.encrypt(T);
}
secure_vector<byte> C = format_c0();
- secure_vector<byte> S0(BS);
+ secure_vector<byte> S0(CCM_BS);
E.encrypt(C, S0);
inc(C);
- secure_vector<byte> X(BS);
+ secure_vector<byte> X(CCM_BS);
const byte* buf_end = &buf[sz - tag_size()];
while(buf != buf_end)
{
- const size_t to_proc = std::min<size_t>(BS, buf_end - buf);
+ const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
E.encrypt(C, X);
xor_buf(buf, X.data(), to_proc);
diff --git a/src/lib/modes/aead/ccm/ccm.h b/src/lib/modes/aead/ccm/ccm.h
index 8277a8f93..7484b500a 100644
--- a/src/lib/modes/aead/ccm/ccm.h
+++ b/src/lib/modes/aead/ccm/ccm.h
@@ -22,7 +22,7 @@ namespace Botan {
class BOTAN_DLL CCM_Mode : public AEAD_Mode
{
public:
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t sz) override;
void set_associated_data(const byte ad[], size_t ad_len) override;
@@ -41,8 +41,6 @@ class BOTAN_DLL CCM_Mode : public AEAD_Mode
size_t tag_size() const override { return m_tag_size; }
protected:
- const size_t BS = 16; // intrinsic to CCM definition
-
CCM_Mode(BlockCipher* cipher, size_t tag_size, size_t L);
size_t L() const { return m_L; }
@@ -60,7 +58,7 @@ class BOTAN_DLL CCM_Mode : public AEAD_Mode
secure_vector<byte> format_b0(size_t msg_size);
secure_vector<byte> format_c0();
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
+ void start_msg(const byte nonce[], size_t nonce_len) override;
void key_schedule(const byte key[], size_t length) override;
diff --git a/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp b/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp
index ca4cc15ed..04326dede 100644
--- a/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp
+++ b/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp
@@ -50,7 +50,7 @@ void ChaCha20Poly1305_Mode::update_len(size_t len)
m_poly1305->update(len8, 8);
}
-secure_vector<byte> ChaCha20Poly1305_Mode::start_raw(const byte nonce[], size_t nonce_len)
+void ChaCha20Poly1305_Mode::start_msg(const byte nonce[], size_t nonce_len)
{
if(!valid_nonce_length(nonce_len))
throw Invalid_IV_Length(name(), nonce_len);
@@ -80,19 +80,14 @@ secure_vector<byte> ChaCha20Poly1305_Mode::start_raw(const byte nonce[], size_t
{
update_len(m_ad.size());
}
-
- return secure_vector<byte>();
}
-void ChaCha20Poly1305_Encryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t ChaCha20Poly1305_Encryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
m_chacha->cipher1(buf, sz);
m_poly1305->update(buf, sz); // poly1305 of ciphertext
m_ctext_len += sz;
+ return sz;
}
void ChaCha20Poly1305_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
@@ -114,15 +109,12 @@ void ChaCha20Poly1305_Encryption::finish(secure_vector<byte>& buffer, size_t off
m_ctext_len = 0;
}
-void ChaCha20Poly1305_Decryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t ChaCha20Poly1305_Decryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
m_poly1305->update(buf, sz); // poly1305 of ciphertext
m_chacha->cipher1(buf, sz);
m_ctext_len += sz;
+ return sz;
}
void ChaCha20Poly1305_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
diff --git a/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h b/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h
index 5aa2dc010..553508854 100644
--- a/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h
+++ b/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h
@@ -50,7 +50,7 @@ class BOTAN_DLL ChaCha20Poly1305_Mode : public AEAD_Mode
bool cfrg_version() const { return m_nonce_len == 12; }
void update_len(size_t len);
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
+ void start_msg(const byte nonce[], size_t nonce_len) override;
void key_schedule(const byte key[], size_t length) override;
};
@@ -66,7 +66,7 @@ class BOTAN_DLL ChaCha20Poly1305_Encryption final : public ChaCha20Poly1305_Mode
size_t minimum_final_size() const override { return 0; }
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
};
@@ -85,7 +85,7 @@ class BOTAN_DLL ChaCha20Poly1305_Decryption final : public ChaCha20Poly1305_Mode
size_t minimum_final_size() const override { return tag_size(); }
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
};
diff --git a/src/lib/modes/aead/eax/eax.cpp b/src/lib/modes/aead/eax/eax.cpp
index 4b928cd31..f26a1eae3 100644
--- a/src/lib/modes/aead/eax/eax.cpp
+++ b/src/lib/modes/aead/eax/eax.cpp
@@ -60,7 +60,7 @@ std::string EAX_Mode::name() const
size_t EAX_Mode::update_granularity() const
{
- return 8 * m_cipher->parallel_bytes();
+ return 1;
}
Key_Length_Specification EAX_Mode::key_spec() const
@@ -91,7 +91,7 @@ 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_raw(const byte nonce[], size_t nonce_len)
+void EAX_Mode::start_msg(const byte nonce[], size_t nonce_len)
{
if(!valid_nonce_length(nonce_len))
throw Invalid_IV_Length(name(), nonce_len);
@@ -103,18 +103,13 @@ secure_vector<byte> EAX_Mode::start_raw(const byte nonce[], size_t nonce_len)
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, size_t offset)
+size_t EAX_Encryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
m_ctr->cipher(buf, buf, sz);
m_cmac->update(buf, sz);
+ return sz;
}
void EAX_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
@@ -128,14 +123,11 @@ void EAX_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
buffer += std::make_pair(data_mac.data(), tag_size());
}
-void EAX_Decryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t EAX_Decryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
m_cmac->update(buf, sz);
m_ctr->cipher(buf, buf, sz);
+ return sz;
}
void EAX_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
diff --git a/src/lib/modes/aead/eax/eax.h b/src/lib/modes/aead/eax/eax.h
index e3d942d5e..0dedefe07 100644
--- a/src/lib/modes/aead/eax/eax.h
+++ b/src/lib/modes/aead/eax/eax.h
@@ -54,7 +54,7 @@ class BOTAN_DLL EAX_Mode : public AEAD_Mode
secure_vector<byte> m_nonce_mac;
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
+ void start_msg(const byte nonce[], size_t nonce_len) override;
void key_schedule(const byte key[], size_t length) override;
};
@@ -77,7 +77,7 @@ class BOTAN_DLL EAX_Encryption final : public EAX_Mode
size_t minimum_final_size() const override { return 0; }
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
};
@@ -103,7 +103,7 @@ class BOTAN_DLL EAX_Decryption final : public EAX_Mode
size_t minimum_final_size() const override { return tag_size(); }
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
};
diff --git a/src/lib/modes/aead/gcm/gcm.cpp b/src/lib/modes/aead/gcm/gcm.cpp
index e23551cb4..78792b79a 100644
--- a/src/lib/modes/aead/gcm/gcm.cpp
+++ b/src/lib/modes/aead/gcm/gcm.cpp
@@ -17,6 +17,8 @@
namespace Botan {
+static const size_t GCM_BS = 16;
+
void GHASH::gcm_multiply(secure_vector<byte>& x) const
{
#if defined(BOTAN_HAS_GCM_CLMUL)
@@ -66,15 +68,13 @@ void GHASH::gcm_multiply(secure_vector<byte>& x) const
void GHASH::ghash_update(secure_vector<byte>& ghash,
const byte input[], size_t length)
{
- const size_t BS = 16;
-
/*
This assumes if less than block size input then we're just on the
final block and should pad with zeros
*/
while(length)
{
- const size_t to_proc = std::min(length, BS);
+ const size_t to_proc = std::min(length, GCM_BS);
xor_buf(ghash.data(), input, to_proc);
@@ -88,7 +88,7 @@ void GHASH::ghash_update(secure_vector<byte>& ghash,
void GHASH::key_schedule(const byte key[], size_t length)
{
m_H.assign(key, key+length);
- m_H_ad.resize(16);
+ m_H_ad.resize(GCM_BS);
m_ad_len = 0;
m_text_len = 0;
}
@@ -109,7 +109,7 @@ void GHASH::set_associated_data(const byte input[], size_t length)
void GHASH::update(const byte input[], size_t length)
{
- BOTAN_ASSERT(m_ghash.size() == 16, "Key was set");
+ BOTAN_ASSERT(m_ghash.size() == GCM_BS, "Key was set");
m_text_len += length;
@@ -119,7 +119,7 @@ void GHASH::update(const byte input[], size_t length)
void GHASH::add_final_block(secure_vector<byte>& hash,
size_t ad_len, size_t text_len)
{
- secure_vector<byte> final_block(16);
+ secure_vector<byte> final_block(GCM_BS);
store_be<u64bit>(final_block.data(), 8*ad_len, 8*text_len);
ghash_update(hash, final_block.data(), final_block.size());
}
@@ -139,7 +139,7 @@ secure_vector<byte> GHASH::final()
secure_vector<byte> GHASH::nonce_hash(const byte nonce[], size_t nonce_len)
{
BOTAN_ASSERT(m_ghash.size() == 0, "nonce_hash called during wrong time");
- secure_vector<byte> y0(16);
+ secure_vector<byte> y0(GCM_BS);
ghash_update(y0, nonce, nonce_len);
add_final_block(y0, 0, nonce_len);
@@ -162,15 +162,14 @@ GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) :
m_tag_size(tag_size),
m_cipher_name(cipher->name())
{
- if(cipher->block_size() != m_BS)
- throw Invalid_Argument("GCM requires a 128 bit cipher so cannot be used with " +
- cipher->name());
+ if(cipher->block_size() != GCM_BS)
+ throw Invalid_Argument("Invalid block cipher for GCM");
m_ghash.reset(new GHASH);
m_ctr.reset(new CTR_BE(cipher, 4)); // CTR_BE takes ownership of cipher
- if(m_tag_size != 8 && m_tag_size != 16)
+ if(m_tag_size != 8 && m_tag_size != GCM_BS)
throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size));
}
@@ -187,7 +186,7 @@ std::string GCM_Mode::name() const
size_t GCM_Mode::update_granularity() const
{
- return m_BS;
+ return GCM_BS;
}
Key_Length_Specification GCM_Mode::key_spec() const
@@ -199,10 +198,10 @@ void GCM_Mode::key_schedule(const byte key[], size_t keylen)
{
m_ctr->set_key(key, keylen);
- const std::vector<byte> zeros(m_BS);
+ const std::vector<byte> zeros(GCM_BS);
m_ctr->set_iv(zeros.data(), zeros.size());
- secure_vector<byte> H(m_BS);
+ secure_vector<byte> H(GCM_BS);
m_ctr->encipher(H);
m_ghash->set_key(H);
}
@@ -212,12 +211,12 @@ void GCM_Mode::set_associated_data(const byte ad[], size_t ad_len)
m_ghash->set_associated_data(ad, ad_len);
}
-secure_vector<byte> GCM_Mode::start_raw(const byte nonce[], size_t nonce_len)
+void GCM_Mode::start_msg(const byte nonce[], size_t nonce_len)
{
if(!valid_nonce_length(nonce_len))
throw Invalid_IV_Length(name(), nonce_len);
- secure_vector<byte> y0(m_BS);
+ secure_vector<byte> y0(GCM_BS);
if(nonce_len == 12)
{
@@ -231,48 +230,48 @@ secure_vector<byte> GCM_Mode::start_raw(const byte nonce[], size_t nonce_len)
m_ctr->set_iv(y0.data(), y0.size());
- secure_vector<byte> m_enc_y0(m_BS);
+ secure_vector<byte> m_enc_y0(GCM_BS);
m_ctr->encipher(m_enc_y0);
m_ghash->start(m_enc_y0.data(), m_enc_y0.size());
-
- return secure_vector<byte>();
}
-void GCM_Encryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t GCM_Encryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
+ BOTAN_ARG_CHECK(sz % update_granularity() == 0);
m_ctr->cipher(buf, buf, sz);
m_ghash->update(buf, sz);
+ return sz;
}
void GCM_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
{
- update(buffer, offset);
+ BOTAN_ARG_CHECK(offset <= buffer.size());
+ const size_t sz = buffer.size() - offset;
+ byte* buf = buffer.data() + offset;
+
+ m_ctr->cipher(buf, buf, sz);
+ m_ghash->update(buf, sz);
auto mac = m_ghash->final();
buffer += std::make_pair(mac.data(), tag_size());
}
-void GCM_Decryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t GCM_Decryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
+ BOTAN_ARG_CHECK(sz % update_granularity() == 0);
m_ghash->update(buf, sz);
m_ctr->cipher(buf, buf, sz);
+ return sz;
}
void GCM_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
+ BOTAN_ARG_CHECK(offset <= buffer.size());
const size_t sz = buffer.size() - offset;
byte* buf = buffer.data() + offset;
- BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input");
+ if(sz < tag_size())
+ throw Exception("Insufficient input for GCM decryption, tag missing");
const size_t remaining = sz - tag_size();
diff --git a/src/lib/modes/aead/gcm/gcm.h b/src/lib/modes/aead/gcm/gcm.h
index ba0d6cad8..0110436b2 100644
--- a/src/lib/modes/aead/gcm/gcm.h
+++ b/src/lib/modes/aead/gcm/gcm.h
@@ -47,7 +47,7 @@ class BOTAN_DLL GCM_Mode : public AEAD_Mode
std::unique_ptr<StreamCipher> m_ctr;
std::unique_ptr<GHASH> m_ghash;
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
+ void start_msg(const byte nonce[], size_t nonce_len) override;
void key_schedule(const byte key[], size_t length) override;
};
@@ -70,7 +70,7 @@ class BOTAN_DLL GCM_Encryption final : public GCM_Mode
size_t minimum_final_size() const override { return 0; }
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
};
@@ -96,7 +96,7 @@ class BOTAN_DLL GCM_Decryption final : public GCM_Mode
size_t minimum_final_size() const override { return tag_size(); }
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
};
diff --git a/src/lib/modes/aead/ocb/ocb.cpp b/src/lib/modes/aead/ocb/ocb.cpp
index 77126ec7a..e21749f3b 100644
--- a/src/lib/modes/aead/ocb/ocb.cpp
+++ b/src/lib/modes/aead/ocb/ocb.cpp
@@ -33,13 +33,12 @@ class L_computer
size_t block_index,
size_t blocks) const
{
- const size_t BS = m_L_star.size();
- m_offset_buf.resize(blocks * BS);
+ m_offset_buf.resize(blocks * 16);
for(size_t i = 0; i != blocks; ++i)
{ // could be done in parallel
offset ^= get(ctz(block_index + 1 + i));
- copy_mem(&m_offset_buf[BS*i], offset.data(), BS);
+ copy_mem(&m_offset_buf[16*i], offset.data(), 16);
}
return m_offset_buf;
@@ -73,15 +72,13 @@ secure_vector<byte> ocb_hash(const L_computer& L,
const BlockCipher& cipher,
const byte ad[], size_t ad_len)
{
- const size_t BS = cipher.block_size();
+ secure_vector<byte> sum(16);
+ secure_vector<byte> offset(16);
- secure_vector<byte> sum(BS);
- secure_vector<byte> offset(BS);
+ secure_vector<byte> buf(16);
- secure_vector<byte> buf(BS);
-
- const size_t ad_blocks = (ad_len / BS);
- const size_t ad_remainder = (ad_len % BS);
+ const size_t ad_blocks = (ad_len / 16);
+ const size_t ad_remainder = (ad_len % 16);
for(size_t i = 0; i != ad_blocks; ++i)
{
@@ -89,7 +86,7 @@ secure_vector<byte> ocb_hash(const L_computer& L,
offset ^= L(ctz(i+1));
buf = offset;
- xor_buf(buf.data(), &ad[BS*i], BS);
+ xor_buf(buf.data(), &ad[16*i], 16);
cipher.encrypt(buf);
@@ -101,8 +98,8 @@ secure_vector<byte> ocb_hash(const L_computer& L,
offset ^= L.star();
buf = offset;
- xor_buf(buf.data(), &ad[BS*ad_blocks], ad_remainder);
- buf[ad_len % BS] ^= 0x80;
+ xor_buf(buf.data(), &ad[16*ad_blocks], ad_remainder);
+ buf[ad_len % 16] ^= 0x80;
cipher.encrypt(buf);
@@ -116,19 +113,16 @@ secure_vector<byte> ocb_hash(const L_computer& L,
OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size) :
m_cipher(cipher),
- m_BS(m_cipher->block_size()),
m_checksum(m_cipher->parallel_bytes()),
- m_offset(m_BS),
- m_ad_hash(m_BS),
+ m_offset(16),
+ m_ad_hash(16),
m_tag_size(tag_size)
{
- if(BS() != 16)
- throw Invalid_Argument("OCB is not compatible with " + m_cipher->name());
-
- if(m_tag_size % 4 != 0 || m_tag_size < 8 || m_tag_size > BS())
- throw Invalid_Argument("OCB cannot produce a " + std::to_string(m_tag_size) +
- " byte tag");
+ if(m_cipher->block_size() != 16)
+ throw Invalid_Argument("OCB requires 128 bit cipher");
+ if(m_tag_size % 4 != 0 || m_tag_size < 8 || m_tag_size > 16)
+ throw Invalid_Argument("Invalid OCB tag length");
}
OCB_Mode::~OCB_Mode() { /* for unique_ptr destructor */ }
@@ -178,16 +172,16 @@ void OCB_Mode::set_associated_data(const byte ad[], size_t ad_len)
secure_vector<byte>
OCB_Mode::update_nonce(const byte nonce[], size_t nonce_len)
{
- BOTAN_ASSERT(nonce_len < BS(), "OCB nonce is less than cipher block size");
+ BOTAN_ASSERT(nonce_len < 16, "OCB nonce is less than cipher block size");
- secure_vector<byte> nonce_buf(BS());
+ secure_vector<byte> nonce_buf(16);
- copy_mem(&nonce_buf[BS() - nonce_len], nonce, nonce_len);
+ copy_mem(&nonce_buf[16 - nonce_len], nonce, nonce_len);
nonce_buf[0] = ((tag_size() * 8) % 128) << 1;
- nonce_buf[BS() - nonce_len - 1] = 1;
+ nonce_buf[16 - nonce_len - 1] = 1;
- const byte bottom = nonce_buf[BS()-1] & 0x3F;
- nonce_buf[BS()-1] &= 0xC0;
+ const byte bottom = nonce_buf[16-1] & 0x3F;
+ nonce_buf[16-1] &= 0xC0;
const bool need_new_stretch = (m_last_nonce != nonce_buf);
@@ -197,7 +191,7 @@ OCB_Mode::update_nonce(const byte nonce[], size_t nonce_len)
m_cipher->encrypt(nonce_buf);
- for(size_t i = 0; i != BS() / 2; ++i)
+ for(size_t i = 0; i != 16 / 2; ++i)
nonce_buf.push_back(nonce_buf[i] ^ nonce_buf[i+1]);
m_stretch = nonce_buf;
@@ -208,8 +202,8 @@ OCB_Mode::update_nonce(const byte nonce[], size_t nonce_len)
const size_t shift_bytes = bottom / 8;
const size_t shift_bits = bottom % 8;
- secure_vector<byte> offset(BS());
- for(size_t i = 0; i != BS(); ++i)
+ secure_vector<byte> offset(16);
+ for(size_t i = 0; i != 16; ++i)
{
offset[i] = (m_stretch[i+shift_bytes] << shift_bits);
offset[i] |= (m_stretch[i+shift_bytes+1] >> (8-shift_bits));
@@ -218,7 +212,7 @@ OCB_Mode::update_nonce(const byte nonce[], size_t nonce_len)
return offset;
}
-secure_vector<byte> OCB_Mode::start_raw(const byte nonce[], size_t nonce_len)
+void OCB_Mode::start_msg(const byte nonce[], size_t nonce_len)
{
if(!valid_nonce_length(nonce_len))
throw Invalid_IV_Length(name(), nonce_len);
@@ -228,18 +222,16 @@ secure_vector<byte> OCB_Mode::start_raw(const byte nonce[], size_t nonce_len)
m_offset = update_nonce(nonce, nonce_len);
zeroise(m_checksum);
m_block_index = 0;
-
- return secure_vector<byte>();
}
void OCB_Encryption::encrypt(byte buffer[], size_t blocks)
{
- const size_t par_blocks = m_checksum.size() / BS();
+ const size_t par_blocks = m_checksum.size() / 16;
while(blocks)
{
const size_t proc_blocks = std::min(blocks, par_blocks);
- const size_t proc_bytes = proc_blocks * BS();
+ const size_t proc_bytes = proc_blocks * 16;
const auto& offsets = m_L->compute_offsets(m_offset, m_block_index, proc_blocks);
@@ -255,14 +247,11 @@ void OCB_Encryption::encrypt(byte buffer[], size_t blocks)
}
}
-void OCB_Encryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t OCB_Encryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
- BOTAN_ASSERT(sz % BS() == 0, "Input length is an even number of blocks");
- encrypt(buf, sz / BS());
+ BOTAN_ASSERT(sz % 16 == 0, "Invalid OCB input size");
+ encrypt(buf, sz / 16);
+ return sz;
}
void OCB_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
@@ -273,14 +262,14 @@ void OCB_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
if(sz)
{
- const size_t final_full_blocks = sz / BS();
- const size_t remainder_bytes = sz - (final_full_blocks * BS());
+ const size_t final_full_blocks = sz / 16;
+ const size_t remainder_bytes = sz - (final_full_blocks * 16);
encrypt(buf, final_full_blocks);
if(remainder_bytes)
{
- BOTAN_ASSERT(remainder_bytes < BS(), "Only a partial block left");
+ BOTAN_ASSERT(remainder_bytes < 16, "Only a partial block left");
byte* remainder = &buf[sz - remainder_bytes];
xor_buf(m_checksum.data(), remainder, remainder_bytes);
@@ -288,13 +277,13 @@ void OCB_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
m_offset ^= m_L->star(); // Offset_*
- secure_vector<byte> zeros(BS());
+ secure_vector<byte> zeros(16);
m_cipher->encrypt(m_offset, zeros);
xor_buf(remainder, zeros.data(), remainder_bytes);
}
}
- secure_vector<byte> checksum(BS());
+ secure_vector<byte> checksum(16);
// fold checksum
for(size_t i = 0; i != m_checksum.size(); ++i)
@@ -320,14 +309,14 @@ void OCB_Decryption::decrypt(byte buffer[], size_t blocks)
{
const size_t par_bytes = m_cipher->parallel_bytes();
- BOTAN_ASSERT(par_bytes % BS() == 0, "Cipher is parallel in full blocks");
+ BOTAN_ASSERT(par_bytes % 16 == 0, "Cipher is parallel in full blocks");
- const size_t par_blocks = par_bytes / BS();
+ const size_t par_blocks = par_bytes / 16;
while(blocks)
{
const size_t proc_blocks = std::min(blocks, par_blocks);
- const size_t proc_bytes = proc_blocks * BS();
+ const size_t proc_bytes = proc_blocks * 16;
const auto& offsets = m_L->compute_offsets(m_offset, m_block_index, proc_blocks);
@@ -343,15 +332,11 @@ void OCB_Decryption::decrypt(byte buffer[], size_t blocks)
}
}
-void OCB_Decryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t OCB_Decryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
- BOTAN_ASSERT(sz % BS() == 0, "Input length is an even number of blocks");
-
- decrypt(buf, sz / BS());
+ BOTAN_ASSERT(sz % 16 == 0, "Invalid OCB input size");
+ decrypt(buf, sz / 16);
+ return sz;
}
void OCB_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
@@ -366,20 +351,20 @@ void OCB_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
if(remaining)
{
- const size_t final_full_blocks = remaining / BS();
- const size_t final_bytes = remaining - (final_full_blocks * BS());
+ const size_t final_full_blocks = remaining / 16;
+ const size_t final_bytes = remaining - (final_full_blocks * 16);
decrypt(buf, final_full_blocks);
if(final_bytes)
{
- BOTAN_ASSERT(final_bytes < BS(), "Only a partial block left");
+ BOTAN_ASSERT(final_bytes < 16, "Only a partial block left");
byte* remainder = &buf[remaining - final_bytes];
m_offset ^= m_L->star(); // Offset_*
- secure_vector<byte> pad(BS());
+ secure_vector<byte> pad(16);
m_cipher->encrypt(m_offset, pad); // P_*
xor_buf(remainder, pad.data(), final_bytes);
@@ -389,7 +374,7 @@ void OCB_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
}
}
- secure_vector<byte> checksum(BS());
+ secure_vector<byte> checksum(16);
// fold checksum
for(size_t i = 0; i != m_checksum.size(); ++i)
diff --git a/src/lib/modes/aead/ocb/ocb.h b/src/lib/modes/aead/ocb/ocb.h
index 92edce970..4daa7a81b 100644
--- a/src/lib/modes/aead/ocb/ocb.h
+++ b/src/lib/modes/aead/ocb/ocb.h
@@ -49,20 +49,17 @@ class BOTAN_DLL OCB_Mode : public AEAD_Mode
*/
OCB_Mode(BlockCipher* cipher, size_t tag_size);
- size_t BS() const { return m_BS; }
-
// fixme make these private
std::unique_ptr<BlockCipher> m_cipher;
std::unique_ptr<L_computer> m_L;
- size_t m_BS;
size_t m_block_index = 0;
secure_vector<byte> m_checksum;
secure_vector<byte> m_offset;
secure_vector<byte> m_ad_hash;
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
+ void start_msg(const byte nonce[], size_t nonce_len) override;
void key_schedule(const byte key[], size_t length) override;
@@ -88,7 +85,7 @@ class BOTAN_DLL OCB_Encryption final : public OCB_Mode
size_t minimum_final_size() const override { return 0; }
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
private:
@@ -113,7 +110,7 @@ class BOTAN_DLL OCB_Decryption final : public OCB_Mode
size_t minimum_final_size() const override { return tag_size(); }
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
private:
diff --git a/src/lib/modes/aead/siv/siv.cpp b/src/lib/modes/aead/siv/siv.cpp
index a4cb65a94..9e638b659 100644
--- a/src/lib/modes/aead/siv/siv.cpp
+++ b/src/lib/modes/aead/siv/siv.cpp
@@ -70,7 +70,7 @@ void SIV_Mode::set_associated_data_n(size_t n, const byte ad[], size_t length)
m_ad_macs[n] = m_cmac->process(ad, length);
}
-secure_vector<byte> SIV_Mode::start_raw(const byte nonce[], size_t nonce_len)
+void SIV_Mode::start_msg(const byte nonce[], size_t nonce_len)
{
if(!valid_nonce_length(nonce_len))
throw Invalid_IV_Length(name(), nonce_len);
@@ -81,18 +81,13 @@ secure_vector<byte> SIV_Mode::start_raw(const byte nonce[], size_t nonce_len)
m_nonce.clear();
m_msg_buf.clear();
-
- return secure_vector<byte>();
}
-void SIV_Mode::update(secure_vector<byte>& buffer, size_t offset)
+size_t SIV_Mode::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
+ // all output is saved for processing in finish
m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
- buffer.resize(offset); // truncate msg
+ return 0;
}
secure_vector<byte> SIV_Mode::S2V(const byte* text, size_t text_len)
diff --git a/src/lib/modes/aead/siv/siv.h b/src/lib/modes/aead/siv/siv.h
index d3e4c5270..6acfe515a 100644
--- a/src/lib/modes/aead/siv/siv.h
+++ b/src/lib/modes/aead/siv/siv.h
@@ -21,7 +21,7 @@ namespace Botan {
class BOTAN_DLL SIV_Mode : public AEAD_Mode
{
public:
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void set_associated_data_n(size_t n, const byte ad[], size_t ad_len);
@@ -53,7 +53,7 @@ class BOTAN_DLL SIV_Mode : public AEAD_Mode
secure_vector<byte> S2V(const byte text[], size_t text_len);
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
+ void start_msg(const byte nonce[], size_t nonce_len) override;
void key_schedule(const byte key[], size_t length) override;
diff --git a/src/lib/modes/cbc/cbc.cpp b/src/lib/modes/cbc/cbc.cpp
index fedeaf20d..8066dae12 100644
--- a/src/lib/modes/cbc/cbc.cpp
+++ b/src/lib/modes/cbc/cbc.cpp
@@ -61,7 +61,7 @@ void CBC_Mode::key_schedule(const byte key[], size_t length)
m_cipher->set_key(key, length);
}
-secure_vector<byte> CBC_Mode::start_raw(const byte nonce[], size_t nonce_len)
+void CBC_Mode::start_msg(const byte nonce[], size_t nonce_len)
{
if(!valid_nonce_length(nonce_len))
throw Invalid_IV_Length(name(), nonce_len);
@@ -73,8 +73,6 @@ secure_vector<byte> CBC_Mode::start_raw(const byte nonce[], size_t nonce_len)
*/
if(nonce_len)
m_state.assign(nonce, nonce + nonce_len);
-
- return secure_vector<byte>();
}
size_t CBC_Encryption::minimum_final_size() const
@@ -90,12 +88,8 @@ size_t CBC_Encryption::output_length(size_t input_length) const
return round_up(input_length, cipher().block_size());
}
-void CBC_Encryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t CBC_Encryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
const size_t BS = cipher().block_size();
BOTAN_ASSERT(sz % BS == 0, "CBC input is full blocks");
@@ -114,6 +108,8 @@ void CBC_Encryption::update(secure_vector<byte>& buffer, size_t offset)
state().assign(&buf[BS*(blocks-1)], &buf[BS*blocks]);
}
+
+ return sz;
}
void CBC_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
@@ -201,12 +197,8 @@ size_t CBC_Decryption::minimum_final_size() const
return cipher().block_size();
}
-void CBC_Decryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t CBC_Decryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
const size_t BS = cipher().block_size();
BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
@@ -227,6 +219,8 @@ void CBC_Decryption::update(secure_vector<byte>& buffer, size_t offset)
buf += to_proc;
blocks -= to_proc / BS;
}
+
+ return sz;
}
void CBC_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
diff --git a/src/lib/modes/cbc/cbc.h b/src/lib/modes/cbc/cbc.h
index 961991d4a..caad102d4 100644
--- a/src/lib/modes/cbc/cbc.h
+++ b/src/lib/modes/cbc/cbc.h
@@ -47,7 +47,7 @@ class BOTAN_DLL CBC_Mode : public Cipher_Mode
byte* state_ptr() { return m_state.data(); }
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
+ void start_msg(const byte nonce[], size_t nonce_len) override;
void key_schedule(const byte key[], size_t length) override;
@@ -65,7 +65,7 @@ class BOTAN_DLL CBC_Encryption : public CBC_Mode
CBC_Encryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) :
CBC_Mode(cipher, padding) {}
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
@@ -100,7 +100,7 @@ class BOTAN_DLL CBC_Decryption : public CBC_Mode
CBC_Decryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) :
CBC_Mode(cipher, padding), m_tempbuf(update_granularity()) {}
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
diff --git a/src/lib/modes/cfb/cfb.cpp b/src/lib/modes/cfb/cfb.cpp
index 6c9239e73..cc5e9bae7 100644
--- a/src/lib/modes/cfb/cfb.cpp
+++ b/src/lib/modes/cfb/cfb.cpp
@@ -69,7 +69,7 @@ void CFB_Mode::key_schedule(const byte key[], size_t length)
m_cipher->set_key(key, length);
}
-secure_vector<byte> CFB_Mode::start_raw(const byte nonce[], size_t nonce_len)
+void CFB_Mode::start_msg(const byte nonce[], size_t nonce_len)
{
if(!valid_nonce_length(nonce_len))
throw Invalid_IV_Length(name(), nonce_len);
@@ -77,24 +77,19 @@ secure_vector<byte> CFB_Mode::start_raw(const byte nonce[], size_t nonce_len)
m_shift_register.assign(nonce, nonce + nonce_len);
m_keystream_buf.resize(m_shift_register.size());
cipher().encrypt(m_shift_register, m_keystream_buf);
-
- return secure_vector<byte>();
}
-void CFB_Encryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t CFB_Encryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
const size_t BS = cipher().block_size();
secure_vector<byte>& state = shift_register();
const size_t shift = feedback();
+ size_t left = sz;
- while(sz)
+ while(left)
{
- const size_t took = std::min(shift, sz);
+ const size_t took = std::min(shift, left);
xor_buf(buf, &keystream_buf()[0], took);
// Assumes feedback-sized block except for last input
@@ -106,8 +101,9 @@ void CFB_Encryption::update(secure_vector<byte>& buffer, size_t offset)
cipher().encrypt(state, keystream_buf());
buf += took;
- sz -= took;
+ left -= took;
}
+ return sz;
}
void CFB_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
@@ -115,20 +111,17 @@ void CFB_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
update(buffer, offset);
}
-void CFB_Decryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t CFB_Decryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
const size_t BS = cipher().block_size();
secure_vector<byte>& state = shift_register();
const size_t shift = feedback();
+ size_t left = sz;
- while(sz)
+ while(left)
{
- const size_t took = std::min(shift, sz);
+ const size_t took = std::min(shift, left);
// first update shift register with ciphertext
if (BS - shift > 0)
@@ -144,8 +137,9 @@ void CFB_Decryption::update(secure_vector<byte>& buffer, size_t offset)
cipher().encrypt(state, keystream_buf());
buf += took;
- sz -= took;
+ left -= took;
}
+ return sz;
}
void CFB_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
diff --git a/src/lib/modes/cfb/cfb.h b/src/lib/modes/cfb/cfb.h
index 49321a1c9..2ec87244e 100644
--- a/src/lib/modes/cfb/cfb.h
+++ b/src/lib/modes/cfb/cfb.h
@@ -46,7 +46,7 @@ class BOTAN_DLL CFB_Mode : public Cipher_Mode
secure_vector<byte>& keystream_buf() { return m_keystream_buf; }
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
+ void start_msg(const byte nonce[], size_t nonce_len) override;
void key_schedule(const byte key[], size_t length) override;
std::unique_ptr<BlockCipher> m_cipher;
@@ -64,7 +64,7 @@ class BOTAN_DLL CFB_Encryption final : public CFB_Mode
CFB_Encryption(BlockCipher* cipher, size_t feedback_bits) :
CFB_Mode(cipher, feedback_bits) {}
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
};
@@ -78,7 +78,7 @@ class BOTAN_DLL CFB_Decryption final : public CFB_Mode
CFB_Decryption(BlockCipher* cipher, size_t feedback_bits) :
CFB_Mode(cipher, feedback_bits) {}
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
};
diff --git a/src/lib/modes/cipher_mode.h b/src/lib/modes/cipher_mode.h
index 73a5f7d96..5781ebbee 100644
--- a/src/lib/modes/cipher_mode.h
+++ b/src/lib/modes/cipher_mode.h
@@ -1,6 +1,6 @@
/*
* Cipher Modes
-* (C) 2013 Jack Lloyd
+* (C) 2013,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -28,25 +28,19 @@ class BOTAN_DLL Cipher_Mode
virtual ~Cipher_Mode() {}
- /**
- * Begin processing a message.
- * @param nonce the per message nonce
+ /*
+ * Prepare for processing a message under the specified nonce
*/
- template<typename Alloc>
- secure_vector<byte> start(const std::vector<byte, Alloc>& nonce)
- {
- return start(nonce.data(), nonce.size());
- }
+ virtual void start_msg(const byte nonce[], size_t nonce_len) = 0;
/**
* Begin processing a message.
* @param nonce the per message nonce
*/
template<typename Alloc>
- BOTAN_DEPRECATED("Use Transform::start")
- secure_vector<byte> start_vec(const std::vector<byte, Alloc>& nonce)
+ void start(const std::vector<byte, Alloc>& nonce)
{
- return start(nonce.data(), nonce.size());
+ start_msg(nonce.data(), nonce.size());
}
/**
@@ -54,27 +48,45 @@ class BOTAN_DLL Cipher_Mode
* @param nonce the per message nonce
* @param nonce_len length of nonce
*/
- secure_vector<byte> start(const byte nonce[], size_t nonce_len)
+ void start(const byte nonce[], size_t nonce_len)
{
- return start_raw(nonce, nonce_len);
+ start_msg(nonce, nonce_len);
}
/**
* Begin processing a message.
*/
- secure_vector<byte> start()
+ void start()
{
- return start_raw(nullptr, 0);
+ return start_msg(nullptr, 0);
}
- virtual secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) = 0;
+ /**
+ * Process message blocks
+ *
+ * Input must be a multiple of update_granularity
+ *
+ * Processes msg in place and returns bytes written. Normally
+ * this will be either msg_len (indicating the entire message was
+ * processes) or for certain AEAD modes zero (indicating that the
+ * mode requires the entire message be processed in one pass.
+ */
+ virtual size_t process(uint8_t msg[], size_t msg_len) = 0;
/**
* Process some data. Input must be in size update_granularity() byte blocks.
* @param blocks in/out parameter which will possibly be resized
* @param offset an offset into blocks to begin processing
*/
- virtual void update(secure_vector<byte>& blocks, size_t offset = 0) = 0;
+ void update(secure_vector<byte>& buffer, size_t offset = 0)
+ {
+ BOTAN_ASSERT(buffer.size() >= offset, "Offset ok");
+ byte* buf = buffer.data() + offset;
+ const size_t buf_size = buffer.size() - offset;
+
+ const size_t written = process(buf, buf_size);
+ buffer.resize(offset + written);
+ }
/**
* Complete processing of a message.
diff --git a/src/lib/modes/ecb/ecb.cpp b/src/lib/modes/ecb/ecb.cpp
index 407b5c582..650cfedf1 100644
--- a/src/lib/modes/ecb/ecb.cpp
+++ b/src/lib/modes/ecb/ecb.cpp
@@ -55,12 +55,10 @@ void ECB_Mode::key_schedule(const byte key[], size_t length)
m_cipher->set_key(key, length);
}
-secure_vector<byte> ECB_Mode::start_raw(const byte[], size_t nonce_len)
+void ECB_Mode::start_msg(const byte[], size_t nonce_len)
{
- if(!valid_nonce_length(nonce_len))
+ if(nonce_len != 0)
throw Invalid_IV_Length(name(), nonce_len);
-
- return secure_vector<byte>();
}
size_t ECB_Encryption::minimum_final_size() const
@@ -76,18 +74,13 @@ size_t ECB_Encryption::output_length(size_t input_length) const
return round_up(input_length, cipher().block_size());
}
-void ECB_Encryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t ECB_Encryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
const size_t BS = cipher().block_size();
-
BOTAN_ASSERT(sz % BS == 0, "ECB input is full blocks");
const size_t blocks = sz / BS;
-
cipher().encrypt_n(buf, buf, blocks);
+ return sz;
}
void ECB_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
@@ -117,18 +110,13 @@ size_t ECB_Decryption::minimum_final_size() const
return cipher().block_size();
}
-void ECB_Decryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t ECB_Decryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
const size_t BS = cipher().block_size();
-
BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
size_t blocks = sz / BS;
-
cipher().decrypt_n(buf, buf, blocks);
+ return sz;
}
void ECB_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
diff --git a/src/lib/modes/ecb/ecb.h b/src/lib/modes/ecb/ecb.h
index aebd4c1a5..9ebbf76a4 100644
--- a/src/lib/modes/ecb/ecb.h
+++ b/src/lib/modes/ecb/ecb.h
@@ -39,7 +39,7 @@ class BOTAN_DLL ECB_Mode : public Cipher_Mode
const BlockCipherModePaddingMethod& padding() const { return *m_padding; }
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
+ void start_msg(const byte nonce[], size_t nonce_len) override;
void key_schedule(const byte key[], size_t length) override;
std::unique_ptr<BlockCipher> m_cipher;
@@ -55,7 +55,7 @@ class BOTAN_DLL ECB_Encryption final : public ECB_Mode
ECB_Encryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) :
ECB_Mode(cipher, padding) {}
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
@@ -73,7 +73,7 @@ class BOTAN_DLL ECB_Decryption final : public ECB_Mode
ECB_Decryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) :
ECB_Mode(cipher, padding) {}
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
diff --git a/src/lib/modes/stream_mode.h b/src/lib/modes/stream_mode.h
index f5f1aa33a..f59f6d9ba 100644
--- a/src/lib/modes/stream_mode.h
+++ b/src/lib/modes/stream_mode.h
@@ -17,10 +17,10 @@ class BOTAN_DLL Stream_Cipher_Mode : public Cipher_Mode
public:
explicit Stream_Cipher_Mode(StreamCipher* cipher) : m_cipher(cipher) {}
- void update(secure_vector<byte>& buf, size_t offset) override
+ size_t process(uint8_t buf[], size_t sz) override
{
- if(offset < buf.size())
- m_cipher->cipher1(&buf[offset], buf.size() - offset);
+ m_cipher->cipher1(buf, sz);
+ return sz;
}
void finish(secure_vector<byte>& buf, size_t offset) override
@@ -28,7 +28,7 @@ class BOTAN_DLL Stream_Cipher_Mode : public Cipher_Mode
size_t output_length(size_t input_length) const override { return input_length; }
- size_t update_granularity() const override { return 64; /* arbitrary */ }
+ size_t update_granularity() const override { return 1; }
size_t minimum_final_size() const override { return 0; }
@@ -44,10 +44,9 @@ class BOTAN_DLL Stream_Cipher_Mode : public Cipher_Mode
void clear() override { return m_cipher->clear(); }
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override
+ void start_msg(const byte nonce[], size_t nonce_len) override
{
m_cipher->set_iv(nonce, nonce_len);
- return secure_vector<byte>();
}
void key_schedule(const byte key[], size_t length) override
diff --git a/src/lib/modes/xts/xts.cpp b/src/lib/modes/xts/xts.cpp
index b369fde29..1993bf15f 100644
--- a/src/lib/modes/xts/xts.cpp
+++ b/src/lib/modes/xts/xts.cpp
@@ -105,7 +105,7 @@ void XTS_Mode::key_schedule(const byte key[], size_t length)
m_tweak_cipher->set_key(&key[key_half], key_half);
}
-secure_vector<byte> XTS_Mode::start_raw(const byte nonce[], size_t nonce_len)
+void XTS_Mode::start_msg(const byte nonce[], size_t nonce_len)
{
if(!valid_nonce_length(nonce_len))
throw Invalid_IV_Length(name(), nonce_len);
@@ -114,8 +114,6 @@ secure_vector<byte> XTS_Mode::start_raw(const byte nonce[], size_t nonce_len)
m_tweak_cipher->encrypt(m_tweak.data());
update_tweak(0);
-
- return secure_vector<byte>();
}
void XTS_Mode::update_tweak(size_t which)
@@ -136,12 +134,8 @@ size_t XTS_Encryption::output_length(size_t input_length) const
return input_length;
}
-void XTS_Encryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t XTS_Encryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
const size_t BS = cipher().block_size();
BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
@@ -163,6 +157,8 @@ void XTS_Encryption::update(secure_vector<byte>& buffer, size_t offset)
update_tweak(to_proc);
}
+
+ return sz;
}
void XTS_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
@@ -214,12 +210,8 @@ size_t XTS_Decryption::output_length(size_t input_length) const
return input_length;
}
-void XTS_Decryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t XTS_Decryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
const size_t BS = cipher().block_size();
BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
@@ -241,6 +233,8 @@ void XTS_Decryption::update(secure_vector<byte>& buffer, size_t offset)
update_tweak(to_proc);
}
+
+ return sz;
}
void XTS_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
diff --git a/src/lib/modes/xts/xts.h b/src/lib/modes/xts/xts.h
index e751b1644..6c4ba8d99 100644
--- a/src/lib/modes/xts/xts.h
+++ b/src/lib/modes/xts/xts.h
@@ -42,7 +42,7 @@ class BOTAN_DLL XTS_Mode : public Cipher_Mode
void update_tweak(size_t last_used);
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
+ void start_msg(const byte nonce[], size_t nonce_len) override;
void key_schedule(const byte key[], size_t length) override;
std::unique_ptr<BlockCipher> m_cipher, m_tweak_cipher;
@@ -57,7 +57,7 @@ class BOTAN_DLL XTS_Encryption final : public XTS_Mode
public:
explicit XTS_Encryption(BlockCipher* cipher) : XTS_Mode(cipher) {}
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
@@ -72,7 +72,7 @@ class BOTAN_DLL XTS_Decryption final : public XTS_Mode
public:
explicit XTS_Decryption(BlockCipher* cipher) : XTS_Mode(cipher) {}
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
diff --git a/src/lib/tls/tls_record.cpp b/src/lib/tls/tls_record.cpp
index 877b81b41..4a52aa4a9 100644
--- a/src/lib/tls/tls_record.cpp
+++ b/src/lib/tls/tls_record.cpp
@@ -190,7 +190,6 @@ void write_record(secure_vector<byte>& output,
const std::vector<byte> nonce = cs->aead_nonce(seq);
- // wrong if start returns something
const size_t rec_size = ctext_size + cs->nonce_bytes_from_record();
BOTAN_ASSERT(rec_size <= 0xFFFF, "Ciphertext length fits in field");
@@ -203,13 +202,11 @@ void write_record(secure_vector<byte>& output,
{
output += std::make_pair(&nonce[cs->nonce_bytes_from_handshake()], cs->nonce_bytes_from_record());
}
- BOTAN_ASSERT(aead->start(nonce).empty(), "AEAD doesn't return anything from start");
-
- const size_t offset = output.size();
+ const size_t header_size = output.size();
output += std::make_pair(msg.get_data(), msg.get_size());
- aead->finish(output, offset);
- BOTAN_ASSERT(output.size() == offset + ctext_size, "Expected size");
+ aead->start(nonce);
+ aead->finish(output, header_size);
BOTAN_ASSERT(output.size() < MAX_CIPHERTEXT_SIZE,
"Produced ciphertext larger than protocol allows");
@@ -469,7 +466,7 @@ void decrypt_record(secure_vector<byte>& output,
cs.format_ad(record_sequence, record_type, record_version, static_cast<u16bit>(ptext_size))
);
- output += aead->start(nonce);
+ aead->start(nonce);
const size_t offset = output.size();
output += std::make_pair(msg, msg_length);
diff --git a/src/lib/utils/assert.h b/src/lib/utils/assert.h
index f80f9b170..c49ae62ee 100644
--- a/src/lib/utils/assert.h
+++ b/src/lib/utils/assert.h
@@ -35,6 +35,19 @@ BOTAN_NORETURN void BOTAN_DLL assertion_failure(const char* expr_str,
} while(0)
/**
+* Make an assertion
+*/
+#define BOTAN_ASSERT_NOMSG(expr) \
+ do { \
+ if(!(expr)) \
+ Botan::assertion_failure(#expr, \
+ "", \
+ BOTAN_CURRENT_FUNCTION, \
+ __FILE__, \
+ __LINE__); \
+ } while(0)
+
+/**
* Assert that value1 == value2
*/
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made) \
diff --git a/src/lib/utils/exceptn.h b/src/lib/utils/exceptn.h
index 193d78ce9..a3cb11f81 100644
--- a/src/lib/utils/exceptn.h
+++ b/src/lib/utils/exceptn.h
@@ -29,14 +29,20 @@ class BOTAN_DLL Exception : public std::exception
};
/**
-* An invalid argument which caused
+* An invalid argument
*/
class BOTAN_DLL Invalid_Argument : public Exception
{
public:
explicit Invalid_Argument(const std::string& msg) :
Exception("Invalid argument", msg) {}
- };
+
+ explicit Invalid_Argument(const std::string& msg, const std::string& where) :
+ Exception("Invalid argument", msg + " in " + where) {}
+};
+
+#define BOTAN_ARG_CHECK(expr) \
+ do { if(!(expr)) throw Invalid_Argument(#expr, BOTAN_CURRENT_FUNCTION); } while(0)
/**
* Unsupported_Argument Exception