authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2024-12-11 18:52:43+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-12-11 18:52:43+01:00
log295c5a64f5746a10259b5fb0799415db023975c7
tree42390862ab8fe79a31ba68402ec104af9a6a62e1
parentc172877b81f4eff50cf214eb553c9df108fbd9eb
signaturebadge-check Signed by PGP key B5690EEEBB952194

Reinstantiates AEGIS-MAC with the final construction (#22205)

This reverts commit c9d6f8b5058ba0df3bf281a3be3a3570c2219754.

3 files changed, 235 insertions(+), 21 deletions(-)

lib/std/crypto.zig+11
......@@ -58,9 +58,20 @@ pub const auth = struct {
5858 pub const siphash = @import("crypto/siphash.zig");
5959 pub const aegis = struct {
6060 const variants = @import("crypto/aegis.zig");
61 pub const Aegis128X4Mac = variants.Aegis128X4Mac;
62 pub const Aegis128X2Mac = variants.Aegis128X2Mac;
6163 pub const Aegis128LMac = variants.Aegis128LMac;
64
65 pub const Aegis256X4Mac = variants.Aegis256X4Mac;
66 pub const Aegis256X2Mac = variants.Aegis256X2Mac;
6267 pub const Aegis256Mac = variants.Aegis256Mac;
68
69 pub const Aegis128X4Mac_128 = variants.Aegis128X4Mac_128;
70 pub const Aegis128X2Mac_128 = variants.Aegis128X2Mac_128;
6371 pub const Aegis128LMac_128 = variants.Aegis128LMac_128;
72
73 pub const Aegis256X4Mac_128 = variants.Aegis256X4Mac_128;
74 pub const Aegis256X2Mac_128 = variants.Aegis256X2Mac_128;
6475 pub const Aegis256Mac_128 = variants.Aegis256Mac_128;
6576 };
6677 pub const cmac = @import("crypto/cmac.zig");
lib/std/crypto/aegis.zig+220-21
......@@ -161,7 +161,7 @@ fn State128X(comptime degree: u7) type {
161161 state.update(msg0, msg1);
162162 }
163163
164 fn mac(state: *State, comptime tag_bits: u9, adlen: usize, mlen: usize) [tag_bits / 8]u8 {
164 fn finalize(state: *State, comptime tag_bits: u9, adlen: usize, mlen: usize) [tag_bits / 8]u8 {
165165 const blocks = &state.blocks;
166166 var sizes: [aes_block_length]u8 = undefined;
167167 mem.writeInt(u64, sizes[0..8], @as(u64, adlen) * 8, .little);
......@@ -200,6 +200,59 @@ fn State128X(comptime degree: u7) type {
200200 else => unreachable,
201201 }
202202 }
203
204 fn finalizeMac(state: *State, comptime tag_bits: u9, datalen: usize) [tag_bits / 8]u8 {
205 const blocks = &state.blocks;
206 var sizes: [aes_block_length]u8 = undefined;
207 mem.writeInt(u64, sizes[0..8], @as(u64, datalen) * 8, .little);
208 mem.writeInt(u64, sizes[8..16], tag_bits, .little);
209 for (1..degree) |i| {
210 @memcpy(sizes[i * 16 ..][0..16], sizes[0..16]);
211 }
212 var t = blocks[2].xorBlocks(AesBlockVec.fromBytes(&sizes));
213 for (0..7) |_| {
214 state.update(t, t);
215 }
216 if (degree > 1) {
217 var v = [_]u8{0} ** rate;
218 switch (tag_bits) {
219 128 => {
220 const tags = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).xorBlocks(blocks[3]).xorBlocks(blocks[4]).xorBlocks(blocks[5]).xorBlocks(blocks[6]).toBytes();
221 for (0..degree / 2) |d| {
222 v[0..32].* = tags[d * 32 ..][0..32].*;
223 state.absorb(&v);
224 }
225 },
226 256 => {
227 const tags_0 = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).xorBlocks(blocks[3]).toBytes();
228 const tags_1 = blocks[4].xorBlocks(blocks[5]).xorBlocks(blocks[6]).xorBlocks(blocks[7]).toBytes();
229 for (1..degree) |d| {
230 v[0..32].* = tags_0[d * 16 ..][0..16].* ++ tags_1[d * 16 ..][0..16].*;
231 state.absorb(&v);
232 }
233 },
234 else => unreachable,
235 }
236 mem.writeInt(u64, sizes[0..8], degree, .little);
237 mem.writeInt(u64, sizes[8..16], tag_bits, .little);
238 t = blocks[2].xorBlocks(AesBlockVec.fromBytes(&sizes));
239 for (0..7) |_| {
240 state.update(t, t);
241 }
242 }
243 switch (tag_bits) {
244 128 => {
245 const tags = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).xorBlocks(blocks[3]).xorBlocks(blocks[4]).xorBlocks(blocks[5]).xorBlocks(blocks[6]).toBytes();
246 return tags[0..16].*;
247 },
248 256 => {
249 const tags_0 = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).xorBlocks(blocks[3]).toBytes();
250 const tags_1 = blocks[4].xorBlocks(blocks[5]).xorBlocks(blocks[6]).xorBlocks(blocks[7]).toBytes();
251 return tags_0[0..16].* ++ tags_1[0..16].*;
252 },
253 else => unreachable,
254 }
255 }
203256 };
204257}
205258
......@@ -252,7 +305,7 @@ fn Aegis128XGeneric(comptime degree: u7, comptime tag_bits: u9) type {
252305 state.enc(&dst, &src);
253306 @memcpy(c[i..][0 .. m.len % block_length], dst[0 .. m.len % block_length]);
254307 }
255 tag.* = state.mac(tag_bits, ad.len, m.len);
308 tag.* = state.finalize(tag_bits, ad.len, m.len);
256309 }
257310
258311 /// `m`: Message
......@@ -284,7 +337,7 @@ fn Aegis128XGeneric(comptime degree: u7, comptime tag_bits: u9) type {
284337 if (m.len % block_length != 0) {
285338 state.decLast(m[i..], c[i..]);
286339 }
287 var computed_tag = state.mac(tag_bits, ad.len, m.len);
340 var computed_tag = state.finalize(tag_bits, ad.len, m.len);
288341 const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
289342 if (!verify) {
290343 crypto.secureZero(u8, &computed_tag);
......@@ -401,7 +454,7 @@ fn State256X(comptime degree: u7) type {
401454 state.update(msg);
402455 }
403456
404 fn mac(state: *State, comptime tag_bits: u9, adlen: usize, mlen: usize) [tag_bits / 8]u8 {
457 fn finalize(state: *State, comptime tag_bits: u9, adlen: usize, mlen: usize) [tag_bits / 8]u8 {
405458 const blocks = &state.blocks;
406459 var sizes: [aes_block_length]u8 = undefined;
407460 mem.writeInt(u64, sizes[0..8], @as(u64, adlen) * 8, .little);
......@@ -440,6 +493,61 @@ fn State256X(comptime degree: u7) type {
440493 else => unreachable,
441494 }
442495 }
496
497 fn finalizeMac(state: *State, comptime tag_bits: u9, datalen: usize) [tag_bits / 8]u8 {
498 const blocks = &state.blocks;
499 var sizes: [aes_block_length]u8 = undefined;
500 mem.writeInt(u64, sizes[0..8], @as(u64, datalen) * 8, .little);
501 mem.writeInt(u64, sizes[8..16], tag_bits, .little);
502 for (1..degree) |i| {
503 @memcpy(sizes[i * 16 ..][0..16], sizes[0..16]);
504 }
505 var t = blocks[3].xorBlocks(AesBlockVec.fromBytes(&sizes));
506 for (0..7) |_| {
507 state.update(t);
508 }
509 if (degree > 1) {
510 var v = [_]u8{0} ** rate;
511 switch (tag_bits) {
512 128 => {
513 const tags = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).xorBlocks(blocks[3]).xorBlocks(blocks[4]).xorBlocks(blocks[5]).toBytes();
514 for (1..degree) |d| {
515 v[0..16].* = tags[d * 16 ..][0..16].*;
516 state.absorb(&v);
517 }
518 },
519 256 => {
520 const tags_0 = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).toBytes();
521 const tags_1 = blocks[3].xorBlocks(blocks[4]).xorBlocks(blocks[5]).toBytes();
522 for (1..degree) |d| {
523 v[0..16].* = tags_0[d * 16 ..][0..16].*;
524 state.absorb(&v);
525 v[0..16].* = tags_1[d * 16 ..][0..16].*;
526 state.absorb(&v);
527 }
528 },
529 else => unreachable,
530 }
531 mem.writeInt(u64, sizes[0..8], degree, .little);
532 mem.writeInt(u64, sizes[8..16], tag_bits, .little);
533 t = blocks[3].xorBlocks(AesBlockVec.fromBytes(&sizes));
534 for (0..7) |_| {
535 state.update(t);
536 }
537 }
538 switch (tag_bits) {
539 128 => {
540 const tags = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).xorBlocks(blocks[3]).xorBlocks(blocks[4]).xorBlocks(blocks[5]).toBytes();
541 return tags[0..16].*;
542 },
543 256 => {
544 const tags_0 = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).toBytes();
545 const tags_1 = blocks[3].xorBlocks(blocks[4]).xorBlocks(blocks[5]).toBytes();
546 return tags_0[0..16].* ++ tags_1[0..16].*;
547 },
548 else => unreachable,
549 }
550 }
443551 };
444552}
445553
......@@ -492,7 +600,7 @@ fn Aegis256XGeneric(comptime degree: u7, comptime tag_bits: u9) type {
492600 state.enc(&dst, &src);
493601 @memcpy(c[i..][0 .. m.len % block_length], dst[0 .. m.len % block_length]);
494602 }
495 tag.* = state.mac(tag_bits, ad.len, m.len);
603 tag.* = state.finalize(tag_bits, ad.len, m.len);
496604 }
497605
498606 /// `m`: Message
......@@ -524,7 +632,7 @@ fn Aegis256XGeneric(comptime degree: u7, comptime tag_bits: u9) type {
524632 if (m.len % block_length != 0) {
525633 state.decLast(m[i..], c[i..]);
526634 }
527 var computed_tag = state.mac(tag_bits, ad.len, m.len);
635 var computed_tag = state.finalize(tag_bits, ad.len, m.len);
528636 const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
529637 if (!verify) {
530638 crypto.secureZero(u8, &computed_tag);
......@@ -562,9 +670,31 @@ pub const Aegis128X2Mac = AegisMac(Aegis128X2_256);
562670/// - It has a large security margin against internal collisions.
563671pub const Aegis128LMac = AegisMac(Aegis128L_256);
564672
673/// The `Aegis256X4Mac` message authentication function has a 256-bit key size,
674/// and outputs 256 bit tags.
675/// The key size is the main practical difference with `Aegis128X4Mac`.
676/// AEGIS' large state, non-linearity and non-invertibility provides the
677/// following properties:
678/// - 256 bit security against forgery.
679/// - Recovering the secret key from the state would require ~2^256 attempts,
680/// which is infeasible for any practical adversary.
681/// - It has a large security margin against internal collisions.
682pub const Aegis256X4Mac = AegisMac(Aegis256X4_256);
683
684/// The `Aegis256X2Mac` message authentication function has a 256-bit key size,
685/// and outputs 256 bit tags.
686/// The key size is the main practical difference with `Aegis128X2Mac`.
687/// AEGIS' large state, non-linearity and non-invertibility provides the
688/// following properties:
689/// - 256 bit security against forgery.
690/// - Recovering the secret key from the state would require ~2^256 attempts,
691/// which is infeasible for any practical adversary.
692/// - It has a large security margin against internal collisions.
693pub const Aegis256X2Mac = AegisMac(Aegis256X2_256);
694
565695/// The `Aegis256Mac` message authentication function has a 256-bit key size,
566/// and outputs 256 bit tags. Unless theoretical multi-target attacks are a
567/// concern, the AEGIS-128L variant should be preferred.
696/// and outputs 256 bit tags.
697/// The key size is the main practical difference with `Aegis128LMac`.
568698/// AEGIS' large state, non-linearity and non-invertibility provides the
569699/// following properties:
570700/// - 256 bit security against forgery.
......@@ -573,9 +703,21 @@ pub const Aegis128LMac = AegisMac(Aegis128L_256);
573703/// - It has a large security margin against internal collisions.
574704pub const Aegis256Mac = AegisMac(Aegis256_256);
575705
706/// AEGIS-128X4 MAC with 128-bit tags
707pub const Aegis128X4Mac_128 = AegisMac(Aegis128X4);
708
709/// AEGIS-128X2 MAC with 128-bit tags
710pub const Aegis128X2Mac_128 = AegisMac(Aegis128X2);
711
576712/// AEGIS-128L MAC with 128-bit tags
577713pub const Aegis128LMac_128 = AegisMac(Aegis128L);
578714
715/// AEGIS-256X4 MAC with 128-bit tags
716pub const Aegis256X4Mac_128 = AegisMac(Aegis256X4);
717
718/// AEGIS-256X2 MAC with 128-bit tags
719pub const Aegis256X2Mac_128 = AegisMac(Aegis256X2);
720
579721/// AEGIS-256 MAC with 128-bit tags
580722pub const Aegis256Mac_128 = AegisMac(Aegis256);
581723
......@@ -585,6 +727,7 @@ fn AegisMac(comptime T: type) type {
585727
586728 pub const mac_length = T.tag_length;
587729 pub const key_length = T.key_length;
730 pub const nonce_length = T.nonce_length;
588731 pub const block_length = T.block_length;
589732
590733 state: T.State,
......@@ -592,11 +735,17 @@ fn AegisMac(comptime T: type) type {
592735 off: usize = 0,
593736 msg_len: usize = 0,
594737
595 /// Initialize a state for the MAC function
738 /// Initialize a state for the MAC function, with a key and a nonce
739 pub fn initWithNonce(key: *const [key_length]u8, nonce: *const [nonce_length]u8) Mac {
740 return Mac{
741 .state = T.State.init(key.*, nonce.*),
742 };
743 }
744
745 /// Initialize a state for the MAC function, with a default nonce
596746 pub fn init(key: *const [key_length]u8) Mac {
597 const nonce = [_]u8{0} ** T.nonce_length;
598747 return Mac{
599 .state = T.State.init(key.*, nonce),
748 .state = T.State.init(key.*, [_]u8{0} ** nonce_length),
600749 };
601750 }
602751
......@@ -634,7 +783,14 @@ fn AegisMac(comptime T: type) type {
634783 @memcpy(pad[0..self.off], self.buf[0..self.off]);
635784 self.state.absorb(&pad);
636785 }
637 out.* = self.state.mac(T.tag_length * 8, self.msg_len, 0);
786 out.* = self.state.finalizeMac(T.tag_length * 8, self.msg_len);
787 }
788
789 /// Return an authentication tag for a message, a key and a nonce
790 pub fn createWithNonce(out: *[mac_length]u8, msg: []const u8, key: *const [key_length]u8, nonce: *const [nonce_length]u8) void {
791 var ctx = Mac.initWithNonce(key, nonce);
792 ctx.update(msg);
793 ctx.final(out);
638794 }
639795
640796 /// Return an authentication tag for a message and a key
......@@ -820,29 +976,72 @@ test "Aegis MAC" {
820976 st.update(msg[0..32]);
821977 st.update(msg[32..]);
822978 st.final(&tag);
823 try htest.assertEqual("f8840849602738d81037cbaa0f584ea95759e2ac60263ce77346bcdc79fe4319", &tag);
979 try htest.assertEqual("f5eb88d90b7d31c9a679eb94ed1374cd14816b19cdb77930d1a5158f8595983b", &tag);
824980
825981 st = st_init;
826982 st.update(msg[0..31]);
827983 st.update(msg[31..]);
828984 st.final(&tag);
829 try htest.assertEqual("f8840849602738d81037cbaa0f584ea95759e2ac60263ce77346bcdc79fe4319", &tag);
985 try htest.assertEqual("f5eb88d90b7d31c9a679eb94ed1374cd14816b19cdb77930d1a5158f8595983b", &tag);
830986
831987 st = st_init;
832988 st.update(msg[0..14]);
833989 st.update(msg[14..30]);
834990 st.update(msg[30..]);
835991 st.final(&tag);
836 try htest.assertEqual("f8840849602738d81037cbaa0f584ea95759e2ac60263ce77346bcdc79fe4319", &tag);
837
838 var empty: [0]u8 = undefined;
839 const nonce = [_]u8{0x00} ** Aegis128L_256.nonce_length;
840 Aegis128L_256.encrypt(&empty, &tag, &empty, &msg, nonce, key);
841 try htest.assertEqual("f8840849602738d81037cbaa0f584ea95759e2ac60263ce77346bcdc79fe4319", &tag);
992 try htest.assertEqual("f5eb88d90b7d31c9a679eb94ed1374cd14816b19cdb77930d1a5158f8595983b", &tag);
842993
843994 // An update whose size is not a multiple of the block size
844995 st = st_init;
845996 st.update(msg[0..33]);
846997 st.final(&tag);
847 try htest.assertEqual("c7cf649a844c1a6676cf6d91b1658e0aee54a4da330b0a8d3bc7ea4067551d1b", &tag);
998 try htest.assertEqual("07b3ba5ad9ceee5ef1906e3396f0fa540fbcd2f33833ef97c35bdc2ae9ae0535", &tag);
999}
1000
1001test "AEGISMAC-128* test vectors" {
1002 const key = [_]u8{ 0x10, 0x01 } ++ [_]u8{0x00} ** (16 - 2);
1003 const nonce = [_]u8{ 0x10, 0x00, 0x02 } ++ [_]u8{0x00} ** (16 - 3);
1004 var msg: [35]u8 = undefined;
1005 for (&msg, 0..) |*byte, i| byte.* = @truncate(i);
1006 var mac128: [16]u8 = undefined;
1007 var mac256: [32]u8 = undefined;
1008
1009 Aegis128LMac.createWithNonce(&mac256, &msg, &key, &nonce);
1010 Aegis128LMac_128.createWithNonce(&mac128, &msg, &key, &nonce);
1011 try htest.assertEqual("d3f09b2842ad301687d6902c921d7818", &mac128);
1012 try htest.assertEqual("9490e7c89d420c9f37417fa625eb38e8cad53c5cbec55285e8499ea48377f2a3", &mac256);
1013
1014 Aegis128X2Mac.createWithNonce(&mac256, &msg, &key, &nonce);
1015 Aegis128X2Mac_128.createWithNonce(&mac128, &msg, &key, &nonce);
1016 try htest.assertEqual("7aa41edfd57a95c1108d83c63b8d4d01", &mac128);
1017 try htest.assertEqual("55b6449929cd2b01d04786e57698b3ddfb5cbf6e421bbd022637a33d60f40294", &mac256);
1018
1019 Aegis128X4Mac.createWithNonce(&mac256, &msg, &key, &nonce);
1020 Aegis128X4Mac_128.createWithNonce(&mac128, &msg, &key, &nonce);
1021 try htest.assertEqual("46a194ea4337bb32c2186a99e312f3a7", &mac128);
1022 try htest.assertEqual("ea884072699569532fb68ae9fb2653c9ffef3e974333d3a17d77be02453cc12f", &mac256);
1023}
1024
1025test "AEGISMAC-256* test vectors" {
1026 const key = [_]u8{ 0x10, 0x01 } ++ [_]u8{0x00} ** (32 - 2);
1027 const nonce = [_]u8{ 0x10, 0x00, 0x02 } ++ [_]u8{0x00} ** (32 - 3);
1028 var msg: [35]u8 = undefined;
1029 for (&msg, 0..) |*byte, i| byte.* = @truncate(i);
1030 var mac128: [16]u8 = undefined;
1031 var mac256: [32]u8 = undefined;
1032
1033 Aegis256Mac.createWithNonce(&mac256, &msg, &key, &nonce);
1034 Aegis256Mac_128.createWithNonce(&mac128, &msg, &key, &nonce);
1035 try htest.assertEqual("c08e20cfc56f27195a46c9cef5c162d4", &mac128);
1036 try htest.assertEqual("a5c906ede3d69545c11e20afa360b221f936e946ed2dba3d7c75ad6dc2784126", &mac256);
1037
1038 Aegis256X2Mac.createWithNonce(&mac256, &msg, &key, &nonce);
1039 Aegis256X2Mac_128.createWithNonce(&mac128, &msg, &key, &nonce);
1040 try htest.assertEqual("fb319cb6dd728a764606fb14d37f2a5e", &mac128);
1041 try htest.assertEqual("0844b20ed5147ceae89c7a160263afd4b1382d6b154ecf560ce8a342cb6a8fd1", &mac256);
1042
1043 Aegis256X4Mac.createWithNonce(&mac256, &msg, &key, &nonce);
1044 Aegis256X4Mac_128.createWithNonce(&mac128, &msg, &key, &nonce);
1045 try htest.assertEqual("a51f9bc5beae60cce77f0dbc60761edd", &mac128);
1046 try htest.assertEqual("b36a16ef07c36d75a91f437502f24f545b8dfa88648ed116943c29fead3bf10c", &mac256);
8481047}
lib/std/crypto/benchmark.zig+4
......@@ -72,6 +72,10 @@ const macs = [_]Crypto{
7272 Crypto{ .ty = crypto.auth.siphash.SipHash64(1, 3), .name = "siphash-1-3" },
7373 Crypto{ .ty = crypto.auth.siphash.SipHash128(2, 4), .name = "siphash128-2-4" },
7474 Crypto{ .ty = crypto.auth.siphash.SipHash128(1, 3), .name = "siphash128-1-3" },
75 Crypto{ .ty = crypto.auth.aegis.Aegis128X4Mac, .name = "aegis-128x4 mac" },
76 Crypto{ .ty = crypto.auth.aegis.Aegis256X4Mac, .name = "aegis-256x4 mac" },
77 Crypto{ .ty = crypto.auth.aegis.Aegis128X2Mac, .name = "aegis-128x2 mac" },
78 Crypto{ .ty = crypto.auth.aegis.Aegis256X2Mac, .name = "aegis-256x2 mac" },
7579 Crypto{ .ty = crypto.auth.aegis.Aegis128LMac, .name = "aegis-128l mac" },
7680 Crypto{ .ty = crypto.auth.aegis.Aegis256Mac, .name = "aegis-256 mac" },
7781 Crypto{ .ty = crypto.auth.cmac.CmacAes128, .name = "aes-cmac" },