| ... | @@ -88,16 +88,19 @@ fn AesSiv(comptime Aes: anytype) type { | ... | @@ -88,16 +88,19 @@ fn AesSiv(comptime Aes: anytype) type { |
| 88 | // Process the final string | 88 | // Process the final string |
| 89 | const sn = strings[strings.len - 1]; | 89 | const sn = strings[strings.len - 1]; |
| 90 | if (sn.len >= 16) { | 90 | if (sn.len >= 16) { |
| 91 | // XOR d with the first 16 bytes of Sn | 91 | // XOR d with the last 16 bytes of Sn, |
| 92 | var xored_msg_buf: [4096]u8 = undefined; | 92 | // and give the entire Sn to CMAC incrementally. |
| 93 | const xored_len = @min(sn.len, xored_msg_buf.len); | 93 | var cmac = CmacImpl.init(&key); |
| 94 | @memcpy(xored_msg_buf[0..xored_len], sn[0..xored_len]); | 94 | const prefix = sn.len - 16; |
| 95 | | 95 | cmac.update(sn[0..prefix]); |
| 96 | for (d, 0..) |b, j| { | 96 | |
| 97 | xored_msg_buf[j] ^= b; | 97 | var tail: [16]u8 = undefined; |
| | 98 | for (&tail, sn[prefix..][0..16], d) |*out, s, db| { |
| | 99 | out.* = s ^ db; |
| 98 | } | 100 | } |
| | 101 | cmac.update(&tail); |
| 99 | | 102 | |
| 100 | CmacImpl.create(iv, xored_msg_buf[0..xored_len], &key); | 103 | cmac.final(iv); |
| 101 | } else { | 104 | } else { |
| 102 | // Pad and XOR | 105 | // Pad and XOR |
| 103 | d = dbl(d); | 106 | d = dbl(d); |
| ... | @@ -355,6 +358,48 @@ test "Aes128Siv - RFC 5297 Test Vector A.1" { | ... | @@ -355,6 +358,48 @@ test "Aes128Siv - RFC 5297 Test Vector A.1" { |
| 355 | try testing.expectEqualSlices(u8, &plaintext, &decrypted); | 358 | try testing.expectEqualSlices(u8, &plaintext, &decrypted); |
| 356 | } | 359 | } |
| 357 | | 360 | |
| | 361 | test "Aes128Siv - RFC 5297 Test Vector A.2" { |
| | 362 | // Test vector from RFC 5297 Appendix A.2 |
| | 363 | const key: [32]u8 = .{ |
| | 364 | 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78, |
| | 365 | 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, |
| | 366 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, |
| | 367 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, |
| | 368 | }; |
| | 369 | const ad1 = [_]u8{ |
| | 370 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, |
| | 371 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, |
| | 372 | 0xde, 0xad, 0xda, 0xda, 0xde, 0xad, 0xda, 0xda, |
| | 373 | 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, |
| | 374 | 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, |
| | 375 | }; |
| | 376 | const ad2 = [_]u8{ |
| | 377 | 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, |
| | 378 | 0x90, 0xa0, |
| | 379 | }; |
| | 380 | const nonce: [16]u8 = .{ |
| | 381 | 0x09, 0xf9, 0x11, 0x02, 0x9d, 0x74, 0xe3, 0x5b, |
| | 382 | 0xd8, 0x41, 0x56, 0xc5, 0x63, 0x56, 0x88, 0xc0, |
| | 383 | }; |
| | 384 | const plaintext = [_]u8{ |
| | 385 | 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, |
| | 386 | 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x6c, 0x61, |
| | 387 | 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x74, |
| | 388 | 0x6f, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, |
| | 389 | 0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, |
| | 390 | 0x53, 0x49, 0x56, 0x2d, 0x41, 0x45, 0x53, |
| | 391 | }; |
| | 392 | |
| | 393 | var ciphertext: [plaintext.len]u8 = undefined; |
| | 394 | var tag: [16]u8 = undefined; |
| | 395 | |
| | 396 | Aes128Siv.encryptWithAdVector(&ciphertext, &tag, &plaintext, &.{ &ad1, &ad2, &nonce }, key); |
| | 397 | |
| | 398 | // Expected values from RFC 5297 |
| | 399 | try htest.assertEqual("7bdb6e3b432667eb06f4d14bff2fbd0f", &tag); |
| | 400 | try htest.assertEqual("cb900f2fddbe404326601965c889bf17dba77ceb094fa663b7a3f748ba8af829ea64ad544a272e9c485b62a3fd5c0d", &ciphertext); |
| | 401 | } |
| | 402 | |
| 358 | test "Aes128Siv - empty plaintext" { | 403 | test "Aes128Siv - empty plaintext" { |
| 359 | const key: [32]u8 = @splat(0x42); | 404 | const key: [32]u8 = @splat(0x42); |
| 360 | const plaintext = ""; | 405 | const plaintext = ""; |