1 /*
2 * CBC mode
3 * (C) 1999-2007,2013 Jack Lloyd
4 * (C) 2014-2015 Etienne Cimon
5 *
6 * License:
7 * Botan is released under the Simplified BSD License (see LICENSE.md)
8 */
9 module botan.modes.cbc;
10 
11 import botan.constants;
12 static if (BOTAN_HAS_MODE_CBC):
13 
14 import botan.modes.cipher_mode;
15 import botan.block.block_cipher;
16 import botan.modes.mode_pad;
17 import botan.utils.loadstor;
18 import botan.utils.xor_buf;
19 import botan.utils.rounding;
20 import botan.utils.mem_ops;
21 import std.algorithm : min, swap;
22 
23 /**
24 * CBC Mode
25 */
26 abstract class CBCMode : CipherMode, Transformation
27 {
28 public:
29     override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len)
30     {
31         if (!validNonceLength(nonce_len))
32             throw new InvalidIVLength(name(), nonce_len);
33         
34         /*
35         * A nonce of zero length means carry the last ciphertext value over
36         * as the new IV, as unfortunately some protocols require this. If
37         * this is the first message then we use an IV of all zeros.
38         */
39         if (nonce_len)
40             m_state[] = nonce[0 .. nonce_len];
41         
42         return SecureVector!ubyte();
43     }
44 
45     override @property string name() const
46     {
47         if (m_padding)
48             return cipher().name ~ "/CBC/" ~ padding().name;
49         else
50             return cipher().name ~ "/CBC/CTS";
51     }
52 
53     override size_t updateGranularity() const
54     {
55         return cipher().parallelBytes();
56     }
57 
58     override KeyLengthSpecification keySpec() const
59     {
60         return cipher().keySpec();
61     }
62 
63     override size_t defaultNonceLength() const
64     {
65         return cipher().blockSize();
66     }
67 
68     override bool validNonceLength(size_t n) const
69     {
70         return (n == 0 || n == cipher().blockSize());
71     }
72 
73     override void clear()
74     {
75         m_cipher.clear();
76         m_state.clear();
77     }
78 
79     final override bool authenticated() const { return true; }
80 protected:
81     this(BlockCipher cipher, BlockCipherModePaddingMethod padding) 
82     {
83         m_cipher = cipher;
84         m_padding = padding;
85         m_state = SecureVector!ubyte(m_cipher.blockSize());
86         if (!m_padding.isEmpty && !m_padding.validBlocksize(m_cipher.blockSize()))
87             throw new InvalidArgument("Padding " ~ m_padding.name ~ " cannot be used with " ~ m_cipher.name ~ "/CBC");
88     }
89 
90     final BlockCipher cipher() const { return cast()*m_cipher; }
91 
92     final const(BlockCipherModePaddingMethod) padding() const
93     {
94         assert(m_padding, "No padding defined");
95         return *m_padding;
96     }
97 
98     final ref SecureVector!ubyte state() { return m_state; }
99 
100     final ubyte* statePtr() { return m_state.ptr; }
101 
102     final override void keySchedule(const(ubyte)* key, size_t length)
103     {
104         m_cipher.setKey(key, length);
105     }
106 
107 private:
108     Unique!BlockCipher m_cipher;
109     Unique!BlockCipherModePaddingMethod m_padding;
110     SecureVector!ubyte m_state;
111 }
112 
113 /**
114 * CBC Encryption
115 */
116 class CBCEncryption : CBCMode, Transformation
117 {
118 public:
119     this(BlockCipher cipher, BlockCipherModePaddingMethod padding)
120     {
121         super(cipher, padding);
122     }
123 
124     override void update(ref SecureVector!ubyte buffer, size_t offset = 0)
125     {
126         assert(buffer.length >= offset, "Offset is sane");
127         const size_t sz = buffer.length - offset;
128         ubyte* buf = buffer.ptr + offset;
129         
130         const size_t BS = cipher().blockSize();
131         
132         assert(sz % BS == 0, "CBC input is full blocks");
133         const size_t blocks = sz / BS;
134         
135         const(ubyte)* prev_block = statePtr();
136         
137         if (blocks)
138         {
139             foreach (size_t i; 0 .. blocks)
140             {
141                 assert(buffer.length >= BS*i);
142                 xorBuf(buf + BS*i, prev_block, BS);
143                 cipher().encrypt(buf + BS*i);
144                 prev_block = buf + BS*i;
145             }
146             
147             assert(buffer.length >= BS*blocks);
148             state()[] = buf[BS*(blocks-1) .. BS*blocks];
149         }
150 
151     }
152 
153 
154     override void finish(ref SecureVector!ubyte buffer, size_t offset = 0)
155     {
156         assert(buffer.length >= offset, "Offset is sane");
157         
158         const size_t BS = cipher().blockSize();
159         
160         const size_t bytes_in_final_block = (buffer.length-offset) % BS;
161         
162         padding().addPadding(buffer, bytes_in_final_block, BS);
163         
164         if ((buffer.length-offset) % BS)
165             throw new Exception("Did not pad to full block size in " ~ name);
166         
167         update(buffer, offset);
168     }
169 
170     override size_t outputLength(size_t input_length) const
171     {
172         return roundUp(input_length, cipher().blockSize());
173     }
174 
175     override size_t minimumFinalSize() const
176     {
177         return 0;
178     }
179 
180     // Interface fallthrough
181     override string provider() const { return "core"; }
182     override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); }
183     override size_t updateGranularity() const { return super.updateGranularity(); }
184     override size_t defaultNonceLength() const { return super.defaultNonceLength(); }
185     override bool validNonceLength(size_t nonce_len) const { return super.validNonceLength(nonce_len); }
186     override @property string name() const { return super.name; }
187     override void clear() { return super.clear(); }
188 }
189 
190 /**
191 * CBC Encryption with ciphertext stealing (CBC-CS3 variant)
192 */
193 final class CTSEncryption : CBCEncryption
194 {
195 public:
196     this(BlockCipher cipher)
197     {
198         super(cipher, null);
199     }
200 
201     override size_t outputLength(size_t input_length) const
202     {
203         return input_length; // no ciphertext expansion in CTS
204     }
205 
206     override void finish(ref SecureVector!ubyte buffer, size_t offset = 0)
207     {
208         assert(buffer.length >= offset, "Offset is sane");
209         ubyte* buf = buffer.ptr + offset;
210         const size_t sz = buffer.length - offset;
211         
212         const size_t BS = cipher().blockSize();
213         
214         if (sz < BS + 1)
215             throw new EncodingError(name() ~ ": insufficient data to encrypt");
216         
217         if (sz % BS == 0)
218         {
219             update(buffer, offset);
220             
221             // swap last two blocks
222             foreach (size_t i; 0 .. BS)
223                 swap(buffer[buffer.length-BS+i], buffer[buffer.length-2*BS+i]);
224         }
225         else
226         {
227             const size_t full_blocks = ((sz / BS) - 1) * BS;
228             const size_t final_bytes = sz - full_blocks;
229             assert(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");
230             assert(buffer.length >= full_blocks+final_bytes);
231             SecureVector!ubyte last = SecureVector!ubyte(buf[full_blocks .. full_blocks + final_bytes]);
232             buffer.resize(full_blocks + offset);
233             update(buffer, offset);
234             
235             xorBuf(last.ptr, statePtr(), BS);
236             cipher().encrypt(last.ptr);
237             
238             foreach (size_t i; 0 .. (final_bytes - BS))
239             {
240                 last[i] ^= last[i + BS];
241                 last[i + BS] ^= last[i];
242             }
243             
244             cipher().encrypt(last.ptr);
245             
246             buffer ~= last[];
247         }
248     }
249 
250     override size_t minimumFinalSize() const
251     {
252         return cipher().blockSize() + 1;
253     }
254 
255     override bool validNonceLength(size_t n) const
256     {
257         return (n == cipher().blockSize());
258     }
259 
260     // Interface fallthrough
261     override string provider() const { return "core"; }
262     override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); }
263     override void update(ref SecureVector!ubyte blocks, size_t offset = 0) { super.update(blocks, offset); }
264     override size_t updateGranularity() const { return super.updateGranularity(); }
265     override size_t defaultNonceLength() const { return super.defaultNonceLength(); }
266     override @property string name() const { return super.name; }
267     override void clear() { return super.clear(); }
268 
269 }
270 
271 /**
272 * CBC Decryption
273 */
274 class CBCDecryption : CBCMode, Transformation
275 {
276 public:
277     this(BlockCipher cipher, BlockCipherModePaddingMethod padding)  
278     {
279         super(cipher, padding);
280         m_tempbuf = SecureVector!ubyte(updateGranularity());
281     }
282 
283     override void update(ref SecureVector!ubyte buffer, size_t offset)
284     {
285         assert(buffer.length >= offset, "Offset is sane");
286         const size_t sz = buffer.length - offset;
287         ubyte* buf = buffer.ptr + offset;
288         
289         const size_t BS = cipher().blockSize();
290         
291         assert(sz % BS == 0, "Input is full blocks");
292         size_t blocks = sz / BS;
293         
294         while (blocks)
295         {
296             const size_t to_proc = min(BS * blocks, m_tempbuf.length);
297             cipher().decryptN(buf, m_tempbuf.ptr, to_proc / BS);
298             
299             assert(m_tempbuf.length >= BS);
300             xorBuf(m_tempbuf.ptr, statePtr(), BS);
301             xorBuf(m_tempbuf.ptr + BS, buf, to_proc - BS);
302                         
303             assert(state().length >= BS);
304             copyMem(statePtr(), buf + (to_proc - BS), BS);
305             
306             assert(buffer.length >= to_proc);
307             copyMem(buf, m_tempbuf.ptr, to_proc);
308             
309             buf += to_proc;
310             blocks -= to_proc / BS;
311         }
312     }
313 
314     override void finish(ref SecureVector!ubyte buffer, size_t offset = 0)
315     {
316         assert(buffer.length >= offset, "Offset is sane");
317         const size_t sz = buffer.length - offset;
318         
319         const size_t BS = cipher().blockSize();
320         
321         if (sz == 0 || sz % BS)
322             throw new DecodingError(name() ~ ": Ciphertext not a multiple of block size");
323         
324         update(buffer, offset);
325         assert(buffer.length >= BS);
326         const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.length-BS], BS);
327         buffer.resize(buffer.length - pad_bytes); // remove padding
328     }
329 
330     override size_t outputLength(size_t input_length) const
331     {
332         return input_length; // precise for CTS, worst case otherwise
333     }
334 
335     override size_t minimumFinalSize() const
336     {
337         return cipher().blockSize();
338     }
339 
340     // Interface fallthrough
341     override string provider() const { return "core"; }
342     override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); }
343     override size_t updateGranularity() const { return super.updateGranularity(); }
344     override size_t defaultNonceLength() const { return super.defaultNonceLength(); }
345     override bool validNonceLength(size_t nonce_len) const { return super.validNonceLength(nonce_len); }
346     override @property string name() const { return super.name; }
347     override void clear() { return super.clear(); }
348 private:
349     SecureVector!ubyte m_tempbuf;
350 }
351 
352 /**
353 * CBC Decryption with ciphertext stealing (CBC-CS3 variant)
354 */
355 final class CTSDecryption : CBCDecryption, Transformation
356 {
357 public:
358     this(BlockCipher cipher)
359     {
360         super(cipher, null);
361     }
362 
363     override void finish(ref SecureVector!ubyte buffer, size_t offset = 0)
364     {
365         assert(buffer.length >= offset, "Offset is sane");
366         const size_t sz = buffer.length - offset;
367         ubyte* buf = buffer.ptr + offset;
368         
369         const size_t BS = cipher().blockSize();
370         
371         if (sz < BS + 1)
372             throw new EncodingError(name() ~ ": insufficient data to decrypt");
373         
374         if (sz % BS == 0)
375         {
376             // swap last two blocks
377             
378             foreach (size_t i; 0 .. BS)
379                 swap(buffer[buffer.length-BS+i], buffer[buffer.length-2*BS+i]);
380             
381             update(buffer, offset);
382         }
383         else
384         {
385             const size_t full_blocks = ((sz / BS) - 1) * BS;
386             const size_t final_bytes = sz - full_blocks;
387             assert(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");
388             
389             SecureVector!ubyte last = SecureVector!ubyte(buf[full_blocks .. full_blocks + final_bytes]);
390             buffer.resize(full_blocks + offset);
391             update(buffer, offset);
392             
393             cipher().decrypt(last.ptr);
394             
395             xorBuf(last.ptr, &last[BS], final_bytes - BS);
396             
397             foreach (size_t i; 0 .. (final_bytes - BS))
398                 swap(last[i], last[i + BS]);
399             
400             cipher().decrypt(last.ptr);
401             xorBuf(last.ptr, statePtr(), BS);
402             
403             buffer ~= last;
404         }
405     }
406 
407     override size_t minimumFinalSize() const
408     {
409         return cipher().blockSize() + 1;
410     }
411 
412     override bool validNonceLength(size_t n) const
413     {
414         return (n == cipher().blockSize());
415     }
416 
417     // Interface fallthrough
418     override string provider() const { return "core"; }
419     override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); }
420     override void update(ref SecureVector!ubyte blocks, size_t offset = 0) { super.update(blocks, offset); }
421     override size_t updateGranularity() const { return super.updateGranularity(); }
422     override size_t defaultNonceLength() const { return super.defaultNonceLength(); }
423     override @property string name() const { return super.name; }
424     override void clear() { return super.clear(); }
425     override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); }
426 }