1 /**
2 * Block Cipher Base Class
3 * 
4 * Copyright:
5 * (C) 1999-2009 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.block_cipher;
12 
13 import botan.constants;
14 public import botan.algo_base.transform;
15 public import botan.algo_base.sym_algo;
16 
17 /**
18 * This class represents a block cipher object.
19 */
20 interface BlockCipher : SymmetricAlgorithm
21 {
22 public:
23 
24     /**
25     * Returns: block size of this algorithm
26     */
27     abstract size_t blockSize() const;
28 
29     /**
30     * Returns: native parallelism of this cipher in blocks
31     */
32     abstract @property size_t parallelism() const;
33 
34     /**
35     * Returns: prefererred parallelism of this cipher in bytes
36     */
37     final size_t parallelBytes() const
38     {
39         return parallelism * this.blockSize() * BOTAN_BLOCK_CIPHER_PAR_MULT;
40     }
41 
42     /**
43     * Encrypt a block.
44     * 
45     * Params:
46     *  input = The plaintext block to be encrypted as a ubyte array.
47     *  output = The ubyte array designated to hold the encrypted block.
48     * 
49     * Notes: Both arguments must be of length blockSize().
50     */
51     final void encrypt(const(ubyte)* input, ubyte* output)
52     { encryptN(input, output, 1); }
53 
54     /**
55     * Decrypt a block.
56     * Params:
57     *  input = The ciphertext block to be decypted as a ubyte array.
58     *  output = The ubyte array designated to hold the decrypted block.
59     * Notes: Both parameters must be of length blockSize().
60     */
61     final void decrypt(const(ubyte)* input, ubyte* output)
62     { decryptN(input, output, 1); }
63 
64     /**
65     * Encrypt a block.
66     * Params:
67     *  block = the plaintext block to be encrypted
68     * Notes: Must be of length blockSize(). Will hold the result when the function
69     * has finished.
70     */
71     final void encrypt(ubyte* block) { encryptN(cast(const(ubyte)*)block, block, 1); }
72     
73     /**
74     * Decrypt a block.
75     * Params:
76     *  block = the ciphertext block to be decrypted
77     * Notes: Must be of length blockSize(). Will hold the result when the function
78     * has finished.
79     */
80     final void decrypt(ubyte* block) { decryptN(cast(const(ubyte)*)block, block, 1); }
81 
82     /**
83     * Encrypt a block.
84     * Params:
85     *  block = the plaintext block to be encrypted
86     * Notes: Must be of length blockSize(). Will hold the result when the function
87     * has finished.
88     */
89     final void encrypt(ref ubyte[] block) 
90     in { assert(block.length == this.blockSize()); }
91     body { encryptN(block.ptr, block.ptr, 1); }
92     
93     /**
94     * Decrypt a block.
95     * Params:
96     *  block = the ciphertext block to be decrypted
97     * Notes: Must be of length blockSize(). Will hold the result when the function
98     * has finished.
99     */
100     final void decrypt(ref ubyte[] block) 
101     in { assert(block.length >= this.blockSize()); }
102     body { decryptN(block.ptr, block.ptr, 1); }
103 
104     /**
105     * Encrypt one or more blocks
106     * Params:
107     *  block = the input/output buffer (multiple of blockSize())
108     */
109     final void encrypt(Alloc)(ref Vector!( ubyte, Alloc ) block)
110     in { assert(block.length >= this.blockSize()); }
111     body {
112         return encryptN(block.ptr, block.ptr, block.length / this.blockSize());
113     }
114 
115     /**
116     * Decrypt one or more blocks
117     * Params:
118     *  block = the input/output buffer (multiple of blockSize())
119     */
120     final void decrypt(Alloc)(ref Vector!( ubyte, Alloc ) block)
121     in { assert(block.length >= this.blockSize()); }
122     body {
123         return decryptN(block.ptr, block.ptr, block.length / this.blockSize());
124     }
125 
126     /**
127     * Encrypt one or more blocks
128     * Params:
129     *  input = the input buffer (multiple of blockSize())
130     *  output = the output buffer (same size as input)
131     */
132     final void encrypt(Alloc, Alloc2)(auto const ref Vector!( ubyte, Alloc ) input,
133                                               ref Vector!( ubyte, Alloc2 ) output)
134     in { assert(input.length >= this.blockSize()); }
135     body {
136         return encryptN(input.ptr, output.ptr, input.length / this.blockSize());
137     }
138     
139     /**
140     * Decrypt one or more blocks
141     * Params:
142     *  input = the input buffer (multiple of blockSize())
143     *  output = the output buffer (same size as input)
144     */
145     final void decrypt(Alloc, Alloc2)(auto const ref Vector!( ubyte, Alloc ) input,
146                                               ref Vector!( ubyte, Alloc2 ) output)
147     in { assert(input.length >= this.blockSize()); }
148     body {
149         return decryptN(input.ptr, output.ptr, input.length / this.blockSize());
150     }
151     /**
152     * Encrypt one or more blocks
153     * Params:
154     *  input = the input buffer (multiple of blockSize())
155     *  output = the output buffer (same size as input)
156     */
157     final void encrypt(ubyte[] input, ref ubyte[] output)
158     in { assert(input.length >= this.blockSize()); }
159     body {
160         return encryptN(input.ptr, output.ptr, input.length / blockSize());
161     }
162     
163     /**
164     * Decrypt one or more blocks
165     * Params:
166     *  input = the input buffer (multiple of blockSize())
167     *  output = the output buffer (same size as input)
168     */
169     final void decrypt(ubyte[] input, ref ubyte[] output)
170     in { assert(input.length >= this.blockSize()); }
171     body {
172         return decryptN(input.ptr, output.ptr, input.length / this.blockSize());
173     }
174 
175     /**
176     * Encrypt one or more blocks
177     * Params:
178     *  input = the input buffer (multiple of blockSize())
179     *  output = the output buffer (same size as input)
180     *  blocks = the number of blocks to process
181     */
182     abstract void encryptN(const(ubyte)* input, ubyte* output, size_t blocks);
183 
184     /**
185     * Decrypt one or more blocks
186     * Params:
187     *  input = the input buffer (multiple of blockSize())
188     *  output = the output buffer (same size as input)
189     *  blocks = the number of blocks to process
190     */
191     abstract void decryptN(const(ubyte)* input, ubyte* output, size_t blocks);
192 
193     /**
194     * Returns: new object representing the same algorithm as this
195     */
196     abstract BlockCipher clone() const;
197 }
198 
199 /**
200 * Represents a block cipher with a single fixed block size
201 */ 
202 abstract class BlockCipherFixedParams(size_t BS, size_t KMIN, size_t KMAX = 0, size_t KMOD = 1) : BlockCipher, SymmetricAlgorithm
203 {
204 public:
205     enum { BLOCK_SIZE = BS }
206     override size_t blockSize() const { return BS; }
207 
208     KeyLengthSpecification keySpec() const
209     {
210         return KeyLengthSpecification(KMIN, KMAX, KMOD);
211     }
212 
213     abstract void clear();
214     this() { clear(); } // TODO: Write some real constructors for each object.
215 }
216 
217 static if (BOTAN_TEST):
218 
219 import botan.test;
220 import botan.libstate.libstate;
221 import botan.algo_factory.algo_factory;
222 import botan.codec.hex;
223 import core.atomic;
224 import memutils.hashmap;
225 
226 shared size_t total_tests;
227 
228 size_t blockTest(string algo, string key_hex, string in_hex, string out_hex)
229 {
230     const SecureVector!ubyte key = hexDecodeLocked(key_hex);
231     const SecureVector!ubyte pt = hexDecodeLocked(in_hex);
232     const SecureVector!ubyte ct = hexDecodeLocked(out_hex);
233 
234     AlgorithmFactory af = globalState().algorithmFactory();
235     
236     const auto providers = af.providersOf(algo);
237     size_t fails = 0;
238     
239     if (providers.empty)
240         throw new Exception("Unknown block cipher " ~ algo);
241     
242     foreach (provider; providers[])
243     {
244 
245         atomicOp!"+="(total_tests, 1);
246         const BlockCipher proto = af.prototypeBlockCipher(algo, provider);
247         
248         if (!proto)
249         {
250             logError("Unable to get " ~ algo ~ " from " ~ provider);
251             ++fails;
252             continue;
253         }
254         
255         Unique!BlockCipher cipher = proto.clone();
256         cipher.setKey(key);
257         SecureVector!ubyte buf = pt.dup;
258         
259         cipher.encrypt(buf);
260         atomicOp!"+="(total_tests, 1);
261         if (buf != ct)
262         {
263             logTrace(buf[], " Real");
264             logTrace(ct[], " Expected");
265             ++fails;
266             buf = ct.dup;
267         }
268 
269         cipher.decrypt(buf);
270 
271         atomicOp!"+="(total_tests, 1);
272         if (buf != pt)
273         {
274             logTrace(buf[], " Real");
275             logTrace(pt[], " Expected");
276             ++fails;
277         }
278     }
279     //logTrace("Finished ", algo, " Fails: ", fails);
280     assert(fails == 0);
281     return fails;
282 }
283 
284 static if (BOTAN_HAS_TESTS && !SKIP_BLOCK_TEST) unittest {
285 
286 
287     logDebug("Testing block_cipher.d ...");
288     size_t test_bc(string input)
289     {
290         logDebug("Testing file `" ~ input ~ " ...");
291         File vec = File(input, "r");
292         return runTestsBb(vec, "BlockCipher", "Out", true,
293               (ref HashMap!(string, string) m) {
294                   return blockTest(m["BlockCipher"], m["Key"], m["In"], m["Out"]);
295               });
296     }
297     
298     logTrace("Running tests ...");
299     size_t fails = runTestsInDir("../test_data/block", &test_bc);
300 
301 
302     testReport("block_cipher", total_tests, fails);
303 }