authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2026-05-29 11:18:39+02:00
committergravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2026-07-12 13:23:53+02:00
loge3395669223afa70a5cae1dd9a12b3a5f0656209
tree2259cd02591b5671399cbb672edb77139c3b8487
parentcb5635714cbd8c7fc2911536e59e58b96fe0ba1f

crypto.mode.ctr: make the counter wrap, even in parallel updates

Counter mode encrypts/decrypts using a counter to create the key stream. The counter is allowed to wrap. This is especially necessary in SIV modes where it can start from any possible value. And it was in the sequential path, but not in the parallel one.

1 files changed, 8 insertions(+), 1 deletions(-)

lib/std/crypto/modes.zig+8-1
...@@ -55,7 +55,7 @@ pub fn ctrSlice(...@@ -55,7 +55,7 @@ pub fn ctrSlice(
55 inline while (j < parallel_count) : (j += 1) {55 inline while (j < parallel_count) : (j += 1) {
56 mem.writeInt(CounterInt, counters[j * block_length + counter_offset ..][0..counter_size], cnt_val +% j, endian);56 mem.writeInt(CounterInt, counters[j * block_length + counter_offset ..][0..counter_size], cnt_val +% j, endian);
57 }57 }
58 cnt_val += parallel_count;58 cnt_val +%= parallel_count;
59 block_cipher.xorWide(parallel_count, dst[i .. i + wide_block_length][0..wide_block_length], src[i .. i + wide_block_length][0..wide_block_length], counters);59 block_cipher.xorWide(parallel_count, dst[i .. i + wide_block_length][0..wide_block_length], src[i .. i + wide_block_length][0..wide_block_length], counters);
60 }60 }
61 mem.writeInt(CounterInt, counterBlock[counter_offset..][0..counter_size], cnt_val, endian);61 mem.writeInt(CounterInt, counterBlock[counter_offset..][0..counter_size], cnt_val, endian);
...@@ -224,4 +224,11 @@ test "ctr mode" {...@@ -224,4 +224,11 @@ test "ctr mode" {
224 const expected = [_]u8{ 0x7e, 0x48, 0x15, 0xa8, 0x16, 0x66, 0xf0, 0xea, 0xad, 0x3c, 0x07, 0x97, 0x2f, 0xe8, 0x25, 0xc1 };224 const expected = [_]u8{ 0x7e, 0x48, 0x15, 0xa8, 0x16, 0x66, 0xf0, 0xea, 0xad, 0x3c, 0x07, 0x97, 0x2f, 0xe8, 0x25, 0xc1 };
225 try testing.expectEqualSlices(u8, expected[0..], out[0..]);225 try testing.expectEqualSlices(u8, expected[0..], out[0..]);
226 }226 }
227
228 // Make the counter wrap
229 {
230 const iv_top: [16]u8 = @splat(0xff);
231 var buf: [256]u8 = @splat(0);
232 ctr(aes.AesEncryptCtx(aes.Aes128), ctx, buf[0..], buf[0..], iv_top, .little);
233 }
227}234}