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 }