/* * Block Cipher Cascade * (C) 2010 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include namespace Botan { BOTAN_REGISTER_NAMED_T(BlockCipher, "Cascade", Cascade_Cipher, Cascade_Cipher::make); Cascade_Cipher* Cascade_Cipher::make(const BlockCipher::Spec& spec) { std::unique_ptr c1(get_block_cipher(spec.arg(0))); std::unique_ptr c2(get_block_cipher(spec.arg(1))); if(c1 && c2) return new Cascade_Cipher(c1.release(), c2.release()); return nullptr; } void Cascade_Cipher::encrypt_n(const byte in[], byte out[], size_t blocks) const { size_t c1_blocks = blocks * (block_size() / m_cipher1->block_size()); size_t c2_blocks = blocks * (block_size() / m_cipher2->block_size()); m_cipher1->encrypt_n(in, out, c1_blocks); m_cipher2->encrypt_n(out, out, c2_blocks); } void Cascade_Cipher::decrypt_n(const byte in[], byte out[], size_t blocks) const { size_t c1_blocks = blocks * (block_size() / m_cipher1->block_size()); size_t c2_blocks = blocks * (block_size() / m_cipher2->block_size()); m_cipher2->decrypt_n(in, out, c2_blocks); m_cipher1->decrypt_n(out, out, c1_blocks); } void Cascade_Cipher::key_schedule(const byte key[], size_t) { const byte* key2 = key + m_cipher1->maximum_keylength(); m_cipher1->set_key(key , m_cipher1->maximum_keylength()); m_cipher2->set_key(key2, m_cipher2->maximum_keylength()); } void Cascade_Cipher::clear() { m_cipher1->clear(); m_cipher2->clear(); } std::string Cascade_Cipher::name() const { return "Cascade(" + m_cipher1->name() + "," + m_cipher2->name() + ")"; } BlockCipher* Cascade_Cipher::clone() const { return new Cascade_Cipher(m_cipher1->clone(), m_cipher2->clone()); } namespace { size_t euclids_algorithm(size_t a, size_t b) { while(b != 0) // gcd { size_t t = b; b = a % b; a = t; } return a; } size_t block_size_for_cascade(size_t bs, size_t bs2) { if(bs == bs2) return bs; size_t gcd = euclids_algorithm(bs, bs2); return (bs * bs2) / gcd; } } Cascade_Cipher::Cascade_Cipher(BlockCipher* c1, BlockCipher* c2) : m_cipher1(c1), m_cipher2(c2) { m_block = block_size_for_cascade(c1->block_size(), c2->block_size()); if(block_size() % c1->block_size() || block_size() % c2->block_size()) throw Internal_Error("Failure in " + name() + " constructor"); } }