master
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3const testing = std.testing;
4
5const has_aesni = builtin.cpu.has(.x86, .aes);
6const has_avx = builtin.cpu.has(.x86, .avx);
7const has_armaes = builtin.cpu.has(.aarch64, .aes);
8// C backend doesn't currently support passing vectors to inline asm.
9const impl = if (builtin.cpu.arch == .x86_64 and builtin.zig_backend != .stage2_c and has_aesni and has_avx) impl: {
10 break :impl @import("aes/aesni.zig");
11} else if (builtin.cpu.arch == .aarch64 and builtin.zig_backend != .stage2_c and has_armaes)
12impl: {
13 break :impl @import("aes/armcrypto.zig");
14} else impl: {
15 break :impl @import("aes/soft.zig");
16};
17
18/// `true` if AES is backed by hardware (AES-NI on x86_64, ARM Crypto Extensions on AArch64).
19/// Software implementations are much slower, and should be avoided if possible.
20pub const has_hardware_support =
21 (builtin.cpu.arch == .x86_64 and has_aesni and has_avx) or
22 (builtin.cpu.arch == .aarch64 and has_armaes);
23
24pub const Block = impl.Block;
25pub const BlockVec = impl.BlockVec;
26pub const AesEncryptCtx = impl.AesEncryptCtx;
27pub const AesDecryptCtx = impl.AesDecryptCtx;
28pub const Aes128 = impl.Aes128;
29pub const Aes256 = impl.Aes256;
30
31test "encrypt" {
32 // Appendix B
33 {
34 const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
35 const in = [_]u8{ 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 };
36 const exp_out = [_]u8{ 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 };
37
38 var out: [exp_out.len]u8 = undefined;
39 var ctx = Aes128.initEnc(key);
40 ctx.encrypt(out[0..], in[0..]);
41 try testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
42 }
43
44 // Appendix C.3
45 {
46 const key = [_]u8{
47 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
48 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
49 };
50 const in = [_]u8{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
51 const exp_out = [_]u8{ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 };
52
53 var out: [exp_out.len]u8 = undefined;
54 var ctx = Aes256.initEnc(key);
55 ctx.encrypt(out[0..], in[0..]);
56 try testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
57 }
58}
59
60test "decrypt" {
61 // Appendix B
62 {
63 const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
64 const in = [_]u8{ 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 };
65 const exp_out = [_]u8{ 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 };
66
67 var out: [exp_out.len]u8 = undefined;
68 var ctx = Aes128.initDec(key);
69 ctx.decrypt(out[0..], in[0..]);
70 try testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
71 }
72
73 // Appendix C.3
74 {
75 const key = [_]u8{
76 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
77 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
78 };
79 const in = [_]u8{ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 };
80 const exp_out = [_]u8{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
81
82 var out: [exp_out.len]u8 = undefined;
83 var ctx = Aes256.initDec(key);
84 ctx.decrypt(out[0..], in[0..]);
85 try testing.expectEqualSlices(u8, exp_out[0..], out[0..]);
86 }
87}
88
89test "expand 128-bit key" {
90 const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
91 const exp_enc = [_]*const [32:0]u8{
92 "2b7e151628aed2a6abf7158809cf4f3c", "a0fafe1788542cb123a339392a6c7605", "f2c295f27a96b9435935807a7359f67f", "3d80477d4716fe3e1e237e446d7a883b", "ef44a541a8525b7fb671253bdb0bad00", "d4d1c6f87c839d87caf2b8bc11f915bc", "6d88a37a110b3efddbf98641ca0093fd", "4e54f70e5f5fc9f384a64fb24ea6dc4f", "ead27321b58dbad2312bf5607f8d292f", "ac7766f319fadc2128d12941575c006e", "d014f9a8c9ee2589e13f0cc8b6630ca6",
93 };
94 const exp_dec = [_]*const [32:0]u8{
95 "d014f9a8c9ee2589e13f0cc8b6630ca6", "0c7b5a631319eafeb0398890664cfbb4", "df7d925a1f62b09da320626ed6757324", "12c07647c01f22c7bc42d2f37555114a", "6efcd876d2df54807c5df034c917c3b9", "6ea30afcbc238cf6ae82a4b4b54a338d", "90884413d280860a12a128421bc89739", "7c1f13f74208c219c021ae480969bf7b", "cc7505eb3e17d1ee82296c51c9481133", "2b3708a7f262d405bc3ebdbf4b617d62", "2b7e151628aed2a6abf7158809cf4f3c",
96 };
97 const enc = Aes128.initEnc(key);
98 const dec = Aes128.initDec(key);
99 var exp: [16]u8 = undefined;
100
101 for (enc.key_schedule.round_keys, 0..) |round_key, i| {
102 _ = try std.fmt.hexToBytes(&exp, exp_enc[i]);
103 try testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
104 }
105 for (dec.key_schedule.round_keys, 0..) |round_key, i| {
106 _ = try std.fmt.hexToBytes(&exp, exp_dec[i]);
107 try testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
108 }
109}
110
111test "invMixColumns" {
112 const key = [_]u8{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
113 const enc_ctx = Aes128.initEnc(key);
114 const dec_ctx = Aes128.initDec(key);
115
116 for (1..10) |i| {
117 const enc_rk = enc_ctx.key_schedule.round_keys[10 - i];
118 const dec_rk = dec_ctx.key_schedule.round_keys[i];
119 const computed = enc_rk.invMixColumns();
120 try testing.expectEqualSlices(u8, &dec_rk.toBytes(), &computed.toBytes());
121 }
122}
123
124test "BlockVec invMixColumns" {
125 const input = [_]u8{
126 0x5f, 0x57, 0xf7, 0x1d, 0x72, 0xf5, 0xbe, 0xb9, 0x64, 0xbc, 0x3b, 0xf9, 0x15, 0x92, 0x29, 0x1a,
127 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
128 };
129
130 const vec2 = BlockVec(2).fromBytes(&input);
131 const result_vec = vec2.invMixColumns();
132 const result_bytes = result_vec.toBytes();
133
134 for (0..2) |i| {
135 const block = Block.fromBytes(input[i * 16 ..][0..16]);
136 const expected = block.invMixColumns().toBytes();
137 try testing.expectEqualSlices(u8, &expected, result_bytes[i * 16 ..][0..16]);
138 }
139}
140
141test "expand 256-bit key" {
142 const key = [_]u8{
143 0x60, 0x3d, 0xeb, 0x10,
144 0x15, 0xca, 0x71, 0xbe,
145 0x2b, 0x73, 0xae, 0xf0,
146 0x85, 0x7d, 0x77, 0x81,
147 0x1f, 0x35, 0x2c, 0x07,
148 0x3b, 0x61, 0x08, 0xd7,
149 0x2d, 0x98, 0x10, 0xa3,
150 0x09, 0x14, 0xdf, 0xf4,
151 };
152 const exp_enc = [_]*const [32:0]u8{
153 "603deb1015ca71be2b73aef0857d7781", "1f352c073b6108d72d9810a30914dff4", "9ba354118e6925afa51a8b5f2067fcde",
154 "a8b09c1a93d194cdbe49846eb75d5b9a", "d59aecb85bf3c917fee94248de8ebe96", "b5a9328a2678a647983122292f6c79b3",
155 "812c81addadf48ba24360af2fab8b464", "98c5bfc9bebd198e268c3ba709e04214", "68007bacb2df331696e939e46c518d80",
156 "c814e20476a9fb8a5025c02d59c58239", "de1369676ccc5a71fa2563959674ee15", "5886ca5d2e2f31d77e0af1fa27cf73c3",
157 "749c47ab18501ddae2757e4f7401905a", "cafaaae3e4d59b349adf6acebd10190d", "fe4890d1e6188d0b046df344706c631e",
158 };
159 const exp_dec = [_]*const [32:0]u8{
160 "fe4890d1e6188d0b046df344706c631e", "ada23f4963e23b2455427c8a5c709104", "57c96cf6074f07c0706abb07137f9241",
161 "b668b621ce40046d36a047ae0932ed8e", "34ad1e4450866b367725bcc763152946", "32526c367828b24cf8e043c33f92aa20",
162 "c440b289642b757227a3d7f114309581", "d669a7334a7ade7a80c8f18fc772e9e3", "25ba3c22a06bc7fb4388a28333934270",
163 "54fb808b9c137949cab22ff547ba186c", "6c3d632985d1fbd9e3e36578701be0f3", "4a7459f9c8e8f9c256a156bc8d083799",
164 "42107758e9ec98f066329ea193f8858b", "8ec6bff6829ca03b9e49af7edba96125", "603deb1015ca71be2b73aef0857d7781",
165 };
166 const enc = Aes256.initEnc(key);
167 const dec = Aes256.initDec(key);
168 var exp: [16]u8 = undefined;
169
170 for (enc.key_schedule.round_keys, 0..) |round_key, i| {
171 _ = try std.fmt.hexToBytes(&exp, exp_enc[i]);
172 try testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
173 }
174 for (dec.key_schedule.round_keys, 0..) |round_key, i| {
175 _ = try std.fmt.hexToBytes(&exp, exp_dec[i]);
176 try testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
177 }
178}