1 /**
2 * Lion
3 * 
4 * Copyright:
5 * (C) 1999-2007,2014 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.lion;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_LION):
15 
16 import botan.block.block_cipher;
17 import botan.stream.stream_cipher;
18 import botan.hash.hash;
19 import botan.utils.xor_buf;
20 import botan.utils.parsing;
21 import botan.utils.mem_ops;
22 import std.conv : to;
23 import std.algorithm : max;
24 import botan.utils.mem_ops;
25 
26 /**
27 * Lion is a block cipher construction designed by Ross Anderson and
28 * Eli Biham, described in "Two Practical and Provably Secure Block
29 * Ciphers: BEAR and LION". It has a variable block size and is
30 * designed to encrypt very large blocks (up to a megabyte)
31 
32 * http://www.cl.cam.ac.uk/~rja14/Papers/bear-lion.pdf
33 */
34 final class Lion : BlockCipher, SymmetricAlgorithm
35 {
36 public:
37     /*
38     * Lion Encryption
39     */
40     override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks)
41     {
42         const size_t LEFT_SIZE = leftSize();
43         const size_t RIGHT_SIZE = right_size();
44         
45         SecureVector!ubyte buffer_vec = SecureVector!ubyte(LEFT_SIZE);
46         ubyte* buffer = buffer_vec.ptr;
47         
48         foreach (size_t i; 0 .. blocks)
49         {
50             xorBuf(buffer, input, m_key1.ptr, LEFT_SIZE);
51             m_cipher.setKey(buffer, LEFT_SIZE);
52             m_cipher.cipher(input + LEFT_SIZE, output + LEFT_SIZE, RIGHT_SIZE);
53             
54             m_hash.update(output + LEFT_SIZE, RIGHT_SIZE);
55             m_hash.flushInto(buffer);
56             xorBuf(output, input, buffer, LEFT_SIZE);
57             
58             xorBuf(buffer, output, m_key2.ptr, LEFT_SIZE);
59             m_cipher.setKey(buffer, LEFT_SIZE);
60             m_cipher.cipher1(output + LEFT_SIZE, RIGHT_SIZE);
61             
62             input += m_block_size;
63             output += m_block_size;
64         }
65     }
66 
67     /*
68     * Lion Decryption
69     */
70     override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks)
71     {
72         const size_t LEFT_SIZE = leftSize();
73         const size_t RIGHT_SIZE = right_size();
74         
75         SecureVector!ubyte buffer_vec = SecureVector!ubyte(LEFT_SIZE);
76         ubyte* buffer = buffer_vec.ptr;
77         
78         foreach (size_t i; 0 .. blocks)
79         {
80             xorBuf(buffer, input, m_key2.ptr, LEFT_SIZE);
81             m_cipher.setKey(buffer, LEFT_SIZE);
82             m_cipher.cipher(input + LEFT_SIZE, output + LEFT_SIZE, RIGHT_SIZE);
83             
84             m_hash.update(output + LEFT_SIZE, RIGHT_SIZE);
85             m_hash.flushInto(buffer);
86             xorBuf(output, input, buffer, LEFT_SIZE);
87             
88             xorBuf(buffer, output, m_key1.ptr, LEFT_SIZE);
89             m_cipher.setKey(buffer, LEFT_SIZE);
90             m_cipher.cipher1(output + LEFT_SIZE, RIGHT_SIZE);
91             
92             input += m_block_size;
93             output += m_block_size;
94         }
95     }
96 
97     override size_t blockSize() const { return m_block_size; }
98 
99     override KeyLengthSpecification keySpec() const
100     {
101         return KeyLengthSpecification(2, 2*m_hash.outputLength, 2);
102     }
103 
104     /*
105     * Clear memory of sensitive data
106     */
107     override void clear()
108     {
109         zeroise(m_key1);
110         zeroise(m_key2);
111         m_hash.clear();
112         m_cipher.clear();
113     }
114 
115     /*
116     * Return the name of this type
117     */
118     override @property string name() const
119     {
120         return "Lion(" ~ m_hash.name ~ "," ~
121             m_cipher.name ~ "," ~
122                 to!string(blockSize()) ~ ")";
123     }
124 
125     /*
126     * Return a clone of this object
127     */
128     override BlockCipher clone() const
129     {
130         return new Lion(m_hash.clone(), m_cipher.clone(), blockSize());
131     }
132 
133 
134     /**
135     * Params:
136     *  hash = the hash to use internally
137     *  cipher = the stream cipher to use internally
138     *  block_size = the size of the block to use
139     */
140     this(HashFunction hash, StreamCipher cipher, size_t block_size) 
141     {
142         m_block_size = max(2*hash.outputLength + 1, block_size);
143         m_hash = hash;
144         m_cipher = cipher;
145         
146         if (2*leftSize() + 1 > m_block_size)
147             throw new InvalidArgument(name ~ ": Chosen block size is too small");
148         
149         if (!m_cipher.validKeylength(leftSize()))
150             throw new InvalidArgument(name ~ ": This stream/hash combo is invalid");
151         
152         m_key1.resize(leftSize());
153         m_key2.resize(leftSize());
154     }
155     override @property size_t parallelism() const { return 1; }
156 protected:
157 
158     /*
159     * Lion Key Schedule
160     */
161     override void keySchedule(const(ubyte)* key, size_t length)
162     {
163         clear();
164         
165         const size_t half = length / 2;
166         copyMem(m_key1.ptr, key, half);
167         copyMem(m_key2.ptr, key + half, half);
168     }
169 
170 private:
171     size_t leftSize() const { return m_hash.outputLength; }
172     size_t right_size() const { return m_block_size - leftSize(); }
173 
174     const size_t m_block_size;
175     Unique!HashFunction m_hash;
176     Unique!StreamCipher m_cipher;
177     SecureVector!ubyte m_key1, m_key2;
178 }