1 /**
2 * Cipher Modes
3 * 
4 * Copyright:
5 * (C) 2013 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.modes.cipher_mode;
12 
13 public import botan.algo_base.transform;
14 import botan.constants; 
15 
16 /**
17 * Interface for cipher modes
18 */
19 abstract class CipherMode : KeyedTransform, Transformation
20 {
21 public:
22     /**
23     * Returns true iff this mode provides authentication as well as
24     * confidentiality.
25     */
26     abstract bool authenticated() const { return false; }
27 }
28 
29 static if (BOTAN_TEST):
30 
31 import botan.test;
32 import botan.codec.hex;
33 import botan.libstate.lookup;
34 import botan.filters.filters;
35 import core.atomic;
36 import memutils.hashmap;
37 
38 private shared size_t total_tests;
39 SecureVector!ubyte runMode()(string algo, CipherDir dir, 
40                              auto const ref SecureVector!ubyte pt, 
41                              auto const ref SecureVector!ubyte nonce, 
42                              auto const ref SecureVector!ubyte key)
43 {
44     /*
45     Unique!CipherMode cipher = getCipher(algo, dir);
46 
47     cipher.setKey(key);
48     cipher.start(nonce);
49 
50     SecureVector!ubyte ct = pt;
51     cipher.finish(ct);
52     */
53     
54     Pipe pipe = Pipe(getCipher(algo, SymmetricKey(key.dup), InitializationVector(nonce.dup), dir));
55     
56     pipe.processMsg(pt.ptr, pt.length);
57     
58     return pipe.readAll();
59 }
60 
61 size_t modeTest(string algo, string pt, string ct, string key_hex, string nonce_hex)
62 {
63     auto nonce = hexDecodeLocked(nonce_hex);
64     auto key = hexDecodeLocked(key_hex);
65     
66     size_t fails = 0;
67     
68     const string ct2 = hexEncode(runMode(algo, ENCRYPTION, hexDecodeLocked(pt), nonce, key));
69     atomicOp!"+="(total_tests, 1);
70     if (ct != ct2)
71     {
72         logError(algo ~ " got ct " ~ ct2 ~ " expected " ~ ct);
73         ++fails;
74     }
75     
76     const string pt2 = hexEncode(runMode(algo, DECRYPTION, hexDecodeLocked(ct), nonce, key));
77     atomicOp!"+="(total_tests, 1);
78     if (pt != pt2)
79     {
80         logError(algo ~ " got pt " ~ pt2 ~ " expected " ~ pt);
81         ++fails;
82     }
83     
84     return fails;
85 }
86 
87 static if (BOTAN_HAS_TESTS && !SKIP_CIPHER_MODE_TEST) unittest {
88     logDebug("Testing cipher_mode.d ...");
89     auto test = delegate(string input)
90     {
91         File vec = File(input, "r");
92         
93         return runTestsBb(vec, "Mode", "Out", true,
94             (ref HashMap!(string, string) m) {
95                 return modeTest(m["Mode"], m["In"], m["Out"], m["Key"], m["Nonce"]);
96             });
97     };
98     
99     size_t fails = runTestsInDir("test_data/modes", test);
100 
101     testReport("cipher_mode", total_tests, fails);
102 }