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