diff --git a/vlib/x/crypto/chacha20/chacha.v b/vlib/x/crypto/chacha20/chacha.v index f16829d402..4887cc0d5e 100644 --- a/vlib/x/crypto/chacha20/chacha.v +++ b/vlib/x/crypto/chacha20/chacha.v @@ -141,12 +141,14 @@ pub fn (mut c Cipher) xor_key_stream(mut dst []u8, src []u8) { if dst.len < src.len { panic('chacha20/chacha: dst buffer is to small') } - if subtle.inexact_overlap(dst, src) { - panic('chacha20: invalid buffer overlap') - } mut idx := 0 mut src_len := src.len + dst = unsafe { dst[..src_len] } + + if subtle.inexact_overlap(dst, src) { + panic('chacha20: invalid buffer overlap') + } // We adapt and ports the go version here // First, drain any remaining key stream @@ -188,7 +190,9 @@ pub fn (mut c Cipher) xor_key_stream(mut dst []u8, src []u8) { src_len -= full // we dont support bufsize + // FIXME: instead generates once block keystream again, i think we can panic here if u64(c.nonce[0]) + 1 > max_u32 { + c.block = []u8{len: block_size} numblocks := (src_len + block_size - 1) / block_size mut buf := c.block[block_size - numblocks * block_size..] _ := copy(mut buf, src[idx..]) @@ -200,6 +204,10 @@ pub fn (mut c Cipher) xor_key_stream(mut dst []u8, src []u8) { // If we have a partial block, pad it for chacha20_block_generic, and // keep the leftover keystream for the next invocation. if src_len > 0 { + // Make sure, internal buffer cleared with the new one + // or the old garbaged data from previous call still there + // See https://github.com/vlang/v/issues/24043 + c.block = []u8{len: block_size} // copy the last src block to internal buffer, and performs // chacha20_block_generic on this buffer, and stores into remaining dst _ := copy(mut c.block, src[idx..]) diff --git a/vlib/x/crypto/chacha20/chacha_test.v b/vlib/x/crypto/chacha20/chacha_test.v index 1c947693fc..a8c6af9783 100644 --- a/vlib/x/crypto/chacha20/chacha_test.v +++ b/vlib/x/crypto/chacha20/chacha_test.v @@ -3,6 +3,59 @@ module chacha20 import rand import encoding.hex +const encoded_data = [ + [u8(231), 121, 9, 28], + [u8(178), 221, 62, 9, 153, 189, 106, 12, 117, 47, 192, 81, 65, 112, 85, 57], + [u8(155), 202, 56, 16], + [u8(227), 47, 226, 137], + [u8(162), 77, 218, 52], + [u8(42), 250, 184, 196], + [u8(2), 129, 13, 136, 6, 12, 235, 183, 38, 178, 151, 243, 27, 88, 97, 40], + [u8(248), 170, 168, 206], + [u8(181), 220, 223, 139], + [u8(95), 108, 201, 227], + [u8(38), 221, 147, 230], + [u8(98), 229, 5, 130, 13, 103, 248, 159, 240, 246, 56, 119, 160, 130, 82, 222], + // additional data + 'hello hello hello'.bytes(), + 'me me me'.bytes(), +] + +// expected data obtained with an equivalent Java program +const expected_data = [ + [u8(0), 0, 0, 9], + [u8(0), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [u8(0), 0, 0, 1], + [u8(0), 0, 0, 0], + [u8(0), 0, 0, 0], + [u8(0), 0, 0, 9], + [u8(0), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [u8(0), 0, 0, 1], + [u8(0), 0, 0, 0], + [u8(0), 0, 0, 0], + [u8(0), 0, 0, 9], + [u8(0), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + // golang script produces this + [u8(119), 69, 96, 134, 100, 241, 107, 39, 71, 72, 65, 158, 50, 76, 187, 68, 100], + [u8(164), 169, 216, 98, 61, 175, 20, 175], +] + +// See https://github.com/vlang/v/issues/24043 +fn test_for_more_consecutive_xor_key_stream() { + key := [u8(225), 2, 1, 178, 238, 127, 187, 188, 27, 237, 18, 62, 181, 65, 67, 152, 13, 247, + 147, 148, 101, 220, 185, 120, 234, 58, 144, 173, 3, 218, 193, 130] + nonce := [u8(153), 221, 244, 134, 99, 135, 243, 247, 169, 121, 69, 54] + + mut cipher := new_cipher(key, nonce)! + for i := 0; i < encoded_data.len; i++ { + p := encoded_data[i] + e := expected_data[i] + mut dst := []u8{len: p.len} + cipher.xor_key_stream(mut dst, p) + assert dst == e + } +} + fn test_xor_key_stream_consecutive() { // See https://github.com/vlang/v/issues/23977 key := [u8(64), 116, 63, 11, 221, 199, 187, 110, 217, 68, 0, 50, 65, 79, 24, 10, 124, 174,