#include "botan-1.6/include/cbc.h"
#include "botan-1.6/include/lookup.h"
#include "botan-1.6/include/bit_ops.h"
#include <algorithm>
namespace Enctain {
namespace Botan {
CBC_Encryption::CBC_Encryption(const std::string& cipher_name,
const std::string& padding_name) :
BlockCipherMode(cipher_name, "CBC", block_size_of(cipher_name)),
padder(get_bc_pad(padding_name))
{
if(!padder->valid_blocksize(BLOCK_SIZE))
throw Invalid_Block_Size(name(), padder->name());
}
CBC_Encryption::CBC_Encryption(const std::string& cipher_name,
const std::string& padding_name,
const SymmetricKey& key,
const InitializationVector& iv) :
BlockCipherMode(cipher_name, "CBC", block_size_of(cipher_name)),
padder(get_bc_pad(padding_name))
{
if(!padder->valid_blocksize(BLOCK_SIZE))
throw Invalid_Block_Size(name(), padder->name());
set_key(key);
set_iv(iv);
}
void CBC_Encryption::write(const byte input[], u32bit length)
{
while(length)
{
u32bit xored = std::min(BLOCK_SIZE - position, length);
xor_buf(state + position, input, xored);
input += xored;
length -= xored;
position += xored;
if(position == BLOCK_SIZE)
{
cipher->encrypt(state);
send(state, BLOCK_SIZE);
position = 0;
}
}
}
void CBC_Encryption::end_msg()
{
SecureVector<byte> padding(BLOCK_SIZE);
padder->pad(padding, padding.size(), position);
write(padding, padder->pad_bytes(BLOCK_SIZE, position));
if(position != 0)
throw Exception(name() + ": Did not pad to full blocksize");
}
std::string CBC_Encryption::name() const
{
return (cipher->name() + "/" + mode_name + "/" + padder->name());
}
CBC_Decryption::CBC_Decryption(const std::string& cipher_name,
const std::string& padding_name) :
BlockCipherMode(cipher_name, "CBC", block_size_of(cipher_name)),
padder(get_bc_pad(padding_name))
{
if(!padder->valid_blocksize(BLOCK_SIZE))
throw Invalid_Block_Size(name(), padder->name());
temp.create(BLOCK_SIZE);
}
CBC_Decryption::CBC_Decryption(const std::string& cipher_name,
const std::string& padding_name,
const SymmetricKey& key,
const InitializationVector& iv) :
BlockCipherMode(cipher_name, "CBC", block_size_of(cipher_name)),
padder(get_bc_pad(padding_name))
{
if(!padder->valid_blocksize(BLOCK_SIZE))
throw Invalid_Block_Size(name(), padder->name());
temp.create(BLOCK_SIZE);
set_key(key);
set_iv(iv);
}
void CBC_Decryption::write(const byte input[], u32bit length)
{
while(length)
{
if(position == BLOCK_SIZE)
{
cipher->decrypt(buffer, temp);
xor_buf(temp, state, BLOCK_SIZE);
send(temp, BLOCK_SIZE);
state = buffer;
position = 0;
}
u32bit added = std::min(BLOCK_SIZE - position, length);
buffer.copy(position, input, added);
input += added;
length -= added;
position += added;
}
}
void CBC_Decryption::end_msg()
{
if(position != BLOCK_SIZE)
throw Decoding_Error(name());
cipher->decrypt(buffer, temp);
xor_buf(temp, state, BLOCK_SIZE);
send(temp, padder->unpad(temp, BLOCK_SIZE));
state = buffer;
position = 0;
}
std::string CBC_Decryption::name() const
{
return (cipher->name() + "/" + mode_name + "/" + padder->name());
}
}
}