1 module dcrypt.macs.poly1305; 2 3 import dcrypt.macs.mac; 4 import dcrypt.blockcipher.blockcipher; 5 import dcrypt.bitmanip; 6 import dcrypt.util: wipe; 7 8 static assert(isMAC!(Poly1305!void), "Poly1305!void is not a valid mac."); 9 10 private { 11 enum ubyte rMaskLow2 = 0xFC; 12 enum ubyte rMaskHigh4 = 0x0F; 13 } 14 15 alias Poly1305!void Poly1305Raw; 16 17 /// Poly1305 MAC. 18 /// 19 /// Params: 20 /// Cipher = A block cipher used to derive the key. Set this to `void` if no block cipher should be used. 21 /// 22 /// Standard: RFC 7539 23 @safe nothrow @nogc 24 public struct Poly1305(Cipher) if ((isBlockCipher!Cipher && Cipher.blockSize == 16) || is(Cipher == void)) { 25 26 static if(useCipher) { 27 public enum name = "Poly1305-" ~ Cipher.name; 28 } else { 29 public enum name = "Poly1305"; 30 } 31 32 public enum macSize = blockSize; 33 34 private { 35 enum useCipher = !is(Cipher == void); 36 enum blockSize = 16; 37 38 static if(useCipher) { 39 Cipher cipher; 40 } 41 42 // Polynomial key 43 int r0, r1, r2, r3, r4; 44 45 // Precomputed 5 * r[1..4] 46 int s1, s2, s3, s4; 47 48 // Encrypted nonce 49 int k0, k1, k2, k3; 50 51 // Accumulating state 52 53 // Current block of buffered input 54 ubyte[blockSize] currentBlock; 55 56 // Current offset in input buffer 57 uint currentBlockOffset = 0; 58 59 // Polynomial accumulator 60 int h0, h1, h2, h3, h4; 61 } 62 63 /// Wipe sensitive data. 64 ~this() { 65 wipe(r0, r1, r2, r3, r4); 66 wipe(s1, s2, s3, s4); 67 wipe(k0, k1, k2, k3); 68 wipe(h0, h1, h2, h3, h4); 69 70 wipe(currentBlock); 71 } 72 73 /// Initializes the Poly1305 MAC. 74 /// Params: 75 /// key = 32 byte key. 76 /// nonce = 16 byte nonce. Required if used with block cipher. 77 public void start(in ubyte[] key, in ubyte[] nonce = null) 78 { 79 setKey(key, nonce); 80 81 reset(); 82 } 83 84 private void setKey(in ubyte[] key, in ubyte[] nonce) 85 in { 86 static if(useCipher) { 87 assert(nonce !is null && nonce.length == blockSize, "Poly1305 requires an 256 bit IV when used with a block cipher."); 88 } 89 90 assert(key !is null && key.length == 32, "Poly1305 requires a 32 byte key."); 91 92 } 93 body { 94 95 ubyte[16] r, s; 96 r[] = key[0..16]; 97 clamp(r); 98 s[] = key[16..32]; 99 100 assert(checkKey(r), "Invalid format for r portion of Poly1305 key."); 101 102 // Extract r portion of key 103 104 int t0 = fromLittleEndian!int(r[0..4]); 105 int t1 = fromLittleEndian!int(r[4..8]); 106 int t2 = fromLittleEndian!int(r[8..12]); 107 int t3 = fromLittleEndian!int(r[12..16]); 108 109 r0 = t0 & 0x3ffffff; t0 >>>= 26; t0 |= t1 << 6; 110 r1 = t0 & 0x3ffff03; t1 >>>= 20; t1 |= t2 << 12; 111 r2 = t1 & 0x3ffc0ff; t2 >>>= 14; t2 |= t3 << 18; 112 r3 = t2 & 0x3f03fff; t3 >>>= 8; 113 r4 = t3 & 0x00fffff; 114 115 // Precompute multipliers 116 s1 = r1 * 5; 117 s2 = r2 * 5; 118 s3 = r3 * 5; 119 s4 = r4 * 5; 120 121 static if (useCipher) 122 { 123 cipher.start(true, s); 124 cipher.processBlock(nonce, s); 125 } 126 127 k0 = fromLittleEndian!int(s[0..4]); 128 k1 = fromLittleEndian!int(s[4..8]); 129 k2 = fromLittleEndian!int(s[8..12]); 130 k3 = fromLittleEndian!int(s[12..16]); 131 } 132 133 public void put(in ubyte[] inp...) { 134 135 import std.algorithm: min; 136 137 const(ubyte)[] input = inp; 138 139 uint copied = 0; 140 while (input.length > 0) 141 { 142 if (currentBlockOffset == blockSize) 143 { 144 processBlock(); 145 currentBlockOffset = 0; 146 } 147 148 uint toCopy = min(input.length, blockSize - currentBlockOffset); 149 //System.arraycopy(in, copied + inOff, currentBlock, currentBlockOffset, toCopy); 150 currentBlock[currentBlockOffset..currentBlockOffset+toCopy] = input[0..toCopy]; 151 input = input[toCopy..$]; 152 copied += toCopy; 153 currentBlockOffset += toCopy; 154 } 155 156 } 157 158 private void processBlock() 159 { 160 if (currentBlockOffset < blockSize) 161 { 162 currentBlock[currentBlockOffset] = 1; 163 for (uint i = currentBlockOffset + 1; i < blockSize; i++) 164 { 165 currentBlock[i] = 0; 166 } 167 } 168 169 immutable long t0 = 0xffffffffL & fromLittleEndian!int(currentBlock[0..4]); 170 immutable long t1 = 0xffffffffL & fromLittleEndian!int(currentBlock[4..8]); 171 immutable long t2 = 0xffffffffL & fromLittleEndian!int(currentBlock[8..12]); 172 immutable long t3 = 0xffffffffL & fromLittleEndian!int(currentBlock[12..16]); 173 174 h0 += t0 & 0x3ffffff; 175 h1 += (((t1 << 32) | t0) >>> 26) & 0x3ffffff; 176 h2 += (((t2 << 32) | t1) >>> 20) & 0x3ffffff; 177 h3 += (((t3 << 32) | t2) >>> 14) & 0x3ffffff; 178 h4 += (t3 >>> 8); 179 180 if (currentBlockOffset == blockSize) 181 { 182 h4 += (1 << 24); 183 } 184 185 long tp0 = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); 186 long tp1 = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); 187 long tp2 = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); 188 long tp3 = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); 189 long tp4 = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); 190 191 long b; 192 h0 = cast(int)tp0 & 0x3ffffff; b = (tp0 >>> 26); 193 tp1 += b; h1 = cast(int)tp1 & 0x3ffffff; b = ((tp1 >>> 26) & 0xffffffff); 194 tp2 += b; h2 = cast(int)tp2 & 0x3ffffff; b = ((tp2 >>> 26) & 0xffffffff); 195 tp3 += b; h3 = cast(int)tp3 & 0x3ffffff; b = (tp3 >>> 26); 196 tp4 += b; h4 = cast(int)tp4 & 0x3ffffff; b = (tp4 >>> 26); 197 h0 += b * 5; 198 } 199 200 public ubyte[macSize] finish() { 201 ubyte[macSize] mac; 202 finish(mac); 203 return mac; 204 } 205 206 public ubyte[] finish(ubyte[] output) 207 in { 208 assert(output.length >= blockSize, "Output buffer is too short."); 209 } 210 body { 211 if (currentBlockOffset > 0) 212 { 213 // Process padded final block 214 processBlock(); 215 } 216 217 long f0, f1, f2, f3; 218 219 int b = h0 >>> 26; 220 h0 = h0 & 0x3ffffff; 221 h1 += b; b = h1 >>> 26; h1 = h1 & 0x3ffffff; 222 h2 += b; b = h2 >>> 26; h2 = h2 & 0x3ffffff; 223 h3 += b; b = h3 >>> 26; h3 = h3 & 0x3ffffff; 224 h4 += b; b = h4 >>> 26; h4 = h4 & 0x3ffffff; 225 h0 += b * 5; 226 227 int g0, g1, g2, g3, g4; 228 g0 = h0 + 5; b = g0 >>> 26; g0 &= 0x3ffffff; 229 g1 = h1 + b; b = g1 >>> 26; g1 &= 0x3ffffff; 230 g2 = h2 + b; b = g2 >>> 26; g2 &= 0x3ffffff; 231 g3 = h3 + b; b = g3 >>> 26; g3 &= 0x3ffffff; 232 g4 = h4 + b - (1 << 26); 233 234 b = (g4 >>> 31) - 1; 235 int nb = ~b; 236 h0 = (h0 & nb) | (g0 & b); 237 h1 = (h1 & nb) | (g1 & b); 238 h2 = (h2 & nb) | (g2 & b); 239 h3 = (h3 & nb) | (g3 & b); 240 h4 = (h4 & nb) | (g4 & b); 241 242 f0 = (((h0 ) | (h1 << 26)) & 0xffffffffL) + (0xffffffffL & k0); 243 f1 = (((h1 >>> 6 ) | (h2 << 20)) & 0xffffffffL) + (0xffffffffL & k1); 244 f2 = (((h2 >>> 12) | (h3 << 14)) & 0xffffffffL) + (0xffffffffL & k2); 245 f3 = (((h3 >>> 18) | (h4 << 8 )) & 0xffffffffL) + (0xffffffffL & k3); 246 247 toLittleEndian!int(cast(int)f0, output[0..4]); 248 f1 += (f0 >>> 32); 249 toLittleEndian!int(cast(int)f1, output[4..8]); 250 f2 += (f1 >>> 32); 251 toLittleEndian!int(cast(int)f2, output[8..12]); 252 f3 += (f2 >>> 32); 253 toLittleEndian!int(cast(int)f3, output[12..16]); 254 255 reset(); 256 return output[0..blockSize]; 257 } 258 259 /// Resets the internal state such that a new MAC can be computed. 260 public void reset() 261 { 262 currentBlockOffset = 0; 263 h0 = h1 = h2 = h3 = h4 = 0; 264 } 265 266 /// Returns: i1*i2 as long 267 private long mul32x32_64(in int i1, in int i2) pure 268 { 269 return (cast(long)i1) * i2; 270 } 271 272 /// Check if r has right format. 273 private bool checkKey(in ubyte[] key) pure { 274 assert(key.length == 16, "r must be 128 bits."); 275 276 bool checkMask(in ubyte b, in ubyte mask) pure 277 { 278 return (b & (~mask)) == 0; 279 } 280 281 return 282 checkMask(key[3], rMaskHigh4) && 283 checkMask(key[7], rMaskHigh4) && 284 checkMask(key[11], rMaskHigh4) && 285 checkMask(key[15], rMaskHigh4) && 286 287 checkMask(key[4], rMaskLow2) && 288 checkMask(key[8], rMaskLow2) && 289 checkMask(key[12], rMaskLow2); 290 } 291 292 /// Clears bits in key: 293 /// Clears top four bits of bytes 3,7,11,15 294 /// Clears bottom two bits of bytes 4,8,12 295 /// 296 /// Params: 297 /// key = Some bits of this key get cleared. 298 private void clamp(ref ubyte[16] key) 299 { 300 // r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15}) 301 key[3] &= rMaskHigh4; 302 key[7] &= rMaskHigh4; 303 key[11] &= rMaskHigh4; 304 key[15] &= rMaskHigh4; 305 306 // r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}). 307 key[4] &= rMaskLow2; 308 key[8] &= rMaskLow2; 309 key[12] &= rMaskLow2; 310 } 311 } 312 313 314 315 // Raw Poly1305 316 // onetimeauth.c from nacl-20110221 317 unittest { 318 319 poly1305Test!(Poly1305!void)( 320 x"eea6a7251c1e72916d11c2cb214d3c25 2539121d8e234e652d651fa4c8cff880", 321 null, 322 x"8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a 323 c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738 324 b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da 325 99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5", 326 x"f3ffc7703f9400e52a7dfb4b3d3305d9" 327 ); 328 329 } 330 331 unittest { 332 import dcrypt.blockcipher.aes; 333 334 poly1305Test!(Poly1305!AES)( 335 x"0000000000000000000000000000000000000000000000000000000000000000", 336 x"00000000000000000000000000000000", 337 x"", 338 x"66e94bd4ef8a2c3b884cfa59ca342b2e" 339 ); 340 341 } 342 343 unittest { 344 import dcrypt.blockcipher.aes; 345 346 poly1305Test!(Poly1305!AES)( 347 x"f795bd0a50e29e0710d3130a20e98d0c f795bd4a52e29ed713d313fa20e98dbc", 348 x"917cf69ebd68b2ec9b9fe9a3eadda692", 349 x"66f7", 350 x"5ca585c75e8f8f025e710cabc9a1508b" 351 ); 352 353 } 354 355 // Test vectors from RFC7539, A.3. #1 356 unittest { 357 358 poly1305Test!(Poly1305!void)( 359 x"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 360 null, 361 x"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 362 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 363 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 364 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 365 x"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" 366 ); 367 368 } 369 370 // Test vectors from RFC7539, A.3. #2 371 unittest { 372 373 poly1305Test!(Poly1305!void)( 374 x"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e", 375 null, 376 longTestData0, 377 x"36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e" 378 ); 379 380 } 381 382 // Test vectors from RFC7539, A.3. #3 383 unittest { 384 385 poly1305Test!(Poly1305!void)( 386 x"36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 387 null, 388 longTestData0, 389 x"f3 47 7e 7c d9 54 17 af 89 a6 b8 79 4c 31 0c f0" 390 ); 391 392 } 393 394 // Test vectors from RFC7539, A.3. #4 395 unittest { 396 397 poly1305Test!(Poly1305!void)( 398 x"1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0 47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0", 399 null, 400 x" 401 27 54 77 61 73 20 62 72 69 6c 6c 69 67 2c 20 61 402 6e 64 20 74 68 65 20 73 6c 69 74 68 79 20 74 6f 403 76 65 73 0a 44 69 64 20 67 79 72 65 20 61 6e 64 404 20 67 69 6d 62 6c 65 20 69 6e 20 74 68 65 20 77 405 61 62 65 3a 0a 41 6c 6c 20 6d 69 6d 73 79 20 77 406 65 72 65 20 74 68 65 20 62 6f 72 6f 67 6f 76 65 407 73 2c 0a 41 6e 64 20 74 68 65 20 6d 6f 6d 65 20 408 72 61 74 68 73 20 6f 75 74 67 72 61 62 65 2e 409 ", 410 x"45 41 66 9a 7e aa ee 61 e7 08 dc 7c bc c5 eb 62" 411 ); 412 413 } 414 415 // Test vectors from RFC7539, A.3. #5 416 // If one uses 130-bit partial reduction, does the code handle the case where partially reduced final result is not fully reduced? 417 unittest { 418 419 poly1305Test!(Poly1305!void)( 420 x"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 421 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 422 null, 423 x" 424 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 425 ", 426 x"03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" 427 ); 428 429 } 430 431 // Test vectors from RFC7539, A.3. #6 432 // What happens if addition of s overflows modulo 2^128? 433 unittest { 434 435 poly1305Test!(Poly1305!void)( 436 x"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 437 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF", 438 null, 439 x" 440 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 441 ", 442 x"03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" 443 ); 444 445 } 446 447 // Test vectors from RFC7539, A.3. #7 448 // What happens if data limb is all ones and there is carry from lower limb? 449 unittest { 450 451 poly1305Test!(Poly1305!void)( 452 x"01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 453 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 454 null, 455 x" 456 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 457 F0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 458 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 459 ", 460 x"05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" 461 ); 462 463 } 464 465 // Test vectors from RFC7539, A.3. #8 466 // What happens if final result from polynomial part is exactly 2^130-5? 467 unittest { 468 469 poly1305Test!(Poly1305!void)( 470 x"01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 471 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 472 null, 473 x" 474 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 475 FB FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE 476 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 477 ", 478 x"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" 479 ); 480 481 } 482 483 // Test vectors from RFC7539, A.3. #9 484 // What happens if final result from polynomial part is exactly 2^130-6? 485 unittest { 486 487 poly1305Test!(Poly1305!void)( 488 x"02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 489 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 490 null, 491 x" 492 FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 493 ", 494 x"FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF" 495 ); 496 497 } 498 499 // Test vectors from RFC7539, A.3. #10 500 // What happens if 5*H+L-type reduction produces 131-bit intermediate result? 501 unittest { 502 503 poly1305Test!(Poly1305!void)( 504 x"01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 505 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 506 null, 507 x" 508 E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00 509 33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00 510 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 511 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 512 ", 513 x"14 00 00 00 00 00 00 00 55 00 00 00 00 00 00 00" 514 ); 515 516 } 517 518 // Test vectors from RFC7539, A.3. #11 519 // What happens if 5*H+L-type reduction produces131-bit final result? 520 unittest { 521 522 poly1305Test!(Poly1305!void)( 523 x"01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 524 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 525 null, 526 x" 527 E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00 528 33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00 529 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 530 ", 531 x"13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" 532 ); 533 534 } 535 536 version(unittest) { 537 // Helper function for unittests. 538 private: 539 540 void poly1305Test(P)(string key, string iv, string data, string expectedMac) { 541 542 alias const(ubyte[]) octets; 543 544 P poly; 545 poly.start(cast(octets) key, cast(octets) iv); 546 poly.put(cast(octets) data); 547 548 assert(poly.finish() == expectedMac, "Poly1305 failed!"); 549 550 } 551 552 enum longTestData0 = x" 553 41 6e 79 20 73 75 62 6d 69 73 73 69 6f 6e 20 74 554 6f 20 74 68 65 20 49 45 54 46 20 69 6e 74 65 6e 555 64 65 64 20 62 79 20 74 68 65 20 43 6f 6e 74 72 556 69 62 75 74 6f 72 20 66 6f 72 20 70 75 62 6c 69 557 63 61 74 69 6f 6e 20 61 73 20 61 6c 6c 20 6f 72 558 20 70 61 72 74 20 6f 66 20 61 6e 20 49 45 54 46 559 20 49 6e 74 65 72 6e 65 74 2d 44 72 61 66 74 20 560 6f 72 20 52 46 43 20 61 6e 64 20 61 6e 79 20 73 561 74 61 74 65 6d 65 6e 74 20 6d 61 64 65 20 77 69 562 74 68 69 6e 20 74 68 65 20 63 6f 6e 74 65 78 74 563 20 6f 66 20 61 6e 20 49 45 54 46 20 61 63 74 69 564 76 69 74 79 20 69 73 20 63 6f 6e 73 69 64 65 72 565 65 64 20 61 6e 20 22 49 45 54 46 20 43 6f 6e 74 566 72 69 62 75 74 69 6f 6e 22 2e 20 53 75 63 68 20 567 73 74 61 74 65 6d 65 6e 74 73 20 69 6e 63 6c 75 568 64 65 20 6f 72 61 6c 20 73 74 61 74 65 6d 65 6e 569 74 73 20 69 6e 20 49 45 54 46 20 73 65 73 73 69 570 6f 6e 73 2c 20 61 73 20 77 65 6c 6c 20 61 73 20 571 77 72 69 74 74 65 6e 20 61 6e 64 20 65 6c 65 63 572 74 72 6f 6e 69 63 20 63 6f 6d 6d 75 6e 69 63 61 573 74 69 6f 6e 73 20 6d 61 64 65 20 61 74 20 61 6e 574 79 20 74 69 6d 65 20 6f 72 20 70 6c 61 63 65 2c 575 20 77 68 69 63 68 20 61 72 65 20 61 64 64 72 65 576 73 73 65 64 20 74 6f 577 "; 578 }