1 /** 2 * Block Cipher Cascade 3 * 4 * Copyright: 5 * (C) 2010 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.block.cascade; 12 13 import botan.constants; 14 static if (BOTAN_HAS_CASCADE): 15 16 import botan.block.block_cipher; 17 import botan.utils.mem_ops; 18 19 /** 20 * Block Cipher Cascade 21 */ 22 final class CascadeCipher : BlockCipher, SymmetricAlgorithm 23 { 24 public: 25 override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks) 26 { 27 size_t c1_blocks = blocks * (this.blockSize() / m_cipher1.blockSize()); 28 size_t c2_blocks = blocks * (this.blockSize() / m_cipher2.blockSize()); 29 30 m_cipher1.encryptN(input, output, c1_blocks); 31 m_cipher2.encryptN(output, output, c2_blocks); 32 } 33 34 override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks) 35 { 36 size_t c1_blocks = blocks * (this.blockSize() / m_cipher1.blockSize()); 37 size_t c2_blocks = blocks * (this.blockSize() / m_cipher2.blockSize()); 38 39 m_cipher2.decryptN(input, output, c2_blocks); 40 m_cipher1.decryptN(output, output, c1_blocks); 41 } 42 43 override size_t blockSize() const { return m_block; } 44 45 KeyLengthSpecification keySpec() const 46 { 47 return KeyLengthSpecification(m_cipher1.maximumKeylength() + m_cipher2.maximumKeylength()); 48 } 49 50 override void clear() 51 { 52 m_cipher1.clear(); 53 m_cipher2.clear(); 54 } 55 56 @property string name() const 57 { 58 return "Cascade(" ~ m_cipher1.name ~ "," ~ m_cipher2.name ~ ")"; 59 } 60 61 override @property size_t parallelism() const { return 1; } 62 63 override BlockCipher clone() const 64 { 65 return new CascadeCipher(m_cipher1.clone(), m_cipher2.clone()); 66 } 67 68 /** 69 * Create a cascade of two block ciphers 70 * Params: 71 * c1 = the first cipher 72 * c2 = the second cipher 73 */ 74 this(BlockCipher c1, BlockCipher c2) 75 { 76 m_cipher1 = c1; 77 m_cipher2 = c2; 78 m_block = block_size_for_cascade(m_cipher1.blockSize(), m_cipher2.blockSize()); 79 80 if (this.blockSize() % m_cipher1.blockSize() || this.blockSize() % m_cipher2.blockSize()) 81 throw new InternalError("Failure in " ~ name() ~ " constructor"); 82 } 83 protected: 84 override void keySchedule(const(ubyte)* key, size_t) 85 { 86 const(ubyte)* key2 = key + m_cipher1.maximumKeylength(); 87 88 m_cipher1.setKey(key , m_cipher1.maximumKeylength()); 89 m_cipher2.setKey(key2, m_cipher2.maximumKeylength()); 90 } 91 92 size_t m_block; 93 Unique!BlockCipher m_cipher1, m_cipher2; 94 } 95 96 private: 97 98 size_t euclids_algorithm(size_t a, size_t b) 99 { 100 while (b != 0) // gcd 101 { 102 size_t t = b; 103 b = a % b; 104 a = t; 105 } 106 107 return a; 108 } 109 110 size_t block_size_for_cascade(size_t bs, size_t bs2) 111 { 112 if (bs == bs2) 113 return bs; 114 115 size_t gcd = euclids_algorithm(bs, bs2); 116 117 return (bs * bs2) / gcd; 118 }