diff options
Diffstat (limited to 'botan/src/modes')
31 files changed, 2270 insertions, 0 deletions
diff --git a/botan/src/modes/cbc/cbc.cpp b/botan/src/modes/cbc/cbc.cpp new file mode 100644 index 0000000..f26d4d6 --- /dev/null +++ b/botan/src/modes/cbc/cbc.cpp @@ -0,0 +1,158 @@ +/* +* CBC Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/cbc.h> +#include <botan/xor_buf.h> +#include <algorithm> + +namespace Botan { + +/* +* CBC Encryption Constructor +*/ +CBC_Encryption::CBC_Encryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad) : + BlockCipherMode(ciph, "CBC", ciph->BLOCK_SIZE), + padder(pad) + { + if(!padder->valid_blocksize(BLOCK_SIZE)) + throw Invalid_Block_Size(name(), padder->name()); + } + +/* +* CBC Encryption Constructor +*/ +CBC_Encryption::CBC_Encryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad, + const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(ciph, "CBC", ciph->BLOCK_SIZE), + padder(pad) + { + if(!padder->valid_blocksize(BLOCK_SIZE)) + throw Invalid_Block_Size(name(), padder->name()); + set_key(key); + set_iv(iv); + } + +/* +* Encrypt in CBC mode +*/ +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; + } + } + } + +/* +* Finish encrypting in CBC mode +*/ +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"); + } + +/* +* Return a CBC mode name +*/ +std::string CBC_Encryption::name() const + { + return (cipher->name() + "/" + mode_name + "/" + padder->name()); + } + +/* +* CBC Decryption Constructor +*/ +CBC_Decryption::CBC_Decryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad) : + BlockCipherMode(ciph, "CBC", ciph->BLOCK_SIZE), + padder(pad) + { + if(!padder->valid_blocksize(BLOCK_SIZE)) + throw Invalid_Block_Size(name(), padder->name()); + temp.create(BLOCK_SIZE); + } + +/* +* CBC Decryption Constructor +*/ +CBC_Decryption::CBC_Decryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad, + const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(ciph, "CBC", ciph->BLOCK_SIZE), + padder(pad) + { + if(!padder->valid_blocksize(BLOCK_SIZE)) + throw Invalid_Block_Size(name(), padder->name()); + temp.create(BLOCK_SIZE); + set_key(key); + set_iv(iv); + } + +/* +* Decrypt in CBC mode +*/ +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; + } + } + +/* +* Finish decrypting in CBC mode +*/ +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; + } + +/* +* Return a CBC mode name +*/ +std::string CBC_Decryption::name() const + { + return (cipher->name() + "/" + mode_name + "/" + padder->name()); + } + +} diff --git a/botan/src/modes/cbc/cbc.h b/botan/src/modes/cbc/cbc.h new file mode 100644 index 0000000..a926ac1 --- /dev/null +++ b/botan/src/modes/cbc/cbc.h @@ -0,0 +1,55 @@ +/* +* CBC Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CBC_H__ +#define BOTAN_CBC_H__ + +#include <botan/modebase.h> +#include <botan/mode_pad.h> + +namespace Botan { + +/* +* CBC Encryption +*/ +class BOTAN_DLL CBC_Encryption : public BlockCipherMode + { + public: + CBC_Encryption(BlockCipher*, BlockCipherModePaddingMethod*); + CBC_Encryption(BlockCipher*, BlockCipherModePaddingMethod*, + const SymmetricKey&, const InitializationVector&); + + ~CBC_Encryption() { delete padder; } + private: + std::string name() const; + void write(const byte[], u32bit); + void end_msg(); + const BlockCipherModePaddingMethod* padder; + }; + +/* +* CBC Decryption +*/ +class BOTAN_DLL CBC_Decryption : public BlockCipherMode + { + public: + CBC_Decryption(BlockCipher*, BlockCipherModePaddingMethod*); + CBC_Decryption(BlockCipher*, BlockCipherModePaddingMethod*, + const SymmetricKey&, const InitializationVector&); + + ~CBC_Decryption() { delete padder; } + private: + std::string name() const; + void write(const byte[], u32bit); + void end_msg(); + const BlockCipherModePaddingMethod* padder; + SecureVector<byte> temp; + }; + +} + +#endif diff --git a/botan/src/modes/cbc/info.txt b/botan/src/modes/cbc/info.txt new file mode 100644 index 0000000..de81dcb --- /dev/null +++ b/botan/src/modes/cbc/info.txt @@ -0,0 +1,14 @@ +realname "CBC block cipher mode" + +define CBC + +load_on auto + +<add> +cbc.cpp +cbc.h +</add> + +<requires> +mode_pad +</requires> diff --git a/botan/src/modes/cfb/cfb.cpp b/botan/src/modes/cfb/cfb.cpp new file mode 100644 index 0000000..a126bd9 --- /dev/null +++ b/botan/src/modes/cfb/cfb.cpp @@ -0,0 +1,143 @@ +/* +* CFB Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/cfb.h> +#include <botan/parsing.h> +#include <botan/xor_buf.h> +#include <algorithm> + +namespace Botan { + +namespace { + +/* +* Check the feedback size +*/ +void check_feedback(u32bit BLOCK_SIZE, u32bit FEEDBACK_SIZE, u32bit bits, + const std::string& name) + { + if(FEEDBACK_SIZE == 0 || FEEDBACK_SIZE > BLOCK_SIZE || bits % 8 != 0) + throw Invalid_Argument(name + ": Invalid feedback size " + + to_string(bits)); + } + +} + +/* +* CFB Encryption Constructor +*/ +CFB_Encryption::CFB_Encryption(BlockCipher* ciph, + u32bit fback_bits) : + BlockCipherMode(ciph, "CFB", ciph->BLOCK_SIZE, 1), + FEEDBACK_SIZE(fback_bits ? fback_bits / 8: BLOCK_SIZE) + { + check_feedback(BLOCK_SIZE, FEEDBACK_SIZE, fback_bits, name()); + } + +/* +* CFB Encryption Constructor +*/ +CFB_Encryption::CFB_Encryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv, + u32bit fback_bits) : + BlockCipherMode(ciph, "CFB", ciph->BLOCK_SIZE, 1), + FEEDBACK_SIZE(fback_bits ? fback_bits / 8: BLOCK_SIZE) + { + check_feedback(BLOCK_SIZE, FEEDBACK_SIZE, fback_bits, name()); + set_key(key); + set_iv(iv); + } + +/* +* Encrypt data in CFB mode +*/ +void CFB_Encryption::write(const byte input[], u32bit length) + { + while(length) + { + u32bit xored = std::min(FEEDBACK_SIZE - position, length); + xor_buf(buffer + position, input, xored); + send(buffer + position, xored); + input += xored; + length -= xored; + position += xored; + if(position == FEEDBACK_SIZE) + feedback(); + } + } + +/* +* Do the feedback +*/ +void CFB_Encryption::feedback() + { + for(u32bit j = 0; j != BLOCK_SIZE - FEEDBACK_SIZE; ++j) + state[j] = state[j + FEEDBACK_SIZE]; + state.copy(BLOCK_SIZE - FEEDBACK_SIZE, buffer, FEEDBACK_SIZE); + cipher->encrypt(state, buffer); + position = 0; + } + +/* +* CFB Decryption Constructor +*/ +CFB_Decryption::CFB_Decryption(BlockCipher* ciph, + u32bit fback_bits) : + BlockCipherMode(ciph, "CFB", ciph->BLOCK_SIZE, 1), + FEEDBACK_SIZE(fback_bits ? fback_bits / 8 : BLOCK_SIZE) + { + check_feedback(BLOCK_SIZE, FEEDBACK_SIZE, fback_bits, name()); + } + +/* +* CFB Decryption Constructor +*/ +CFB_Decryption::CFB_Decryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv, + u32bit fback_bits) : + BlockCipherMode(ciph, "CFB", ciph->BLOCK_SIZE, 1), + FEEDBACK_SIZE(fback_bits ? fback_bits / 8 : BLOCK_SIZE) + { + check_feedback(BLOCK_SIZE, FEEDBACK_SIZE, fback_bits, name()); + set_key(key); + set_iv(iv); + } + +/* +* Decrypt data in CFB mode +*/ +void CFB_Decryption::write(const byte input[], u32bit length) + { + while(length) + { + u32bit xored = std::min(FEEDBACK_SIZE - position, length); + xor_buf(buffer + position, input, xored); + send(buffer + position, xored); + buffer.copy(position, input, xored); + input += xored; + length -= xored; + position += xored; + if(position == FEEDBACK_SIZE) + feedback(); + } + } + +/* +* Do the feedback +*/ +void CFB_Decryption::feedback() + { + for(u32bit j = 0; j != BLOCK_SIZE - FEEDBACK_SIZE; ++j) + state[j] = state[j + FEEDBACK_SIZE]; + state.copy(BLOCK_SIZE - FEEDBACK_SIZE, buffer, FEEDBACK_SIZE); + cipher->encrypt(state, buffer); + position = 0; + } + +} diff --git a/botan/src/modes/cfb/cfb.h b/botan/src/modes/cfb/cfb.h new file mode 100644 index 0000000..7810c00 --- /dev/null +++ b/botan/src/modes/cfb/cfb.h @@ -0,0 +1,47 @@ +/* +* CFB Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CFB_H__ +#define BOTAN_CFB_H__ + +#include <botan/modebase.h> + +namespace Botan { + +/* +* CFB Encryption +*/ +class BOTAN_DLL CFB_Encryption : public BlockCipherMode + { + public: + CFB_Encryption(BlockCipher*, u32bit = 0); + CFB_Encryption(BlockCipher*, const SymmetricKey&, + const InitializationVector&, u32bit = 0); + private: + void write(const byte[], u32bit); + void feedback(); + const u32bit FEEDBACK_SIZE; + }; + +/* +* CFB Decryption +*/ +class BOTAN_DLL CFB_Decryption : public BlockCipherMode + { + public: + CFB_Decryption(BlockCipher*, u32bit = 0); + CFB_Decryption(BlockCipher*, const SymmetricKey&, + const InitializationVector&, u32bit = 0); + private: + void write(const byte[], u32bit); + void feedback(); + const u32bit FEEDBACK_SIZE; + }; + +} + +#endif diff --git a/botan/src/modes/cfb/info.txt b/botan/src/modes/cfb/info.txt new file mode 100644 index 0000000..d66df1e --- /dev/null +++ b/botan/src/modes/cfb/info.txt @@ -0,0 +1,15 @@ +realname "CFB block cipher mode" + +define CFB + +load_on auto + +<add> +cfb.cpp +cfb.h +</add> + +<requires> +modes +</requires> + diff --git a/botan/src/modes/ctr/ctr.cpp b/botan/src/modes/ctr/ctr.cpp new file mode 100644 index 0000000..9eb42ec --- /dev/null +++ b/botan/src/modes/ctr/ctr.cpp @@ -0,0 +1,75 @@ +/* +* CTR Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/ctr.h> +#include <botan/xor_buf.h> +#include <algorithm> + +namespace Botan { + +/* +* CTR-BE Constructor +*/ +CTR_BE::CTR_BE(BlockCipher* ciph) : + BlockCipherMode(ciph, "CTR-BE", ciph->BLOCK_SIZE, 1) + { + } + +/* +* CTR-BE Constructor +*/ +CTR_BE::CTR_BE(BlockCipher* ciph, const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(ciph, "CTR-BE", ciph->BLOCK_SIZE, 1) + { + set_key(key); + set_iv(iv); + } + +/* +* CTR-BE Encryption/Decryption +*/ +void CTR_BE::write(const byte input[], u32bit length) + { + u32bit copied = std::min(BLOCK_SIZE - position, length); + xor_buf(buffer + position, input, copied); + send(buffer + position, copied); + input += copied; + length -= copied; + position += copied; + + if(position == BLOCK_SIZE) + increment_counter(); + + while(length >= BLOCK_SIZE) + { + xor_buf(buffer, input, BLOCK_SIZE); + send(buffer, BLOCK_SIZE); + + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + increment_counter(); + } + + xor_buf(buffer + position, input, length); + send(buffer + position, length); + position += length; + } + +/* +* Increment the counter and update the buffer +*/ +void CTR_BE::increment_counter() + { + for(s32bit j = BLOCK_SIZE - 1; j >= 0; --j) + if(++state[j]) + break; + cipher->encrypt(state, buffer); + position = 0; + } + +} diff --git a/botan/src/modes/ctr/ctr.h b/botan/src/modes/ctr/ctr.h new file mode 100644 index 0000000..aa0db57 --- /dev/null +++ b/botan/src/modes/ctr/ctr.h @@ -0,0 +1,31 @@ +/* +* CTR Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_COUNTER_MODE_H__ +#define BOTAN_COUNTER_MODE_H__ + +#include <botan/modebase.h> +#include <botan/modebase.h> + +namespace Botan { + +/* +* CTR-BE Mode +*/ +class BOTAN_DLL CTR_BE : public BlockCipherMode + { + public: + CTR_BE(BlockCipher*); + CTR_BE(BlockCipher*, const SymmetricKey&, const InitializationVector&); + private: + void write(const byte[], u32bit); + void increment_counter(); + }; + +} + +#endif diff --git a/botan/src/modes/ctr/info.txt b/botan/src/modes/ctr/info.txt new file mode 100644 index 0000000..cb291a2 --- /dev/null +++ b/botan/src/modes/ctr/info.txt @@ -0,0 +1,15 @@ +realname "CTR block cipher mode" + +define CTR + +load_on auto + +<add> +ctr.cpp +ctr.h +</add> + +<requires> +modes +</requires> + diff --git a/botan/src/modes/cts/cts.cpp b/botan/src/modes/cts/cts.cpp new file mode 100644 index 0000000..99f042f --- /dev/null +++ b/botan/src/modes/cts/cts.cpp @@ -0,0 +1,134 @@ +/* +* CTS Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/cts.h> +#include <botan/xor_buf.h> +#include <algorithm> + +namespace Botan { + +/* +* Encrypt a block +*/ +void CTS_Encryption::encrypt(const byte block[]) + { + xor_buf(state, block, BLOCK_SIZE); + cipher->encrypt(state); + send(state, BLOCK_SIZE); + } + +/* +* Encrypt in CTS mode +*/ +void CTS_Encryption::write(const byte input[], u32bit length) + { + u32bit copied = std::min(BUFFER_SIZE - position, length); + buffer.copy(position, input, copied); + length -= copied; + input += copied; + position += copied; + + if(length == 0) return; + + encrypt(buffer); + if(length > BLOCK_SIZE) + { + encrypt(buffer + BLOCK_SIZE); + while(length > 2*BLOCK_SIZE) + { + encrypt(input); + length -= BLOCK_SIZE; + input += BLOCK_SIZE; + } + position = 0; + } + else + { + copy_mem(buffer.begin(), buffer + BLOCK_SIZE, BLOCK_SIZE); + position = BLOCK_SIZE; + } + buffer.copy(position, input, length); + position += length; + } + +/* +* Finish encrypting in CTS mode +*/ +void CTS_Encryption::end_msg() + { + if(position < BLOCK_SIZE + 1) + throw Exception("CTS_Encryption: insufficient data to encrypt"); + xor_buf(state, buffer, BLOCK_SIZE); + cipher->encrypt(state); + SecureVector<byte> cn = state; + clear_mem(buffer + position, BUFFER_SIZE - position); + encrypt(buffer + BLOCK_SIZE); + send(cn, position - BLOCK_SIZE); + } + +/* +* Decrypt a block +*/ +void CTS_Decryption::decrypt(const byte block[]) + { + cipher->decrypt(block, temp); + xor_buf(temp, state, BLOCK_SIZE); + send(temp, BLOCK_SIZE); + state.copy(block, BLOCK_SIZE); + } + +/* +* Decrypt in CTS mode +*/ +void CTS_Decryption::write(const byte input[], u32bit length) + { + u32bit copied = std::min(BUFFER_SIZE - position, length); + buffer.copy(position, input, copied); + length -= copied; + input += copied; + position += copied; + + if(length == 0) return; + + decrypt(buffer); + if(length > BLOCK_SIZE) + { + decrypt(buffer + BLOCK_SIZE); + while(length > 2*BLOCK_SIZE) + { + decrypt(input); + length -= BLOCK_SIZE; + input += BLOCK_SIZE; + } + position = 0; + } + else + { + copy_mem(buffer.begin(), buffer + BLOCK_SIZE, BLOCK_SIZE); + position = BLOCK_SIZE; + } + buffer.copy(position, input, length); + position += length; + } + +/* +* Finish decrypting in CTS mode +*/ +void CTS_Decryption::end_msg() + { + cipher->decrypt(buffer, temp); + xor_buf(temp, buffer + BLOCK_SIZE, position - BLOCK_SIZE); + SecureVector<byte> xn = temp; + copy_mem(buffer + position, xn + (position - BLOCK_SIZE), + BUFFER_SIZE - position); + cipher->decrypt(buffer + BLOCK_SIZE, temp); + xor_buf(temp, state, BLOCK_SIZE); + send(temp, BLOCK_SIZE); + send(xn, position - BLOCK_SIZE); + } + +} diff --git a/botan/src/modes/cts/cts.h b/botan/src/modes/cts/cts.h new file mode 100644 index 0000000..9b17203 --- /dev/null +++ b/botan/src/modes/cts/cts.h @@ -0,0 +1,60 @@ +/* +* CTS Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CTS_H__ +#define BOTAN_CTS_H__ + +#include <botan/modebase.h> +#include <botan/block_cipher.h> + +namespace Botan { + +/* +* CTS Encryption +*/ +class BOTAN_DLL CTS_Encryption : public BlockCipherMode + { + public: + CTS_Encryption(BlockCipher* ciph) : + BlockCipherMode(ciph, "CTS", ciph->BLOCK_SIZE, 0, 2) {} + + CTS_Encryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(ciph, "CTS", ciph->BLOCK_SIZE, 0, 2) + { set_key(key); set_iv(iv); } + private: + void write(const byte[], u32bit); + void end_msg(); + void encrypt(const byte[]); + }; + +/* +* CTS Decryption +*/ +class BOTAN_DLL CTS_Decryption : public BlockCipherMode + { + public: + CTS_Decryption(BlockCipher* ciph) : + BlockCipherMode(ciph, "CTS", ciph->BLOCK_SIZE, 0, 2) + { temp.create(BLOCK_SIZE); } + + CTS_Decryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(ciph, "CTS", ciph->BLOCK_SIZE, 0, 2) + { set_key(key); set_iv(iv); temp.create(BLOCK_SIZE); } + private: + void write(const byte[], u32bit); + void end_msg(); + void decrypt(const byte[]); + SecureVector<byte> temp; + }; + +} + +#endif diff --git a/botan/src/modes/cts/info.txt b/botan/src/modes/cts/info.txt new file mode 100644 index 0000000..9eb16ad --- /dev/null +++ b/botan/src/modes/cts/info.txt @@ -0,0 +1,14 @@ +realname "CTS block cipher mode" + +define CTS + +load_on auto + +<add> +cts.cpp +cts.h +</add> + +<requires> +block +</requires> diff --git a/botan/src/modes/eax/eax.cpp b/botan/src/modes/eax/eax.cpp new file mode 100644 index 0000000..67465a7 --- /dev/null +++ b/botan/src/modes/eax/eax.cpp @@ -0,0 +1,172 @@ +/* +* 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/xor_buf.h> +#include <botan/parsing.h> +#include <algorithm> + +namespace Botan { + +namespace { + +/* +* EAX MAC-based PRF +*/ +SecureVector<byte> eax_prf(byte tag, u32bit BLOCK_SIZE, + MessageAuthenticationCode* mac, + const byte in[], u32bit length) + { + for(u32bit j = 0; j != BLOCK_SIZE - 1; ++j) + mac->update(0); + mac->update(tag); + mac->update(in, length); + return mac->final(); + } + +} + +/* +* EAX_Base Constructor +*/ +EAX_Base::EAX_Base(BlockCipher* ciph, + u32bit tag_size) : + TAG_SIZE(tag_size ? tag_size / 8 : ciph->BLOCK_SIZE), + BLOCK_SIZE(ciph->BLOCK_SIZE) + { + cipher = ciph; + mac = new CMAC(cipher->clone()); + + if(tag_size % 8 != 0 || TAG_SIZE == 0 || TAG_SIZE > mac->OUTPUT_LENGTH) + throw Invalid_Argument(name() + ": Bad tag size " + to_string(tag_size)); + + state.create(BLOCK_SIZE); + buffer.create(BLOCK_SIZE); + position = 0; + } + +/* +* Check if a keylength is valid for EAX +*/ +bool EAX_Base::valid_keylength(u32bit n) const + { + if(!cipher->valid_keylength(n)) + return false; + if(!mac->valid_keylength(n)) + return false; + return true; + } + +/* +* Set the EAX key +*/ +void EAX_Base::set_key(const SymmetricKey& key) + { + cipher->set_key(key); + mac->set_key(key); + header_mac = eax_prf(1, BLOCK_SIZE, mac, 0, 0); + } + +/* +* Do setup at the start of each message +*/ +void EAX_Base::start_msg() + { + for(u32bit j = 0; j != BLOCK_SIZE - 1; ++j) + mac->update(0); + mac->update(2); + } + +/* +* Set the EAX nonce +*/ +void EAX_Base::set_iv(const InitializationVector& iv) + { + nonce_mac = eax_prf(0, BLOCK_SIZE, mac, iv.begin(), iv.length()); + state = nonce_mac; + cipher->encrypt(state, buffer); + } + +/* +* Set the EAX header +*/ +void EAX_Base::set_header(const byte header[], u32bit length) + { + header_mac = eax_prf(1, BLOCK_SIZE, mac, header, length); + } + +/* +* Return the name of this cipher mode +*/ +std::string EAX_Base::name() const + { + return (cipher->name() + "/EAX"); + } + +/* +* Increment the counter and update the buffer +*/ +void EAX_Base::increment_counter() + { + for(s32bit j = BLOCK_SIZE - 1; j >= 0; --j) + if(++state[j]) + break; + cipher->encrypt(state, buffer); + position = 0; + } + +/* +* Encrypt in EAX mode +*/ +void EAX_Encryption::write(const byte input[], u32bit length) + { + u32bit copied = std::min(BLOCK_SIZE - position, length); + xor_buf(buffer + position, input, copied); + send(buffer + position, copied); + mac->update(buffer + position, copied); + input += copied; + length -= copied; + position += copied; + + if(position == BLOCK_SIZE) + increment_counter(); + + while(length >= BLOCK_SIZE) + { + xor_buf(buffer, input, BLOCK_SIZE); + send(buffer, BLOCK_SIZE); + mac->update(buffer, BLOCK_SIZE); + + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + increment_counter(); + } + + xor_buf(buffer + position, input, length); + send(buffer + position, length); + mac->update(buffer + position, length); + position += length; + } + +/* +* Finish encrypting in EAX mode +*/ +void EAX_Encryption::end_msg() + { + SecureVector<byte> data_mac = mac->final(); + xor_buf(data_mac, nonce_mac, data_mac.size()); + xor_buf(data_mac, header_mac, data_mac.size()); + + send(data_mac, TAG_SIZE); + + state.clear(); + buffer.clear(); + position = 0; + } + +} diff --git a/botan/src/modes/eax/eax.h b/botan/src/modes/eax/eax.h new file mode 100644 index 0000000..1bb2e51 --- /dev/null +++ b/botan/src/modes/eax/eax.h @@ -0,0 +1,85 @@ +/* +* EAX Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EAX_H__ +#define BOTAN_EAX_H__ + +#include <botan/basefilt.h> +#include <botan/block_cipher.h> +#include <botan/mac.h> + +namespace Botan { + +/* +* EAX Base Class +*/ +class BOTAN_DLL EAX_Base : public Keyed_Filter + { + public: + void set_key(const SymmetricKey&); + void set_iv(const InitializationVector&); + void set_header(const byte[], u32bit); + std::string name() const; + + bool valid_keylength(u32bit) const; + + ~EAX_Base() { delete cipher; delete mac; } + protected: + EAX_Base(BlockCipher*, u32bit); + void start_msg(); + void increment_counter(); + + const u32bit TAG_SIZE, BLOCK_SIZE; + BlockCipher* cipher; + MessageAuthenticationCode* mac; + SecureVector<byte> nonce_mac, header_mac, state, buffer; + u32bit position; + }; + +/* +* EAX Encryption +*/ +class BOTAN_DLL EAX_Encryption : public EAX_Base + { + public: + EAX_Encryption(BlockCipher* ciph, u32bit tag_size = 0) : + EAX_Base(ciph, tag_size) {} + + EAX_Encryption(BlockCipher* ciph, const SymmetricKey& key, + const InitializationVector& iv, + u32bit tag_size) : EAX_Base(ciph, tag_size) + { + set_key(key); + set_iv(iv); + } + private: + void write(const byte[], u32bit); + void end_msg(); + }; + +/* +* EAX Decryption +*/ +class BOTAN_DLL EAX_Decryption : public EAX_Base + { + public: + EAX_Decryption(BlockCipher* ciph, u32bit tag_size = 0); + + EAX_Decryption(BlockCipher* ciph, const SymmetricKey& key, + const InitializationVector& iv, + u32bit tag_size = 0); + private: + void write(const byte[], u32bit); + void do_write(const byte[], u32bit); + void end_msg(); + SecureVector<byte> queue; + u32bit queue_start, queue_end; + }; + +} + +#endif diff --git a/botan/src/modes/eax/eax_dec.cpp b/botan/src/modes/eax/eax_dec.cpp new file mode 100644 index 0000000..b7e5795 --- /dev/null +++ b/botan/src/modes/eax/eax_dec.cpp @@ -0,0 +1,127 @@ +/* +* EAX Mode Encryption +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/eax.h> +#include <botan/xor_buf.h> +#include <botan/parsing.h> +#include <algorithm> + +namespace Botan { + +/* +* EAX_Decryption Constructor +*/ +EAX_Decryption::EAX_Decryption(BlockCipher* ciph, + u32bit tag_size) : + EAX_Base(ciph, tag_size) + { + queue.create(2*TAG_SIZE + DEFAULT_BUFFERSIZE); + queue_start = queue_end = 0; + } + +/* +* EAX_Decryption Constructor +*/ +EAX_Decryption::EAX_Decryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv, + u32bit tag_size) : + EAX_Base(ciph, tag_size) + { + set_key(key); + set_iv(iv); + queue.create(2*TAG_SIZE + DEFAULT_BUFFERSIZE); + queue_start = queue_end = 0; + } + +/* +* Decrypt in EAX mode +*/ +void EAX_Decryption::write(const byte input[], u32bit length) + { + while(length) + { + const u32bit copied = std::min(length, queue.size() - queue_end); + + queue.copy(queue_end, input, copied); + input += copied; + length -= copied; + queue_end += copied; + + SecureVector<byte> block_buf(cipher->BLOCK_SIZE); + while((queue_end - queue_start) > TAG_SIZE) + { + u32bit removed = (queue_end - queue_start) - TAG_SIZE; + do_write(queue + queue_start, removed); + queue_start += removed; + } + + if(queue_start + TAG_SIZE == queue_end && + queue_start >= queue.size() / 2) + { + SecureVector<byte> queue_data(TAG_SIZE); + queue_data.copy(queue + queue_start, TAG_SIZE); + queue.copy(queue_data, TAG_SIZE); + queue_start = 0; + queue_end = TAG_SIZE; + } + } + } + +/* +* Decrypt in EAX mode +*/ +void EAX_Decryption::do_write(const byte input[], u32bit length) + { + mac->update(input, length); + + u32bit copied = std::min(BLOCK_SIZE - position, length); + xor_buf(buffer + position, input, copied); + send(buffer + position, copied); + input += copied; + length -= copied; + position += copied; + + if(position == BLOCK_SIZE) + increment_counter(); + + while(length >= BLOCK_SIZE) + { + xor_buf(buffer, input, BLOCK_SIZE); + send(buffer, BLOCK_SIZE); + + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + increment_counter(); + } + + xor_buf(buffer + position, input, length); + send(buffer + position, length); + position += length; + } + +/* +* Finish decrypting in EAX mode +*/ +void EAX_Decryption::end_msg() + { + if((queue_end - queue_start) != TAG_SIZE) + throw Integrity_Failure(name() + ": Message authentication failure"); + + SecureVector<byte> data_mac = mac->final(); + + for(u32bit j = 0; j != TAG_SIZE; ++j) + if(queue[queue_start+j] != (data_mac[j] ^ nonce_mac[j] ^ header_mac[j])) + throw Integrity_Failure(name() + ": Message authentication failure"); + + state.clear(); + buffer.clear(); + position = 0; + queue_start = queue_end = 0; + } + +} diff --git a/botan/src/modes/eax/info.txt b/botan/src/modes/eax/info.txt new file mode 100644 index 0000000..d1fc7e0 --- /dev/null +++ b/botan/src/modes/eax/info.txt @@ -0,0 +1,18 @@ +realname "EAX block cipher mode" + +define EAX + +load_on auto + +<add> +eax.cpp +eax.h +eax_dec.cpp +</add> + +<requires> +block +cmac +filters +mac +</requires> diff --git a/botan/src/modes/ecb/ecb.cpp b/botan/src/modes/ecb/ecb.cpp new file mode 100644 index 0000000..8da0a48 --- /dev/null +++ b/botan/src/modes/ecb/ecb.cpp @@ -0,0 +1,105 @@ +/* +* ECB Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/ecb.h> + +namespace Botan { + +/* +* Verify the IV is not set +*/ +bool ECB::valid_iv_size(u32bit iv_size) const + { + if(iv_size == 0) + return true; + return false; + } + +/* +* Return an ECB mode name +*/ +std::string ECB::name() const + { + return (cipher->name() + "/" + mode_name + "/" + padder->name()); + } + +/* +* Encrypt in ECB mode +*/ +void ECB_Encryption::write(const byte input[], u32bit length) + { + buffer.copy(position, input, length); + if(position + length >= BLOCK_SIZE) + { + cipher->encrypt(buffer); + send(buffer, BLOCK_SIZE); + input += (BLOCK_SIZE - position); + length -= (BLOCK_SIZE - position); + while(length >= BLOCK_SIZE) + { + cipher->encrypt(input, buffer); + send(buffer, BLOCK_SIZE); + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + } + buffer.copy(input, length); + position = 0; + } + position += length; + } + +/* +* Finish encrypting in ECB mode +*/ +void ECB_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 Encoding_Error(name() + ": Did not pad to full blocksize"); + } + +/* +* Decrypt in ECB mode +*/ +void ECB_Decryption::write(const byte input[], u32bit length) + { + buffer.copy(position, input, length); + if(position + length > BLOCK_SIZE) + { + cipher->decrypt(buffer); + send(buffer, BLOCK_SIZE); + input += (BLOCK_SIZE - position); + length -= (BLOCK_SIZE - position); + while(length > BLOCK_SIZE) + { + cipher->decrypt(input, buffer); + send(buffer, BLOCK_SIZE); + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + } + buffer.copy(input, length); + position = 0; + } + position += length; + } + +/* +* Finish decrypting in ECB mode +*/ +void ECB_Decryption::end_msg() + { + if(position != BLOCK_SIZE) + throw Decoding_Error(name()); + cipher->decrypt(buffer); + send(buffer, padder->unpad(buffer, BLOCK_SIZE)); + state = buffer; + position = 0; + } + +} diff --git a/botan/src/modes/ecb/ecb.h b/botan/src/modes/ecb/ecb.h new file mode 100644 index 0000000..5230f9b --- /dev/null +++ b/botan/src/modes/ecb/ecb.h @@ -0,0 +1,73 @@ +/* +* ECB Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECB_H__ +#define BOTAN_ECB_H__ + +#include <botan/modebase.h> +#include <botan/mode_pad.h> +#include <botan/block_cipher.h> + +namespace Botan { + +/* +* ECB +*/ +class BOTAN_DLL ECB : public BlockCipherMode + { + protected: + ECB(BlockCipher* ciph, BlockCipherModePaddingMethod* pad) : + BlockCipherMode(ciph, "ECB", 0), padder(pad) {} + ~ECB() { delete padder; } + + std::string name() const; + BlockCipherModePaddingMethod* padder; + private: + bool valid_iv_size(u32bit) const; + }; + +/* +* ECB Encryption +*/ +class BOTAN_DLL ECB_Encryption : public ECB + { + public: + ECB_Encryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad) : + ECB(ciph, pad) {} + + ECB_Encryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad, + const SymmetricKey& key) : + ECB(ciph, pad) { set_key(key); } + private: + void write(const byte[], u32bit); + void end_msg(); + }; + +/* +* ECB Decryption +*/ +class BOTAN_DLL ECB_Decryption : public ECB + { + public: + ECB_Decryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad) : + ECB(ciph, pad) {} + + ECB_Decryption(BlockCipher* ciph, + BlockCipherModePaddingMethod* pad, + const SymmetricKey& key) : + ECB(ciph, pad) { set_key(key); } + private: + void write(const byte[], u32bit); + void end_msg(); + }; + +} + +#endif diff --git a/botan/src/modes/ecb/info.txt b/botan/src/modes/ecb/info.txt new file mode 100644 index 0000000..06b7b4f --- /dev/null +++ b/botan/src/modes/ecb/info.txt @@ -0,0 +1,15 @@ +realname "ECB block cipher mode" + +define ECB + +load_on auto + +<add> +ecb.cpp +ecb.h +</add> + +<requires> +block +mode_pad +</requires> diff --git a/botan/src/modes/info.txt b/botan/src/modes/info.txt new file mode 100644 index 0000000..e089e74 --- /dev/null +++ b/botan/src/modes/info.txt @@ -0,0 +1,15 @@ +realname "Cipher Mode Base Class" + +define CIPHER_MODEBASE + +load_on auto + +<add> +modebase.cpp +modebase.h +</add> + +<requires> +block +filters +</requires> diff --git a/botan/src/modes/mode_pad/info.txt b/botan/src/modes/mode_pad/info.txt new file mode 100644 index 0000000..f22cf74 --- /dev/null +++ b/botan/src/modes/mode_pad/info.txt @@ -0,0 +1,10 @@ +realname "Cipher Mode Padding Method" + +define CIPHER_MODE_PADDING + +load_on auto + +<add> +mode_pad.cpp +mode_pad.h +</add> diff --git a/botan/src/modes/mode_pad/mode_pad.cpp b/botan/src/modes/mode_pad/mode_pad.cpp new file mode 100644 index 0000000..b8badd7 --- /dev/null +++ b/botan/src/modes/mode_pad/mode_pad.cpp @@ -0,0 +1,128 @@ +/* +* CBC Padding Methods +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/mode_pad.h> +#include <botan/exceptn.h> +#include <botan/util.h> + +namespace Botan { + +/* +* Default amount of padding +*/ +u32bit BlockCipherModePaddingMethod::pad_bytes(u32bit bs, u32bit pos) const + { + return (bs - pos); + } + +/* +* Pad with PKCS #7 Method +*/ +void PKCS7_Padding::pad(byte block[], u32bit size, u32bit position) const + { + for(u32bit j = 0; j != size; ++j) + block[j] = (size-position); + } + +/* +* Unpad with PKCS #7 Method +*/ +u32bit PKCS7_Padding::unpad(const byte block[], u32bit size) const + { + u32bit position = block[size-1]; + if(position > size) + throw Decoding_Error(name()); + for(u32bit j = size-position; j != size-1; ++j) + if(block[j] != position) + throw Decoding_Error(name()); + return (size-position); + } + +/* +* Query if the size is valid for this method +*/ +bool PKCS7_Padding::valid_blocksize(u32bit size) const + { + if(size > 0 && size < 256) + return true; + else + return false; + } + +/* +* Pad with ANSI X9.23 Method +*/ +void ANSI_X923_Padding::pad(byte block[], u32bit size, u32bit position) const + { + for(u32bit j = 0; j != size-position; ++j) + block[j] = 0; + block[size-position-1] = (size-position); + } + +/* +* Unpad with ANSI X9.23 Method +*/ +u32bit ANSI_X923_Padding::unpad(const byte block[], u32bit size) const + { + u32bit position = block[size-1]; + if(position > size) + throw Decoding_Error(name()); + for(u32bit j = size-position; j != size-1; ++j) + if(block[j] != 0) + throw Decoding_Error(name()); + return (size-position); + } + +/* +* Query if the size is valid for this method +*/ +bool ANSI_X923_Padding::valid_blocksize(u32bit size) const + { + if(size > 0 && size < 256) + return true; + else + return false; + } + +/* +* Pad with One and Zeros Method +*/ +void OneAndZeros_Padding::pad(byte block[], u32bit size, u32bit) const + { + block[0] = 0x80; + for(u32bit j = 1; j != size; ++j) + block[j] = 0x00; + } + +/* +* Unpad with One and Zeros Method +*/ +u32bit OneAndZeros_Padding::unpad(const byte block[], u32bit size) const + { + while(size) + { + if(block[size-1] == 0x80) + break; + if(block[size-1] != 0x00) + throw Decoding_Error(name()); + size--; + } + if(!size) + throw Decoding_Error(name()); + return (size-1); + } + +/* +* Query if the size is valid for this method +*/ +bool OneAndZeros_Padding::valid_blocksize(u32bit size) const + { + if(size) return true; + else return false; + } + +} diff --git a/botan/src/modes/mode_pad/mode_pad.h b/botan/src/modes/mode_pad/mode_pad.h new file mode 100644 index 0000000..a486d3c --- /dev/null +++ b/botan/src/modes/mode_pad/mode_pad.h @@ -0,0 +1,120 @@ +/** +* CBC Padding Methods +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CBC_PADDING_H__ +#define BOTAN_CBC_PADDING_H__ + +#include <botan/types.h> +#include <string> + +namespace Botan { + +/** +* Block Cipher Mode Padding Method +* This class is pretty limited, it cannot deal well with +* randomized padding methods, or any padding method that +* wants to add more than one block. For instance, it should +* be possible to define cipher text stealing mode as simply +* a padding mode for CBC, which happens to consume the last +* two block (and requires use of the block cipher). +*/ +class BOTAN_DLL BlockCipherModePaddingMethod + { + public: + /** + * @param block output buffer + * @param size of the block + * @param current_position in the last block + */ + virtual void pad(byte block[], + u32bit size, + u32bit current_position) const = 0; + + /** + * @param block the last block + * @param size the of the block + */ + virtual u32bit unpad(const byte block[], + u32bit size) const = 0; + + /** + * @param block_size of the cipher + * @param position in the current block + * @return number of padding bytes that will be appended + */ + virtual u32bit pad_bytes(u32bit block_size, + u32bit position) const; + + /** + * @param block_size of the cipher + * @return valid block size for this padding mode + */ + virtual bool valid_blocksize(u32bit block_size) const = 0; + + /** + * @return name of the mode + */ + virtual std::string name() const = 0; + + /** + * virtual destructor + */ + virtual ~BlockCipherModePaddingMethod() {} + }; + +/** +* PKCS#7 Padding +*/ +class BOTAN_DLL PKCS7_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], u32bit, u32bit) const; + u32bit unpad(const byte[], u32bit) const; + bool valid_blocksize(u32bit) const; + std::string name() const { return "PKCS7"; } + }; + +/** +* ANSI X9.23 Padding +*/ +class BOTAN_DLL ANSI_X923_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], u32bit, u32bit) const; + u32bit unpad(const byte[], u32bit) const; + bool valid_blocksize(u32bit) const; + std::string name() const { return "X9.23"; } + }; + +/** +* One And Zeros Padding +*/ +class BOTAN_DLL OneAndZeros_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], u32bit, u32bit) const; + u32bit unpad(const byte[], u32bit) const; + bool valid_blocksize(u32bit) const; + std::string name() const { return "OneAndZeros"; } + }; + +/** +* Null Padding +*/ +class BOTAN_DLL Null_Padding : public BlockCipherModePaddingMethod + { + public: + void pad(byte[], u32bit, u32bit) const { return; } + u32bit unpad(const byte[], u32bit size) const { return size; } + u32bit pad_bytes(u32bit, u32bit) const { return 0; } + bool valid_blocksize(u32bit) const { return true; } + std::string name() const { return "NoPadding"; } + }; + +} + +#endif diff --git a/botan/src/modes/modebase.cpp b/botan/src/modes/modebase.cpp new file mode 100644 index 0000000..8293acc --- /dev/null +++ b/botan/src/modes/modebase.cpp @@ -0,0 +1,54 @@ +/* +* Block Cipher Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/modebase.h> + +namespace Botan { + +/* +* Block Cipher Mode Constructor +*/ +BlockCipherMode::BlockCipherMode(BlockCipher* cipher_ptr, + const std::string& cipher_mode_name, + u32bit iv_size, u32bit iv_meth, + u32bit buf_mult) : + BLOCK_SIZE(cipher_ptr->BLOCK_SIZE), BUFFER_SIZE(buf_mult * BLOCK_SIZE), + IV_METHOD(iv_meth), mode_name(cipher_mode_name) + { + base_ptr = cipher = cipher_ptr; + buffer.create(BUFFER_SIZE); + state.create(iv_size); + position = 0; + } + +/* +* Return the name of this type +*/ +std::string BlockCipherMode::name() const + { + return (cipher->name() + "/" + mode_name); + } + +/* +* Set the IV +*/ +void BlockCipherMode::set_iv(const InitializationVector& new_iv) + { + if(new_iv.length() != state.size()) + throw Invalid_IV_Length(name(), new_iv.length()); + + state = new_iv.bits_of(); + buffer.clear(); + position = 0; + + if(IV_METHOD == 1) + cipher->encrypt(state, buffer); + else if(IV_METHOD == 2) + cipher->encrypt(state); + } + +} diff --git a/botan/src/modes/modebase.h b/botan/src/modes/modebase.h new file mode 100644 index 0000000..173fde5 --- /dev/null +++ b/botan/src/modes/modebase.h @@ -0,0 +1,39 @@ +/* +* Block Cipher Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MODEBASE_H__ +#define BOTAN_MODEBASE_H__ + +#include <botan/basefilt.h> +#include <botan/block_cipher.h> + +namespace Botan { + +/** +* This class represents an abstract block cipher mode +*/ +class BOTAN_DLL BlockCipherMode : public Keyed_Filter + { + public: + std::string name() const; + + BlockCipherMode(BlockCipher*, const std::string&, + u32bit, u32bit = 0, u32bit = 1); + + virtual ~BlockCipherMode() { delete cipher; } + protected: + void set_iv(const InitializationVector&); + const u32bit BLOCK_SIZE, BUFFER_SIZE, IV_METHOD; + const std::string mode_name; + BlockCipher* cipher; + SecureVector<byte> buffer, state; + u32bit position; + }; + +} + +#endif diff --git a/botan/src/modes/ofb/info.txt b/botan/src/modes/ofb/info.txt new file mode 100644 index 0000000..3cba415 --- /dev/null +++ b/botan/src/modes/ofb/info.txt @@ -0,0 +1,14 @@ +realname "OFB block cipher mode" + +define OFB + +load_on auto + +<add> +ofb.cpp +ofb.h +</add> + +<requires> +block +</requires> diff --git a/botan/src/modes/ofb/ofb.cpp b/botan/src/modes/ofb/ofb.cpp new file mode 100644 index 0000000..cb40fde --- /dev/null +++ b/botan/src/modes/ofb/ofb.cpp @@ -0,0 +1,66 @@ +/* +* OFB Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/ofb.h> +#include <botan/xor_buf.h> +#include <algorithm> + +namespace Botan { + +/* +* OFB Constructor +*/ +OFB::OFB(BlockCipher* ciph) : + BlockCipherMode(ciph, "OFB", ciph->BLOCK_SIZE, 2) + { + } + +/* +* OFB Constructor +*/ +OFB::OFB(BlockCipher* ciph, const SymmetricKey& key, + const InitializationVector& iv) : + BlockCipherMode(ciph, "OFB", ciph->BLOCK_SIZE, 2) + { + set_key(key); + set_iv(iv); + } + +/* +* OFB Encryption/Decryption +*/ +void OFB::write(const byte input[], u32bit length) + { + u32bit copied = std::min(BLOCK_SIZE - position, length); + xor_buf(buffer, input, state + position, copied); + send(buffer, copied); + input += copied; + length -= copied; + position += copied; + + if(position == BLOCK_SIZE) + { + cipher->encrypt(state); + position = 0; + } + + while(length >= BLOCK_SIZE) + { + xor_buf(buffer, input, state, BLOCK_SIZE); + send(buffer, BLOCK_SIZE); + + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + cipher->encrypt(state); + } + + xor_buf(buffer, input, state + position, length); + send(buffer, length); + position += length; + } + +} diff --git a/botan/src/modes/ofb/ofb.h b/botan/src/modes/ofb/ofb.h new file mode 100644 index 0000000..a3aadc1 --- /dev/null +++ b/botan/src/modes/ofb/ofb.h @@ -0,0 +1,33 @@ +/* +* OFB Mode +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OUTPUT_FEEDBACK_MODE_H__ +#define BOTAN_OUTPUT_FEEDBACK_MODE_H__ + +#include <botan/modebase.h> +#include <botan/block_cipher.h> + +namespace Botan { + +/* +* OFB Mode +*/ +class BOTAN_DLL OFB : public BlockCipherMode + { + public: + OFB(BlockCipher* cipher); + + OFB(BlockCipher* cipher, + const SymmetricKey& key, + const InitializationVector& iv); + private: + void write(const byte[], u32bit); + }; + +} + +#endif diff --git a/botan/src/modes/xts/info.txt b/botan/src/modes/xts/info.txt new file mode 100644 index 0000000..65c7df2 --- /dev/null +++ b/botan/src/modes/xts/info.txt @@ -0,0 +1,15 @@ +realname "XTS block cipher mode" + +define XTS + +load_on auto + +<add> +xts.cpp +xts.h +</add> + +<requires> +block +filters +</requires> diff --git a/botan/src/modes/xts/xts.cpp b/botan/src/modes/xts/xts.cpp new file mode 100644 index 0000000..8780ae1 --- /dev/null +++ b/botan/src/modes/xts/xts.cpp @@ -0,0 +1,344 @@ +/* +* XTS Mode +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/xts.h> +#include <botan/xor_buf.h> +#include <algorithm> +#include <stdexcept> + +namespace Botan { + +namespace { + +void poly_double(byte tweak[], u32bit size) + { + const byte polynomial = 0x87; // for 128 bit ciphers + + byte carry = 0; + for(u32bit i = 0; i != size; ++i) + { + byte carry2 = (tweak[i] >> 7); + tweak[i] = (tweak[i] << 1) | carry; + carry = carry2; + } + + if(carry) + tweak[0] ^= polynomial; + } + +} + +/* +* XTS_Encryption constructor +*/ +XTS_Encryption::XTS_Encryption(BlockCipher* ciph) : cipher(ciph) + { + if(cipher->BLOCK_SIZE != 16) + throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); + + cipher2 = cipher->clone(); + tweak.create(cipher->BLOCK_SIZE); + buffer.create(2 * cipher->BLOCK_SIZE); + position = 0; + } + +/* +* XTS_Encryption constructor +*/ +XTS_Encryption::XTS_Encryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv) : cipher(ciph) + { + if(cipher->BLOCK_SIZE != 16) + throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); + + cipher2 = cipher->clone(); + tweak.create(cipher->BLOCK_SIZE); + buffer.create(2 * cipher->BLOCK_SIZE); + position = 0; + + set_key(key); + set_iv(iv); + } + +/* +* Return the name +*/ +std::string XTS_Encryption::name() const + { + return (cipher->name() + "/XTS"); + } + +/* +* Set new tweak +*/ +void XTS_Encryption::set_iv(const InitializationVector& iv) + { + if(iv.length() != tweak.size()) + throw Invalid_IV_Length(name(), iv.length()); + + tweak = iv.bits_of(); + cipher2->encrypt(tweak); + } + +void XTS_Encryption::set_key(const SymmetricKey& key) + { + u32bit key_half = key.length() / 2; + + if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half)) + throw Invalid_Key_Length(name(), key.length()); + + cipher->set_key(key.begin(), key_half); + cipher2->set_key(key.begin() + key_half, key_half); + } + +void XTS_Encryption::encrypt(const byte block[]) + { + /* + * We can always use the first 16 bytes of buffer as temp space, + * since either the input block is buffer (in which case this is + * just buffer ^= tweak) or it not, in which case we already read + * and used the data there and are processing new input. Kind of + * subtle/nasty, but saves allocating a distinct temp buf. + */ + + xor_buf(buffer, block, tweak, cipher->BLOCK_SIZE); + cipher->encrypt(buffer); + xor_buf(buffer, tweak, cipher->BLOCK_SIZE); + + poly_double(tweak, cipher->BLOCK_SIZE); + + send(buffer, cipher->BLOCK_SIZE); + } + +/* +* Encrypt in XTS mode +*/ +void XTS_Encryption::write(const byte input[], u32bit length) + { + const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; + + u32bit copied = std::min(buffer.size() - position, length); + buffer.copy(position, input, copied); + length -= copied; + input += copied; + position += copied; + + if(length == 0) return; + + encrypt(buffer); + if(length > BLOCK_SIZE) + { + encrypt(buffer + BLOCK_SIZE); + while(length > buffer.size()) + { + encrypt(input); + length -= BLOCK_SIZE; + input += BLOCK_SIZE; + } + position = 0; + } + else + { + copy_mem(buffer.begin(), buffer + BLOCK_SIZE, BLOCK_SIZE); + position = BLOCK_SIZE; + } + buffer.copy(position, input, length); + position += length; + } + +/* +* Finish encrypting in XTS mode +*/ +void XTS_Encryption::end_msg() + { + const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; + + if(position < BLOCK_SIZE) + throw Exception("XTS_Encryption: insufficient data to encrypt"); + else if(position == BLOCK_SIZE) + { + encrypt(buffer); + } + else if(position == 2*BLOCK_SIZE) + { + encrypt(buffer); + encrypt(buffer + BLOCK_SIZE); + } + else + { // steal ciphertext + xor_buf(buffer, tweak, cipher->BLOCK_SIZE); + cipher->encrypt(buffer); + xor_buf(buffer, tweak, cipher->BLOCK_SIZE); + + poly_double(tweak, cipher->BLOCK_SIZE); + + for(u32bit i = 0; i != position - cipher->BLOCK_SIZE; ++i) + std::swap(buffer[i], buffer[i + cipher->BLOCK_SIZE]); + + xor_buf(buffer, tweak, cipher->BLOCK_SIZE); + cipher->encrypt(buffer); + xor_buf(buffer, tweak, cipher->BLOCK_SIZE); + + send(buffer, position); + } + + position = 0; + } + +/* +* XTS_Decryption constructor +*/ +XTS_Decryption::XTS_Decryption(BlockCipher* ciph) + { + cipher = ciph; + cipher2 = ciph->clone(); + tweak.create(cipher->BLOCK_SIZE); + buffer.create(2 * cipher->BLOCK_SIZE); + position = 0; + } + +/* +* XTS_Decryption constructor +*/ +XTS_Decryption::XTS_Decryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv) + { + cipher = ciph; + cipher2 = ciph->clone(); + tweak.create(cipher->BLOCK_SIZE); + buffer.create(2 * cipher->BLOCK_SIZE); + position = 0; + + set_key(key); + set_iv(iv); + } + +/* +* Return the name +*/ +std::string XTS_Decryption::name() const + { + return (cipher->name() + "/XTS"); + } + +/* +* Set new tweak +*/ +void XTS_Decryption::set_iv(const InitializationVector& iv) + { + if(iv.length() != tweak.size()) + throw Invalid_IV_Length(name(), iv.length()); + + tweak = iv.bits_of(); + cipher2->encrypt(tweak); + } + +void XTS_Decryption::set_key(const SymmetricKey& key) + { + u32bit key_half = key.length() / 2; + + if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half)) + throw Invalid_Key_Length(name(), key.length()); + + cipher->set_key(key.begin(), key_half); + cipher2->set_key(key.begin() + key_half, key_half); + } + +/* +* Decrypt a block +*/ +void XTS_Decryption::decrypt(const byte block[]) + { + xor_buf(buffer, block, tweak, cipher->BLOCK_SIZE); + cipher->decrypt(buffer); + xor_buf(buffer, tweak, cipher->BLOCK_SIZE); + + poly_double(tweak, cipher->BLOCK_SIZE); + + send(buffer, cipher->BLOCK_SIZE); + } + +/* +* Decrypt in XTS mode +*/ +void XTS_Decryption::write(const byte input[], u32bit length) + { + const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; + + u32bit copied = std::min(buffer.size() - position, length); + buffer.copy(position, input, copied); + length -= copied; + input += copied; + position += copied; + + if(length == 0) return; + + decrypt(buffer); + if(length > BLOCK_SIZE) + { + decrypt(buffer + BLOCK_SIZE); + while(length > 2*BLOCK_SIZE) + { + decrypt(input); + length -= BLOCK_SIZE; + input += BLOCK_SIZE; + } + position = 0; + } + else + { + copy_mem(buffer.begin(), buffer + BLOCK_SIZE, BLOCK_SIZE); + position = BLOCK_SIZE; + } + buffer.copy(position, input, length); + position += length; + } + +/* +* Finish decrypting in XTS mode +*/ +void XTS_Decryption::end_msg() + { + const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; + + if(position < BLOCK_SIZE) + throw Exception("XTS_Decryption: insufficient data to decrypt"); + else if(position == BLOCK_SIZE) + { + decrypt(buffer); + } + else if(position == 2*BLOCK_SIZE) + { + decrypt(buffer); + decrypt(buffer + BLOCK_SIZE); + } + else + { + SecureVector<byte> tweak2 = tweak; + + poly_double(tweak2, cipher->BLOCK_SIZE); + + xor_buf(buffer, tweak2, cipher->BLOCK_SIZE); + cipher->decrypt(buffer); + xor_buf(buffer, tweak2, cipher->BLOCK_SIZE); + + for(u32bit i = 0; i != position - cipher->BLOCK_SIZE; ++i) + std::swap(buffer[i], buffer[i + cipher->BLOCK_SIZE]); + + xor_buf(buffer, tweak, cipher->BLOCK_SIZE); + cipher->decrypt(buffer); + xor_buf(buffer, tweak, cipher->BLOCK_SIZE); + + send(buffer, position); + } + + position = 0; + } + +} diff --git a/botan/src/modes/xts/xts.h b/botan/src/modes/xts/xts.h new file mode 100644 index 0000000..0155817 --- /dev/null +++ b/botan/src/modes/xts/xts.h @@ -0,0 +1,76 @@ +/* +* XTS mode, from IEEE P1619 +* (C) 2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_XTS_H__ +#define BOTAN_XTS_H__ + +#include <botan/basefilt.h> +#include <botan/block_cipher.h> + +namespace Botan { + +/* +* XTS Encryption +*/ +class BOTAN_DLL XTS_Encryption : public Keyed_Filter + { + public: + void set_key(const SymmetricKey& key); + void set_iv(const InitializationVector& iv); + + std::string name() const; + + XTS_Encryption(BlockCipher* ciph); + + XTS_Encryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv); + + ~XTS_Encryption() { delete cipher; delete cipher2; } + private: + void write(const byte[], u32bit); + void end_msg(); + void encrypt(const byte block[]); + + BlockCipher* cipher; + BlockCipher* cipher2; + SecureVector<byte> tweak; + SecureVector<byte> buffer; + u32bit position; + }; + +/* +* XTS Decryption +*/ +class BOTAN_DLL XTS_Decryption : public Keyed_Filter + { + public: + void set_key(const SymmetricKey& key); + void set_iv(const InitializationVector& iv); + + std::string name() const; + + XTS_Decryption(BlockCipher* ciph); + + XTS_Decryption(BlockCipher* ciph, + const SymmetricKey& key, + const InitializationVector& iv); + private: + void write(const byte[], u32bit); + void end_msg(); + void decrypt(const byte[]); + + BlockCipher* cipher; + BlockCipher* cipher2; + SecureVector<byte> tweak; + SecureVector<byte> buffer; + u32bit position; + }; + +} + +#endif |