1 /**
2 * OCB Mode
3 * 
4 * Copyright:
5 * (C) 2013,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.modes.aead.ocb;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_AEAD_OCB):
15 
16 import botan.modes.aead.aead;
17 import botan.block.block_cipher;
18 
19 import botan.mac.cmac;
20 import botan.utils.xor_buf;
21 import botan.utils.bit_ops;
22 import botan.utils.types;
23 import botan.utils.mem_ops;
24 import std.algorithm;
25 
26 /**
27 * OCB Mode (base class for OCBEncryption and OCBDecryption). Note
28 * that OCB is patented, but is freely licensed in some circumstances.
29 *
30 * @see "The OCB Authenticated-Encryption Algorithm" internet draft
31           http://tools.ietf.org/html/draft-irtf-cfrg-ocb-03
32 * @see Free Licenses http://www.cs.ucdavis.edu/~rogaway/ocb/license.htm
33 * @see OCB home page http://www.cs.ucdavis.edu/~rogaway/ocb
34 */
35 abstract class OCBMode : AEADMode, Transformation
36 {
37 public:
38     override void setAssociatedData(const(ubyte)* ad, size_t ad_len)
39     {
40         assert(m_L, "A key was set");
41         m_ad_hash = ocbHash(*m_L, *m_cipher, ad, ad_len);
42     }
43 
44     override @property string name() const
45     {
46         return m_cipher.name ~ "/OCB"; // include tag size
47     }
48 
49     override size_t updateGranularity() const
50     {
51         return m_cipher.parallelBytes();
52     }
53 
54     override KeyLengthSpecification keySpec() const
55     {
56         return m_cipher.keySpec();
57     }
58 
59     override bool validNonceLength(size_t length) const
60     {
61         return (length > 0 && length < BS);
62     }
63 
64     override size_t tagSize() const { return m_tag_size; }
65 
66     override void clear()
67     {
68         m_cipher.free();
69         m_L.free();
70         
71         zeroise(m_ad_hash);
72         zeroise(m_offset);
73         zeroise(m_checksum);
74     }
75 
76     ~this() { /* for unique_ptr destructor */ }
77 
78     override size_t defaultNonceLength() const { return super.defaultNonceLength(); }
79 protected:
80 
81     override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len)
82     {
83         if (!validNonceLength(nonce_len))
84             throw new InvalidIVLength(name, nonce_len);
85         
86         assert(m_L, "A key was set");
87         
88         m_offset = updateNonce(nonce, nonce_len);
89         zeroise(m_checksum);
90         m_block_index = 0;
91         
92         return SecureVector!ubyte();
93     }
94 
95     /**
96     * Params:
97     *  cipher = the 128-bit block cipher to use
98     *  tag_size = is how big the auth tag will be
99     */
100     this(BlockCipher cipher, size_t tag_size)
101     {     
102         m_cipher = cipher;
103         m_BS = m_cipher.blockSize();
104         m_checksum = m_cipher.parallelBytes();
105         m_offset = m_BS;
106         m_ad_hash = m_BS;
107         m_tag_size = tag_size;
108         if (BS != 16)
109             throw new InvalidArgument("OCB is  not compatible with " ~ m_cipher.name);
110         
111         if (m_tag_size % 4 != 0 || m_tag_size < 8 || m_tag_size > BS)
112             throw new InvalidArgument("OCB cannot produce a " ~ to!string(m_tag_size) ~ " ubyte tag");
113         
114     }
115 
116     final override void keySchedule(const(ubyte)* key, size_t length)
117     {
118         m_cipher.setKey(key, length);
119         m_L = new LComputer(*m_cipher);
120     }
121 
122     @property size_t BS() const { return m_BS; }
123 
124     // fixme make these private
125     Unique!BlockCipher m_cipher;
126     Unique!LComputer m_L;
127 
128     size_t m_BS;
129     size_t m_block_index = 0;
130 
131     SecureVector!ubyte m_checksum;
132     SecureVector!ubyte m_offset;
133     SecureVector!ubyte m_ad_hash;
134 private:
135     final SecureVector!ubyte
136             updateNonce(const(ubyte)* nonce, size_t nonce_len)
137     {
138         assert(nonce_len < BS, "OCB nonce is less than cipher block size");
139         
140         SecureVector!ubyte nonce_buf = SecureVector!ubyte(BS);
141         
142         copyMem(&nonce_buf[BS - nonce_len], nonce, nonce_len);
143         nonce_buf[0] = ((tagSize() * 8) % 128) << 1;
144         nonce_buf[BS - nonce_len - 1] = 1;
145         
146         const ubyte bottom = nonce_buf[BS-1] & 0x3F;
147         nonce_buf[BS-1] &= 0xC0;
148         
149         const bool need_new_stretch = (m_last_nonce != nonce_buf);
150 
151         if (need_new_stretch)
152         {
153             m_last_nonce = nonce_buf.dup;
154             
155             m_cipher.encrypt(nonce_buf);
156             
157             foreach (size_t i; 0 .. BS/2)
158                 nonce_buf.pushBack(nonce_buf[i] ^ nonce_buf[i+1]);
159             
160             m_stretch = nonce_buf.move;
161         }
162         
163         // now set the offset from stretch and bottom
164         
165         const size_t shift_bytes = bottom / 8;
166         const size_t shift_bits  = bottom % 8;
167         
168         SecureVector!ubyte offset = SecureVector!ubyte(BS);
169         foreach (size_t i; 0 .. BS)
170         {
171             offset[i]  = cast(ubyte)(m_stretch[i+shift_bytes] << shift_bits);
172             offset[i] |= cast(ubyte)(m_stretch[i+shift_bytes+1] >> (8-shift_bits));
173         }
174         
175         return offset.move;
176     }
177 
178 
179     size_t m_tag_size = 0;
180     SecureVector!ubyte m_last_nonce;
181     SecureVector!ubyte m_stretch;
182 }
183 
184 final class OCBEncryption : OCBMode, Transformation
185 {
186 public:
187     /**
188     * Params:
189     *  cipher = the 128-bit block cipher to use
190     *  tag_size = is how big the auth tag will be
191     */
192     this(BlockCipher cipher, size_t tag_size = 16)
193     {
194         super(cipher, tag_size);
195     }
196 
197     override size_t outputLength(size_t input_length) const
198     { return input_length + tagSize(); }
199 
200     override size_t minimumFinalSize() const { return 0; }
201 
202     override void update(ref SecureVector!ubyte buffer, size_t offset = 0)
203     {
204         assert(buffer.length >= offset, "Offset is sane");
205         const size_t sz = buffer.length - offset;
206         ubyte* buf = buffer.ptr + offset;
207         
208         assert(sz % BS == 0, "Input length is an even number of blocks");
209         
210         encrypt(buf, sz / BS);
211     }
212 
213 
214     override void finish(ref SecureVector!ubyte buffer, size_t offset = 0)
215     {
216         assert(buffer.length >= offset, "Offset is sane");
217         const size_t sz = buffer.length - offset;
218         ubyte* buf = buffer.ptr + offset;
219         
220         if (sz)
221         {
222             const size_t final_full_blocks = sz / BS;
223             const size_t remainder_bytes = sz - (final_full_blocks * BS);
224             
225             encrypt(buf, final_full_blocks);
226             
227             if (remainder_bytes)
228             {
229                 assert(remainder_bytes < BS, "Only a partial block left");
230                 ubyte* remainder = &buf[sz - remainder_bytes];
231                 
232                 xorBuf(m_checksum.ptr, remainder, remainder_bytes);
233                 m_checksum[remainder_bytes] ^= 0x80;
234                 
235                 m_offset ^= m_L.star(); // Offset_*
236                 
237                 SecureVector!ubyte buf_ = SecureVector!ubyte(BS);
238                 m_cipher.encrypt(m_offset, buf_);
239                 xorBuf(remainder, buf_.ptr, remainder_bytes);
240             }
241         }
242         
243         SecureVector!ubyte checksum = SecureVector!ubyte(BS);
244         
245         // fold checksum
246         for (size_t i = 0; i != m_checksum.length; ++i)
247             checksum[i % checksum.length] ^= m_checksum[i];
248         
249         // now compute the tag
250         SecureVector!ubyte mac = m_offset.move();
251         mac ^= checksum;
252         mac ^= m_L.dollar();
253         
254         m_cipher.encrypt(mac);
255         
256         mac ^= m_ad_hash;
257         
258         buffer ~= mac.ptr[0 .. tagSize()];
259         
260         zeroise(m_checksum);
261         m_block_index = 0;
262     }
263 
264     // Interface fallthrough
265     override string provider() const { return "core"; }
266     override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); }
267     override size_t updateGranularity() const { return super.updateGranularity(); }
268     override size_t defaultNonceLength() const { return super.defaultNonceLength(); }
269     override bool validNonceLength(size_t nonce_len) const { return super.validNonceLength(nonce_len); }
270     override @property string name() const { return super.name; }
271     override void clear() { return super.clear(); }
272 
273 private:
274     void encrypt(ubyte* buffer, size_t blocks)
275     {
276         LComputer L = *m_L; // convenient name
277         
278         const size_t par_blocks = m_checksum.length / BS;
279         
280         while (blocks)
281         {
282             const size_t proc_blocks = std.algorithm.min(blocks, par_blocks);
283             const size_t proc_bytes = proc_blocks * BS;
284             
285             const SecureVector!ubyte* offsets = &L.computeOffsets(m_offset, m_block_index, proc_blocks);
286             
287             xorBuf(m_checksum.ptr, buffer, proc_bytes);
288             
289             xorBuf(buffer, offsets.ptr, proc_bytes);
290             m_cipher.encryptN(buffer, buffer, proc_blocks);
291             xorBuf(buffer, offsets.ptr, proc_bytes);
292             
293             buffer += proc_bytes;
294             blocks -= proc_blocks;
295             m_block_index += proc_blocks;
296         }
297     }
298 }
299 
300 final class OCBDecryption : OCBMode, Transformation
301 {
302 public:
303     /**
304     * Params:
305     *  cipher = the 128-bit block cipher to use
306     *  tag_size = is how big the auth tag will be
307     */
308     this(BlockCipher cipher, size_t tag_size = 16)
309     {
310         super(cipher, tag_size);
311     }
312 
313     override size_t outputLength(size_t input_length) const
314     {
315         assert(input_length > tagSize(), "Sufficient input");
316         return input_length - tagSize();
317     }
318 
319     override size_t minimumFinalSize() const { return tagSize(); }
320 
321     override void update(ref SecureVector!ubyte buffer, size_t offset)
322     {
323         assert(buffer.length >= offset, "Offset is sane");
324         const size_t sz = buffer.length - offset;
325         ubyte* buf = buffer.ptr + offset;
326         
327         assert(sz % BS == 0, "Input length is an even number of blocks");
328         
329         decrypt(buf, sz / BS);
330     }
331 
332     override void finish(ref SecureVector!ubyte buffer, size_t offset = 0)
333     {
334         assert(buffer.length >= offset, "Offset is sane");
335         const size_t sz = buffer.length - offset;
336         ubyte* buf = buffer.ptr + offset;
337         
338         assert(sz >= tagSize(), "We have the tag");
339         
340         const size_t remaining = sz - tagSize();
341         
342         if (remaining)
343         {
344             const size_t final_full_blocks = remaining / BS;
345             const size_t final_bytes = remaining - (final_full_blocks * BS);
346             
347             decrypt(buf, final_full_blocks);
348             
349             if (final_bytes)
350             {
351                 assert(final_bytes < BS, "Only a partial block left");
352                 
353                 ubyte* remainder = &buf[remaining - final_bytes];
354                 
355                 m_offset ^= m_L.star(); // Offset_*
356                 
357                 SecureVector!ubyte pad = SecureVector!ubyte(BS);
358                 m_cipher.encrypt(m_offset, pad); // P_*
359                 
360                 xorBuf(remainder, pad.ptr, final_bytes);
361                 
362                 xorBuf(m_checksum.ptr, remainder, final_bytes);
363                 m_checksum[final_bytes] ^= 0x80;
364             }
365         }
366         
367         SecureVector!ubyte checksum = SecureVector!ubyte(BS);
368         
369         // fold checksum
370         for (size_t i = 0; i != m_checksum.length; ++i)
371             checksum[i % checksum.length] ^= m_checksum[i];
372         
373         // compute the mac
374         SecureVector!ubyte mac = m_offset.move();
375         mac ^= checksum;
376         mac ^= m_L.dollar();
377         
378         m_cipher.encrypt(mac);
379         
380         mac ^= m_ad_hash;
381         
382         // reset state
383         zeroise(m_checksum);
384         m_block_index = 0;
385         
386         // compare mac
387         const(ubyte)* included_tag = &buf[remaining];
388         
389         if (!sameMem(mac.ptr, included_tag, tagSize()))
390             throw new IntegrityFailure("OCB tag check failed");
391         
392         // remove tag from end of message
393         buffer.length = remaining + offset;
394     }
395 
396     // Interface fallthrough
397     override string provider() const { return "core"; }
398     override SecureVector!ubyte startRaw(const(ubyte)* nonce, size_t nonce_len) { return super.startRaw(nonce, nonce_len); }
399     override size_t updateGranularity() const { return super.updateGranularity(); }
400     override size_t defaultNonceLength() const { return super.defaultNonceLength(); }
401     override bool validNonceLength(size_t nonce_len) const { return super.validNonceLength(nonce_len); }
402     override @property string name() const { return super.name; }
403     override void clear() { return super.clear(); }
404 
405 private:
406     void decrypt(ubyte* buffer, size_t blocks)
407     {
408         
409         const size_t par_bytes = m_cipher.parallelBytes();
410         
411         assert(par_bytes % BS == 0, "Cipher is parallel in full blocks");
412         
413         const size_t par_blocks = par_bytes / BS;
414         
415         while (blocks)
416         {
417             const size_t proc_blocks = std.algorithm.min(blocks, par_blocks);
418             const size_t proc_bytes = proc_blocks * BS;
419             
420             const SecureVector!ubyte* offsets = &m_L.computeOffsets(m_offset, m_block_index, proc_blocks);
421             
422             xorBuf(buffer, offsets.ptr, proc_bytes);
423             m_cipher.decryptN(buffer, buffer, proc_blocks);
424             xorBuf(buffer, offsets.ptr, proc_bytes);
425             
426             xorBuf(m_checksum.ptr, buffer, proc_bytes);
427             
428             buffer += proc_bytes;
429             blocks -= proc_blocks;
430             m_block_index += proc_blocks;
431         }
432     }
433 
434 }
435 
436 private:
437 
438 // Has to be in Botan namespace so unique_ptr can reference it
439 final class LComputer
440 {
441 public:
442     this(BlockCipher cipher)
443     {
444         m_L_star.resize(cipher.blockSize());
445         cipher.encrypt(m_L_star);
446         m_L_dollar = polyDouble(star());
447         m_L ~= polyDouble(dollar());
448     }
449     
450     ref const(SecureVector!ubyte) star() const { return m_L_star; }
451     
452     ref const(SecureVector!ubyte) dollar() const { return m_L_dollar; }
453     
454     ref const(SecureVector!ubyte) opIndex(size_t i) { return get(i); }
455     
456     ref const(SecureVector!ubyte) computeOffsets(ref SecureVector!ubyte offset,
457                                                   size_t block_index,
458                                                   size_t blocks)
459     {
460         const size_t BS = m_L_star.length;
461         m_offset_buf.resize(blocks*BS);
462         foreach (size_t i; 0 .. blocks)
463         { // could be done in parallel
464             offset ^= get(ctz(block_index + 1 + i));
465             copyMem(&m_offset_buf[BS*i], offset.ptr, BS);
466         }
467         
468         return m_offset_buf;
469     }
470     
471 private:
472     ref SecureVector!ubyte get(size_t i)
473     {
474         while (m_L.length <= i)
475             m_L.pushBack(polyDouble(m_L.back()));
476         
477         return m_L[i];
478     }
479     
480     SecureVector!ubyte polyDouble(const ref SecureVector!ubyte input)
481     {
482         import botan.mac.cmac : CMAC;
483         return CMAC.polyDouble(input);
484     }
485     
486     SecureVector!ubyte m_L_dollar, m_L_star;
487     Vector!( SecureArray!ubyte ) m_L;
488     SecureVector!ubyte m_offset_buf;
489 }
490 
491 /*
492 * OCB's HASH
493 */
494 SecureVector!ubyte ocbHash(LComputer L,
495                            BlockCipher cipher,
496                            const(ubyte)* ad, size_t ad_len)
497 {
498     const size_t BS = cipher.blockSize();
499     SecureVector!ubyte sum = SecureVector!ubyte(BS);
500     SecureVector!ubyte offset = SecureVector!ubyte(BS);
501     
502     SecureVector!ubyte buf = SecureVector!ubyte(BS);
503     
504     const size_t ad_blocks = (ad_len / BS);
505     const size_t ad_remainder = (ad_len % BS);
506     
507     foreach (size_t i; 0 .. ad_blocks)
508     {
509         // this loop could run in parallel
510         offset ^= L[ctz(i+1)];
511         
512         buf = offset.dup;
513         xorBuf(buf.ptr, &ad[BS*i], BS);
514         
515         cipher.encrypt(buf);
516         
517         sum ^= buf;
518     }
519     
520     if (ad_remainder)
521     {
522         offset ^= L.star();
523         
524         buf = offset.dup;
525         xorBuf(buf.ptr, &ad[BS*ad_blocks], ad_remainder);
526         buf[ad_len % BS] ^= 0x80;
527         
528         cipher.encrypt(buf);
529         
530         sum ^= buf;
531     }
532     
533     return sum;
534 }
535 
536 static if (BOTAN_TEST):
537 
538 import botan.test;
539 import botan.codec.hex;
540 import botan.hash.sha2_32;
541 import botan.block.aes;
542 import botan.libstate.libstate;
543 import botan.libstate.lookup;
544 import botan.algo_factory.algo_factory;
545 import botan.utils.loadstor;
546 
547 Vector!ubyte ocbEncrypt(OCBEncryption enc,
548                         OCBDecryption dec,
549                         const ref Vector!ubyte nonce,
550                         const ref Vector!ubyte pt,
551                         const ref Vector!ubyte ad)
552 {
553     enc.setAssociatedData(ad.ptr, ad.length);
554     
555     enc.start(nonce.ptr, nonce.length);
556 
557     SecureVector!ubyte buf = SecureVector!ubyte(pt.ptr[0 .. pt.length]);
558     enc.finish(buf, 0);
559 
560     try
561     {
562         SecureVector!ubyte ct = buf.dup;
563 
564         dec.setAssociatedData(ad.ptr, ad.length);
565         
566         dec.start(nonce.ptr, nonce.length);
567 
568         dec.finish(ct, 0);
569 
570         if (ct[0 .. $] != pt[0 .. $])
571             logError("OCB failed to decrypt correctly");
572 
573     }
574     catch (Exception e) {
575         logError("OCB round trip error - " ~ e.msg);
576     }
577 
578     return unlock(buf);
579 }
580 
581 size_t testOcbLong(ref AlgorithmFactory af, size_t keylen, size_t taglen, in string expected)
582 {
583     // Test from RFC 7253 Appendix A
584 
585     const string algo = "AES-" ~ keylen.to!string;
586 
587     Unique!OCBEncryption enc = new OCBEncryption(af.makeBlockCipher(algo), taglen / 8);
588     Unique!OCBDecryption dec = new OCBDecryption(af.makeBlockCipher(algo), taglen / 8);
589 
590     Vector!ubyte key;
591     key.length = keylen/8;
592 
593     key[keylen/8-1] = taglen;
594 
595     enc.setKey(key);
596     dec.setKey(key);
597 
598     const Vector!ubyte empty;
599     Vector!ubyte N = Vector!ubyte(12);
600     Vector!ubyte C;
601     
602     for(size_t i = 0; i != 128; ++i)
603     {
604         Vector!ubyte S = Vector!ubyte(i);
605 
606         storeBigEndian(cast(uint)(3*i+1), &N[8]);
607         C ~= ocbEncrypt(*enc, *dec, N, S, S);
608         storeBigEndian(cast(uint)(3*i+2), &N[8]);
609         C ~= ocbEncrypt(*enc, *dec, N, S, empty);
610         storeBigEndian(cast(uint)(3*i+3), &N[8]);
611         C ~= ocbEncrypt(*enc, *dec, N, empty, S);
612     }
613 
614     storeBigEndian(cast(uint)385, &N[8]);
615 
616     const Vector!ubyte cipher = ocbEncrypt(*enc, *dec, N, empty, C);
617     
618     const string cipher_hex = hexEncode(cipher);
619     
620     if (cipher_hex != expected)
621     {
622         logTrace("OCB " ~ algo ~ " long test mistmatch " ~ cipher_hex ~ " != " ~ expected);
623         return 1;
624     }
625     
626     return 0;
627 }
628 
629 static if (BOTAN_HAS_TESTS && !SKIP_OCB_TEST) unittest
630 {
631     import botan.libstate.libstate;
632     globalState();
633     logDebug("Testing ocb.d ...");
634     size_t fails = 0;
635 
636     AlgorithmFactory af = globalState().algorithmFactory();
637 
638     fails += testOcbLong(af, 128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2");
639     fails += testOcbLong(af, 192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17");
640     fails += testOcbLong(af, 256, 128, "D90EB8E9C977C88B79DD793D7FFA161C");
641     fails += testOcbLong(af, 128, 96, "77A3D8E73589158D25D01209");
642     fails += testOcbLong(af, 192, 96, "05D56EAD2752C86BE6932C5E");
643     fails += testOcbLong(af, 256, 96, "5458359AC23B0CBA9E6330DD");
644     fails += testOcbLong(af, 128, 64, "192C9B7BD90BA06A");
645     fails += testOcbLong(af, 192, 64, "0066BC6E0EF34E24");
646     fails += testOcbLong(af, 256, 64, "7D4EA5D445501CBE");
647     testReport("OCB long", 9, fails);
648 }