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 }