aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Schlyter <erik@erisc.se>2025-08-25 17:59:42 +0200
committerGitHub <noreply@github.com>2025-08-25 15:59:42 +0000
commit37f4bee92a78fa4543d723b834a1570e2dd38a13 (patch)
tree29694e59a8077b441b153d295997a37ddc4b0968
parent9924897c065af526f43c82d4b8328b5e72d100bd (diff)
downloadzig-37f4bee92a78fa4543d723b834a1570e2dd38a13.tar.gz
zig-37f4bee92a78fa4543d723b834a1570e2dd38a13.zip
Fix #24999: copy left-overs before we XOR into c. (#25001)
It is important we copy the left-overs in the message *before* we XOR it into the ciphertext, because if we're encrypting in-place (i.e., m == c), we will manipulate the message that will be used for tag generation. This will generate faulty tags when message length doesn't conform with 16 byte blocks.
-rw-r--r--lib/std/crypto/aes_ocb.zig35
1 files changed, 32 insertions, 3 deletions
diff --git a/lib/std/crypto/aes_ocb.zig b/lib/std/crypto/aes_ocb.zig
index b5a0e24f1a..44a0fb2430 100644
--- a/lib/std/crypto/aes_ocb.zig
+++ b/lib/std/crypto/aes_ocb.zig
@@ -155,12 +155,12 @@ fn AesOcb(comptime Aes: anytype) type {
xorWith(&offset, lx.star);
var pad = offset;
aes_enc_ctx.encrypt(&pad, &pad);
- for (m[i * 16 ..], 0..) |x, j| {
- c[i * 16 + j] = pad[j] ^ x;
- }
var e = [_]u8{0} ** 16;
@memcpy(e[0..leftover], m[i * 16 ..][0..leftover]);
e[leftover] = 0x80;
+ for (m[i * 16 ..], 0..) |x, j| {
+ c[i * 16 + j] = pad[j] ^ x;
+ }
xorWith(&sum, e);
}
var e = xorBlocks(xorBlocks(sum, offset), lx.dol);
@@ -354,3 +354,32 @@ test "AesOcb test vector 4" {
try Aes128Ocb.decrypt(&m2, &c, tag, &ad, nonce, k);
assert(mem.eql(u8, &m, &m2));
}
+
+test "AesOcb in-place encryption-decryption" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
+
+ var k: [Aes128Ocb.key_length]u8 = undefined;
+ var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
+ var tag: [Aes128Ocb.tag_length]u8 = undefined;
+ var m: [40]u8 = undefined;
+ var original_m: [m.len]u8 = undefined;
+ _ = try hexToBytes(&k, "000102030405060708090A0B0C0D0E0F");
+ _ = try hexToBytes(&m, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627");
+ _ = try hexToBytes(&nonce, "BBAA9988776655443322110D");
+ const ad = m;
+
+ @memcpy(&original_m, &m);
+
+ Aes128Ocb.encrypt(&m, &tag, &m, &ad, nonce, k);
+
+ var expected_c: [m.len]u8 = undefined;
+ var expected_tag: [tag.len]u8 = undefined;
+ _ = try hexToBytes(&expected_tag, "ED07BA06A4A69483A7035490C5769E60");
+ _ = try hexToBytes(&expected_c, "D5CA91748410C1751FF8A2F618255B68A0A12E093FF454606E59F9C1D0DDC54B65E8628E568BAD7A");
+
+ try testing.expectEqualSlices(u8, &expected_tag, &tag);
+ try testing.expectEqualSlices(u8, &expected_c, &m);
+ try Aes128Ocb.decrypt(&m, &m, tag, &ad, nonce, k);
+
+ try testing.expectEqualSlices(u8, &original_m, &m);
+}