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 }