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     do { 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     do { 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     do {
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     do {
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     do {
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     do {
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     do {
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     do {
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     final @disable BlockCipher dup() const;
198 }
199 
200 /**
201 * Represents a block cipher with a single fixed block size
202 */ 
203 abstract class BlockCipherFixedParams(size_t BS, size_t KMIN, size_t KMAX = 0, size_t KMOD = 1) : BlockCipher, SymmetricAlgorithm
204 {
205 public:
206     enum { BLOCK_SIZE = BS }
207     override size_t blockSize() const { return BS; }
208 
209     KeyLengthSpecification keySpec() const
210     {
211         return KeyLengthSpecification(KMIN, KMAX, KMOD);
212     }
213 
214     abstract void clear();
215     this() { clear(); } // TODO: Write some real constructors for each object.
216 }
217 
218 static if (BOTAN_TEST):
219 
220 import botan.test;
221 private import botan.libstate.libstate;
222 import botan.algo_factory.algo_factory;
223 import botan.codec.hex;
224 import core.atomic;
225 import memutils.hashmap;
226 
227 shared size_t total_tests;
228 
229 size_t blockTest(string algo, string key_hex, string in_hex, string out_hex)
230 {
231     const SecureVector!ubyte key = hexDecodeLocked(key_hex);
232     const SecureVector!ubyte pt = hexDecodeLocked(in_hex);
233     const SecureVector!ubyte ct = hexDecodeLocked(out_hex);
234 
235     AlgorithmFactory af = globalState().algorithmFactory();
236     
237     const auto providers = af.providersOf(algo);
238     size_t fails = 0;
239     
240     if (providers.empty)
241         throw new Exception("Unknown block cipher " ~ algo);
242     
243     foreach (provider; providers[])
244     {
245 
246         atomicOp!"+="(total_tests, 1);
247         const BlockCipher proto = af.prototypeBlockCipher(algo, provider);
248         
249         if (!proto)
250         {
251             logError("Unable to get " ~ algo ~ " from " ~ provider);
252             ++fails;
253             continue;
254         }
255         
256         Unique!BlockCipher cipher = proto.clone();
257         cipher.setKey(key);
258         SecureVector!ubyte buf = pt.clone;
259         
260         cipher.encrypt(buf);
261         atomicOp!"+="(total_tests, 1);
262         if (buf != ct)
263         {
264             logTrace(buf[], " Real");
265             logTrace(ct[], " Expected");
266             ++fails;
267             buf = ct.clone;
268         }
269 
270         cipher.decrypt(buf);
271 
272         atomicOp!"+="(total_tests, 1);
273         if (buf != pt)
274         {
275             logTrace(buf[], " Real");
276             logTrace(pt[], " Expected");
277             ++fails;
278         }
279     }
280     //logTrace("Finished ", algo, " Fails: ", fails);
281     assert(fails == 0);
282     return fails;
283 }
284 
285 static if (BOTAN_HAS_TESTS && !SKIP_BLOCK_TEST) unittest {
286 
287 
288     logDebug("Testing block_cipher.d ...");
289     size_t test_bc(string input)
290     {
291         logDebug("Testing file `" ~ input ~ " ...");
292         File vec = File(input, "r");
293         return runTestsBb(vec, "BlockCipher", "Out", true,
294               (ref HashMap!(string, string) m) {
295                   return blockTest(m["BlockCipher"], m["Key"], m["In"], m["Out"]);
296               });
297     }
298     
299     logTrace("Running tests ...");
300     size_t fails = runTestsInDir("test_data/block", &test_bc);
301 
302 
303     testReport("block_cipher", total_tests, fails);
304 }