diff options
author | lloyd <[email protected]> | 2009-12-27 01:38:15 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2009-12-27 01:38:15 +0000 |
commit | fc12742c25ed6a6d1fd533ee2d53c744c8d07b8f (patch) | |
tree | 267f55b00f7652e91d62e4c892e0ee833077b07e | |
parent | 93eda35a7680421844bab8942b310237fc09d99d (diff) | |
parent | 76018ba3d8c9778c9ef48aece0e84945e8ad4f7e (diff) |
propagate from branch 'net.randombit.botan' (head 79ed5b0f9057b2d40335e268fdb9f375837d1d11)
to branch 'net.randombit.botan.buf-op' (head 87160704bdc30b0a4cb19fd4516e20e85dca2869)
-rw-r--r-- | src/filters/modes/cbc/cbc.cpp | 160 | ||||
-rw-r--r-- | src/filters/modes/cbc/cbc.h | 17 | ||||
-rw-r--r-- | src/utils/buf_op/buf_op.cpp | 120 | ||||
-rw-r--r-- | src/utils/buf_op/buf_op.h | 45 | ||||
-rw-r--r-- | src/utils/buf_op/info.txt | 11 |
5 files changed, 290 insertions, 63 deletions
diff --git a/src/filters/modes/cbc/cbc.cpp b/src/filters/modes/cbc/cbc.cpp index 48ecdf509..9303dd9fd 100644 --- a/src/filters/modes/cbc/cbc.cpp +++ b/src/filters/modes/cbc/cbc.cpp @@ -9,6 +9,8 @@ #include <botan/internal/xor_buf.h> #include <algorithm> +using namespace std::tr1::placeholders; + namespace Botan { /* @@ -16,14 +18,15 @@ namespace Botan { */ CBC_Encryption::CBC_Encryption(BlockCipher* ciph, BlockCipherModePaddingMethod* pad) : - cipher(ciph), padder(pad) + cipher(ciph), padder(pad), + buf_op(std::tr1::bind(&CBC_Encryption::cbc_encrypt, this, _1, _2), + std::tr1::bind(&CBC_Encryption::cbc_final, this, _1, _2), + 2 * cipher->BLOCK_SIZE) { if(!padder->valid_blocksize(cipher->BLOCK_SIZE)) throw Invalid_Block_Size(name(), padder->name()); - buffer.resize(cipher->BLOCK_SIZE); state.resize(cipher->BLOCK_SIZE); - position = 0; } /* @@ -33,14 +36,15 @@ CBC_Encryption::CBC_Encryption(BlockCipher* ciph, BlockCipherModePaddingMethod* pad, const SymmetricKey& key, const InitializationVector& iv) : - cipher(ciph), padder(pad) + cipher(ciph), padder(pad), + buf_op(std::tr1::bind(&CBC_Encryption::cbc_encrypt, this, _1, _2), + std::tr1::bind(&CBC_Encryption::cbc_final, this, _1, _2), + 2 * cipher->BLOCK_SIZE) { if(!padder->valid_blocksize(cipher->BLOCK_SIZE)) throw Invalid_Block_Size(name(), padder->name()); - buffer.resize(cipher->BLOCK_SIZE); state.resize(cipher->BLOCK_SIZE); - position = 0; set_key(key); set_iv(iv); @@ -55,41 +59,51 @@ void CBC_Encryption::set_iv(const InitializationVector& iv) throw Invalid_IV_Length(name(), iv.length()); state = iv.bits_of(); - buffer.clear(); - position = 0; + buf_op.reset(); } /* * Encrypt in CBC mode */ -void CBC_Encryption::write(const byte input[], u32bit length) +void CBC_Encryption::cbc_encrypt(const byte input[], u32bit length) { - while(length) + u32bit blocks = length / state.size(); + + for(u32bit i = 0; i != blocks; ++i) { - u32bit xored = std::min(cipher->BLOCK_SIZE - position, length); - xor_buf(state + position, input, xored); - input += xored; - length -= xored; - position += xored; - if(position == cipher->BLOCK_SIZE) - { - cipher->encrypt(state); - send(state, cipher->BLOCK_SIZE); - position = 0; - } + xor_buf(state, input + i * cipher->BLOCK_SIZE, state.size()); + cipher->encrypt(state); + send(state, state.size()); } } /* * Finish encrypting in CBC mode */ +void CBC_Encryption::cbc_final(const byte input[], u32bit length) + { + if(length % cipher->BLOCK_SIZE == 0) + cbc_encrypt(input, length); + else if(length != 0) + throw Exception(name() + ": Did not pad to full blocksize"); + } + +void CBC_Encryption::write(const byte input[], u32bit input_length) + { + buf_op.write(input, input_length); + } + void CBC_Encryption::end_msg() { + u32bit last_block = buf_op.current_position() % cipher->BLOCK_SIZE; + SecureVector<byte> padding(cipher->BLOCK_SIZE); - padder->pad(padding, padding.size(), position); - write(padding, padder->pad_bytes(cipher->BLOCK_SIZE, position)); - if(position != 0) - throw Exception(name() + ": Did not pad to full blocksize"); + padder->pad(padding, padding.size(), last_block); + + u32bit pad_bytes = padder->pad_bytes(cipher->BLOCK_SIZE, last_block); + + buf_op.write(padding, pad_bytes); + buf_op.final(); } /* @@ -105,15 +119,16 @@ std::string CBC_Encryption::name() const */ CBC_Decryption::CBC_Decryption(BlockCipher* ciph, BlockCipherModePaddingMethod* pad) : - cipher(ciph), padder(pad) + cipher(ciph), padder(pad), + buf_op(std::tr1::bind(&CBC_Decryption::cbc_decrypt, this, _1, _2), + std::tr1::bind(&CBC_Decryption::cbc_final, this, _1, _2), + 2 * cipher->BLOCK_SIZE, cipher->BLOCK_SIZE) { if(!padder->valid_blocksize(cipher->BLOCK_SIZE)) throw Invalid_Block_Size(name(), padder->name()); - buffer.resize(cipher->BLOCK_SIZE); state.resize(cipher->BLOCK_SIZE); - temp.resize(cipher->BLOCK_SIZE); - position = 0; + temp.resize(BOTAN_PARALLEL_BLOCKS_CBC * cipher->BLOCK_SIZE); } /* @@ -123,15 +138,16 @@ CBC_Decryption::CBC_Decryption(BlockCipher* ciph, BlockCipherModePaddingMethod* pad, const SymmetricKey& key, const InitializationVector& iv) : - cipher(ciph), padder(pad) + cipher(ciph), padder(pad), + buf_op(std::tr1::bind(&CBC_Decryption::cbc_decrypt, this, _1, _2), + std::tr1::bind(&CBC_Decryption::cbc_final, this, _1, _2), + 2 * cipher->BLOCK_SIZE, cipher->BLOCK_SIZE) { if(!padder->valid_blocksize(cipher->BLOCK_SIZE)) throw Invalid_Block_Size(name(), padder->name()); - buffer.resize(cipher->BLOCK_SIZE); state.resize(cipher->BLOCK_SIZE); - temp.resize(cipher->BLOCK_SIZE); - position = 0; + temp.resize(BOTAN_PARALLEL_BLOCKS_CBC * cipher->BLOCK_SIZE); set_key(key); set_iv(iv); @@ -146,46 +162,74 @@ void CBC_Decryption::set_iv(const InitializationVector& iv) throw Invalid_IV_Length(name(), iv.length()); state = iv.bits_of(); - buffer.clear(); - position = 0; + buf_op.reset(); } /* * Decrypt in CBC mode */ -void CBC_Decryption::write(const byte input[], u32bit length) +void CBC_Decryption::cbc_decrypt(const byte input[], u32bit length) { - while(length) + const u32bit blocks_in_temp = temp.size() / cipher->BLOCK_SIZE; + u32bit blocks = length / cipher->BLOCK_SIZE; + + while(blocks) { - if(position == cipher->BLOCK_SIZE) - { - cipher->decrypt(buffer, temp); - xor_buf(temp, state, cipher->BLOCK_SIZE); - send(temp, cipher->BLOCK_SIZE); - state = buffer; - position = 0; - } - - u32bit added = std::min(cipher->BLOCK_SIZE - position, length); - buffer.copy(position, input, added); - input += added; - length -= added; - position += added; + u32bit to_proc = std::min<u32bit>(blocks, blocks_in_temp); + + cipher->decrypt_n(input, &temp[0], to_proc); + + xor_buf(temp, state, cipher->BLOCK_SIZE); + + for(u32bit i = 1; i < to_proc; ++i) + xor_buf(temp + i * cipher->BLOCK_SIZE, + input + (i-1) * cipher->BLOCK_SIZE, + cipher->BLOCK_SIZE); + + state.set(input + (to_proc - 1) * cipher->BLOCK_SIZE, cipher->BLOCK_SIZE); + + send(temp, to_proc * cipher->BLOCK_SIZE); + + input += to_proc * cipher->BLOCK_SIZE; + blocks -= to_proc; } } /* -* Finish decrypting in CBC mode +* Finish encrypting in CBC mode */ -void CBC_Decryption::end_msg() +void CBC_Decryption::cbc_final(const byte input[], u32bit length) { - if(position != cipher->BLOCK_SIZE) - throw Decoding_Error(name()); - cipher->decrypt(buffer, temp); + if(length == 0 || length % cipher->BLOCK_SIZE != 0) + throw Decoding_Error(name() + ": Ciphertext not multiple of block size"); + + size_t extra_blocks = (length - 1) / cipher->BLOCK_SIZE; + + cbc_decrypt(input, extra_blocks * cipher->BLOCK_SIZE); + + input += extra_blocks * cipher->BLOCK_SIZE; + + cipher->decrypt(input, temp); xor_buf(temp, state, cipher->BLOCK_SIZE); send(temp, padder->unpad(temp, cipher->BLOCK_SIZE)); - state = buffer; - position = 0; + + state.set(input, state.size()); + } + +/* +* Decrypt in CBC mode +*/ +void CBC_Decryption::write(const byte input[], u32bit length) + { + buf_op.write(input, length); + } + +/* +* Finish decrypting in CBC mode +*/ +void CBC_Decryption::end_msg() + { + buf_op.final(); } /* diff --git a/src/filters/modes/cbc/cbc.h b/src/filters/modes/cbc/cbc.h index 91ab21ab6..8fa322260 100644 --- a/src/filters/modes/cbc/cbc.h +++ b/src/filters/modes/cbc/cbc.h @@ -11,6 +11,7 @@ #include <botan/block_cipher.h> #include <botan/key_filt.h> #include <botan/mode_pad.h> +#include <botan/buf_op.h> namespace Botan { @@ -39,13 +40,16 @@ class BOTAN_DLL CBC_Encryption : public Keyed_Filter ~CBC_Encryption() { delete padder; } private: - void write(const byte[], u32bit); + void cbc_encrypt(const byte input[], u32bit input_length); + void cbc_final(const byte input[], u32bit input_length); + + void write(const byte input[], u32bit input_length); void end_msg(); BlockCipher* cipher; const BlockCipherModePaddingMethod* padder; - SecureVector<byte> buffer, state; - u32bit position; + Buffered_Operation buf_op; + SecureVector<byte> state; }; /* @@ -73,13 +77,16 @@ class BOTAN_DLL CBC_Decryption : public Keyed_Filter ~CBC_Decryption() { delete padder; } private: + void cbc_decrypt(const byte input[], u32bit input_length); + void cbc_final(const byte input[], u32bit input_length); + void write(const byte[], u32bit); void end_msg(); BlockCipher* cipher; const BlockCipherModePaddingMethod* padder; - SecureVector<byte> buffer, state, temp; - u32bit position; + Buffered_Operation buf_op; + SecureVector<byte> state, temp; }; } diff --git a/src/utils/buf_op/buf_op.cpp b/src/utils/buf_op/buf_op.cpp new file mode 100644 index 000000000..2b5b943cd --- /dev/null +++ b/src/utils/buf_op/buf_op.cpp @@ -0,0 +1,120 @@ +/** +* Buffering Central +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/buf_op.h> +#include <botan/mem_ops.h> +#include <botan/internal/rounding.h> +#include <stdexcept> + +#include <stdio.h> +#include <assert.h> + +namespace Botan { + +namespace { + +const size_t BUFFER_MULTIPLE = 2; + +//static_assert(BUFFER_MULTIPLE >= 2, "BUFFER_MULTIPLE must be >= 2"); + +} + +Buffered_Operation::Buffered_Operation(callback_fn m_fn, + callback_fn f_fn, + size_t buf_mod, + size_t final_minimum) : + main_fn(m_fn), final_fn(f_fn), + final_minimum(final_minimum), main_block_mod(buf_mod), + buffer(BUFFER_MULTIPLE * buf_mod), buffer_pos(0) + { + if(buf_mod == 0) + throw std::invalid_argument("buf_mod == 0"); + + if(final_minimum > buf_mod) + throw std::invalid_argument("final_minimum > buf_mod"); + } + +void Buffered_Operation::reset() + { + clear_mem(&buffer[0], buffer.size()); + buffer_pos = 0; + } + +void Buffered_Operation::write(const byte input[], + size_t input_size) + { + if(!input_size) + return; + + if(buffer_pos + input_size >= main_block_mod + final_minimum) + { + size_t to_copy = std::min(buffer.size() - buffer_pos, input_size); + + copy_mem(&buffer[buffer_pos], input, to_copy); + buffer_pos += to_copy; + + input += to_copy; + input_size -= to_copy; + + if(input_size >= final_minimum) + { + size_t to_proc = round_down(buffer_pos, main_block_mod); + main_fn(&buffer[0], to_proc); + + buffer_pos -= to_proc; + + copy_mem(&buffer[0], &buffer[to_proc], buffer_pos); + } + } + + if(input_size >= final_minimum) + { + size_t full_blocks = (input_size - final_minimum) / buffer.size(); + size_t to_copy = full_blocks * buffer.size(); + + if(to_copy) + { + main_fn(input, to_copy); + + input += to_copy; + input_size -= to_copy; + } + } + + assert(input_size + buffer_pos <= buffer.size()); + + copy_mem(&buffer[buffer_pos], input, input_size); + buffer_pos += input_size; + } + +void Buffered_Operation::final() + { + assert(buffer_pos >= final_minimum); + + if(buffer_pos < final_minimum) + throw std::runtime_error("Buffered_Operation::final - not enough input"); + + size_t spare_blocks = (buffer_pos - final_minimum) / main_block_mod; + + if(spare_blocks) + { + size_t spare_bytes = main_block_mod * spare_blocks; + + assert(spare_bytes <= buffer_pos); + + main_fn(&buffer[0], spare_bytes); + + assert(buffer_pos - spare_bytes >= final_minimum); + final_fn(&buffer[spare_bytes], buffer_pos - spare_bytes); + } + else + { + final_fn(&buffer[0], buffer_pos); + } + } + +} diff --git a/src/utils/buf_op/buf_op.h b/src/utils/buf_op/buf_op.h new file mode 100644 index 000000000..cc864c47d --- /dev/null +++ b/src/utils/buf_op/buf_op.h @@ -0,0 +1,45 @@ +/** +* Buffering Central +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BUFFERED_OPTION_H__ +#define BOTAN_BUFFERED_OPTION_H__ + +#include <botan/types.h> +#include <tr1/functional> +#include <vector> + +namespace Botan { + +class BOTAN_DLL Buffered_Operation + { + public: + typedef std::tr1::function<void (const byte[], size_t)> callback_fn; + + void write(const byte input[], size_t input_size); + + void final(); + + void reset(); + + size_t current_position() const { return buffer_pos; } + + Buffered_Operation(callback_fn main_block, + callback_fn final_block, + size_t main_buf_mod, + size_t final_minimum = 0); + + private: + callback_fn main_fn, final_fn; + size_t final_minimum, main_block_mod; + + std::vector<byte> buffer; + size_t buffer_pos; + }; + +} + +#endif diff --git a/src/utils/buf_op/info.txt b/src/utils/buf_op/info.txt new file mode 100644 index 000000000..657a1e0c4 --- /dev/null +++ b/src/utils/buf_op/info.txt @@ -0,0 +1,11 @@ +define BUFFERED_OPERATION + +uses_tr1 yes + +<source> +buf_op.cpp +</source> + +<header:public> +buf_op.h +</header:public> |