diff --git a/vlib/crypto/cipher/aes_ctr_test.v b/vlib/crypto/cipher/aes_ctr_test.v index 31847c0265..e8a0068cfb 100644 --- a/vlib/crypto/cipher/aes_ctr_test.v +++ b/vlib/crypto/cipher/aes_ctr_test.v @@ -18,12 +18,12 @@ fn test_aes_ctr() { fn aes_ctr_en(mut src []u8, key []u8, iv []u8) { block := aes.new_cipher(key) - mode := cipher.new_ctr(block, iv) + mut mode := cipher.new_ctr(block, iv) mode.xor_key_stream(mut src, src.clone()) } fn aes_ctr_de(mut src []u8, key []u8, iv []u8) { block := aes.new_cipher(key) - mode := cipher.new_ctr(block, iv) + mut mode := cipher.new_ctr(block, iv) mode.xor_key_stream(mut src, src.clone()) } diff --git a/vlib/crypto/cipher/cfb.v b/vlib/crypto/cipher/cfb.v index 0dc0ffc420..b677f5c977 100644 --- a/vlib/crypto/cipher/cfb.v +++ b/vlib/crypto/cipher/cfb.v @@ -63,34 +63,34 @@ fn new_cfb(b Block, iv []u8, decrypt bool) Cfb { return x } -pub fn (mut x Cfb) xor_key_stream(mut dst_ []u8, src_ []u8) { +pub fn (mut x Cfb) xor_key_stream(mut dst []u8, src []u8) { unsafe { - mut dst := *dst_ - mut src := src_ - if dst.len < src.len { + mut local_dst := *dst + mut local_src := src + if local_dst.len < local_src.len { panic('crypto.cipher.xor_key_stream: output smaller than input') } - if subtle.inexact_overlap(dst[..src.len], src) { + if subtle.inexact_overlap(local_dst[..src.len], local_src) { panic('crypto.cipher.xor_key_stream: invalid buffer overlap') } - for src.len > 0 { + for local_src.len > 0 { if x.out_used == x.out.len { x.b.encrypt(mut x.out, x.next) x.out_used = 0 } if x.decrypt { - copy(mut x.next[x.out_used..], src) + copy(mut x.next[x.out_used..], local_src) } - n := xor_bytes(mut dst, src, x.out[x.out_used..]) + n := xor_bytes(mut local_dst, local_src, x.out[x.out_used..]) if !x.decrypt { - copy(mut x.next[x.out_used..], dst) + copy(mut x.next[x.out_used..], local_dst) } - dst = dst[n..] - src = src[n..] + local_dst = local_dst[n..] + local_src = local_src[n..] x.out_used += n } } diff --git a/vlib/crypto/cipher/cfb_test.v b/vlib/crypto/cipher/cfb_test.v new file mode 100644 index 0000000000..c896bbfbe3 --- /dev/null +++ b/vlib/crypto/cipher/cfb_test.v @@ -0,0 +1,18 @@ +import crypto.cipher +import crypto.des + +struct StreamCipher { + cipher cipher.Stream +} + +fn test_cfb_stream_cipher() ! { + key := '123456789012345678901234'.bytes() + iv := 'abcdegfh'.bytes() + + block := des.new_cipher(key[..8]) + c := cipher.new_cfb_encrypter(block, iv) + + s := StreamCipher{ + cipher: c + } +} diff --git a/vlib/crypto/cipher/cipher.v b/vlib/crypto/cipher/cipher.v index a364b565e0..086b8f88f5 100644 --- a/vlib/crypto/cipher/cipher.v +++ b/vlib/crypto/cipher/cipher.v @@ -16,6 +16,7 @@ pub interface Block { // A Stream represents a stream cipher. pub interface Stream { +mut: // xor_key_stream XORs each byte in the given slice with a byte from the // cipher's key stream. Dst and src must overlap entirely or not at all. // diff --git a/vlib/crypto/cipher/ctr.v b/vlib/crypto/cipher/ctr.v index 48deef0c82..db8b2c4515 100644 --- a/vlib/crypto/cipher/ctr.v +++ b/vlib/crypto/cipher/ctr.v @@ -49,25 +49,25 @@ pub fn new_ctr(b Block, iv []u8) Ctr { } } -pub fn (x &Ctr) xor_key_stream(mut dst_ []u8, src_ []u8) { +pub fn (mut x Ctr) xor_key_stream(mut dst []u8, src []u8) { unsafe { - mut dst := *dst_ - mut src := src_ - if dst.len < src.len { + mut local_dst := *dst + mut local_src := src + if local_dst.len < local_src.len { panic('crypto.cipher.xor_key_stream: output smaller than input') } - if subtle.inexact_overlap(dst[..src.len], src) { + if subtle.inexact_overlap(local_dst[..local_src.len], local_src) { panic('crypto.cipher.xor_key_stream: invalid buffer overlap') } - for src.len > 0 { + for local_src.len > 0 { if x.out_used == x.out.len { x.b.encrypt(mut x.out, x.next) x.out_used = 0 } - n := xor_bytes(mut dst, src, x.out[x.out_used..]) + n := xor_bytes(mut local_dst, local_src, x.out[x.out_used..]) // increment counter for i := x.next.len - 1; i >= 0; i-- { @@ -77,8 +77,8 @@ pub fn (x &Ctr) xor_key_stream(mut dst_ []u8, src_ []u8) { } } - dst = dst[n..] - src = src[n..] + local_dst = local_dst[n..] + local_src = local_src[n..] x.out_used += n } } diff --git a/vlib/crypto/cipher/ctr_test.v b/vlib/crypto/cipher/ctr_test.v new file mode 100644 index 0000000000..b1327ba55b --- /dev/null +++ b/vlib/crypto/cipher/ctr_test.v @@ -0,0 +1,18 @@ +import crypto.cipher +import crypto.des + +struct StreamCipher { + cipher cipher.Stream +} + +fn test_ctr_stream_cipher() ! { + key := '123456789012345678901234'.bytes() + iv := 'abcdegfh'.bytes() + + block := des.new_cipher(key[..8]) + c := cipher.new_ctr(block, iv) + + s := StreamCipher{ + cipher: c + } +} diff --git a/vlib/crypto/cipher/des_ctr_test.v b/vlib/crypto/cipher/des_ctr_test.v index 923666a73b..73b083fb33 100644 --- a/vlib/crypto/cipher/des_ctr_test.v +++ b/vlib/crypto/cipher/des_ctr_test.v @@ -29,24 +29,24 @@ fn test_des_ctr() { fn des_ctr_en(mut src []u8, key []u8, iv []u8) { block := des.new_cipher(key) - mode := cipher.new_ctr(block, iv) + mut mode := cipher.new_ctr(block, iv) mode.xor_key_stream(mut src, src.clone()) } fn des_ctr_de(mut src []u8, key []u8, iv []u8) { block := des.new_cipher(key) - mode := cipher.new_ctr(block, iv) + mut mode := cipher.new_ctr(block, iv) mode.xor_key_stream(mut src, src.clone()) } fn triple_des_ctr_en(mut src []u8, key []u8, iv []u8) { block := des.new_triple_des_cipher(key) - mode := cipher.new_ctr(block, iv) + mut mode := cipher.new_ctr(block, iv) mode.xor_key_stream(mut src, src.clone()) } fn triple_des_ctr_de(mut src []u8, key []u8, iv []u8) { block := des.new_triple_des_cipher(key) - mode := cipher.new_ctr(block, iv) + mut mode := cipher.new_ctr(block, iv) mode.xor_key_stream(mut src, src.clone()) } diff --git a/vlib/crypto/cipher/ofb.v b/vlib/crypto/cipher/ofb.v index dbfc3bcad8..4c21f94341 100644 --- a/vlib/crypto/cipher/ofb.v +++ b/vlib/crypto/cipher/ofb.v @@ -35,19 +35,19 @@ pub fn new_ofb(b Block, iv []u8) Ofb { return x } -pub fn (mut x Ofb) xor_key_stream(mut dst_ []u8, src_ []u8) { +pub fn (mut x Ofb) xor_key_stream(mut dst []u8, src []u8) { unsafe { - mut dst := *dst_ - mut src := src_ - if dst.len < src.len { + mut local_dst := *dst + mut local_src := src + if local_dst.len < local_src.len { panic('crypto.cipher.xor_key_stream: output smaller than input') } - if subtle.inexact_overlap(dst[..src.len], src) { + if subtle.inexact_overlap(local_dst[..local_src.len], local_src) { panic('crypto.cipher.xor_key_stream: invalid buffer overlap') } - for src.len > 0 { + for local_src.len > 0 { if x.out_used == x.out.len { x.b.encrypt(mut x.out, x.next) x.out_used = 0 @@ -55,9 +55,9 @@ pub fn (mut x Ofb) xor_key_stream(mut dst_ []u8, src_ []u8) { copy(mut x.next, x.out) - n := xor_bytes(mut dst, src, x.out) - dst = dst[n..] - src = src[n..] + n := xor_bytes(mut local_dst, local_src, x.out) + local_dst = local_dst[n..] + local_src = local_src[n..] x.out_used += n } } diff --git a/vlib/crypto/cipher/ofb_test.v b/vlib/crypto/cipher/ofb_test.v new file mode 100644 index 0000000000..99a2af9c97 --- /dev/null +++ b/vlib/crypto/cipher/ofb_test.v @@ -0,0 +1,18 @@ +import crypto.cipher +import crypto.des + +struct StreamCipher { + cipher cipher.Stream +} + +fn test_ctr_stream_cipher() ! { + key := '123456789012345678901234'.bytes() + iv := 'abcdegfh'.bytes() + + block := des.new_cipher(key[..8]) + c := cipher.new_ofb(block, iv) + + s := StreamCipher{ + cipher: c + } +} diff --git a/vlib/crypto/rc4/rc4.v b/vlib/crypto/rc4/rc4.v index 7046f0ad8c..91240f466d 100644 --- a/vlib/crypto/rc4/rc4.v +++ b/vlib/crypto/rc4/rc4.v @@ -65,7 +65,7 @@ pub fn (mut c Cipher) reset() { // xor_key_stream sets dst to the result of XORing src with the key stream. // Dst and src must overlap entirely or not at all. -pub fn (mut c Cipher) xor_key_stream(mut dst []u8, mut src []u8) { +pub fn (mut c Cipher) xor_key_stream(mut dst []u8, src []u8) { if src.len == 0 { return } diff --git a/vlib/crypto/rc4/rc4_test.v b/vlib/crypto/rc4/rc4_test.v index 3e69a1ed5e..15dc20cb27 100644 --- a/vlib/crypto/rc4/rc4_test.v +++ b/vlib/crypto/rc4/rc4_test.v @@ -1,8 +1,22 @@ // Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved. // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. +import crypto.cipher import crypto.rc4 +struct StreamCipher { + cipher cipher.Stream +} + +fn test_cfb_stream_cipher() ! { + key := 'tthisisourrc4key'.bytes() + c := rc4.new_cipher(key)! + + s := StreamCipher{ + cipher: c + } +} + fn test_crypto_rc4() { key := 'tthisisourrc4key'.bytes() @@ -14,7 +28,7 @@ fn test_crypto_rc4() { mut src := 'toencrypt'.bytes() // src & dst same, encrypt in place - c.xor_key_stream(mut src, mut src) // encrypt data + c.xor_key_stream(mut src, src) // encrypt data c.reset() diff --git a/vlib/x/crypto/chacha20/chacha_test.v b/vlib/x/crypto/chacha20/chacha_test.v index 6b464605ab..f74a2edc83 100644 --- a/vlib/x/crypto/chacha20/chacha_test.v +++ b/vlib/x/crypto/chacha20/chacha_test.v @@ -1,8 +1,27 @@ module chacha20 +import crypto.cipher import rand import encoding.hex +struct StreamCipher { +mut: + cipher &cipher.Stream +} + +// Verify chahca20.Cipher implements chiper.Stream correctly. +fn test_chacha20_stream_cipher() ! { + mut key := []u8{len: 32} + mut nonce := []u8{len: 12} + rand.read(mut key) + rand.read(mut nonce) + + mut c := new_cipher(key, nonce)! + s := StreamCipher{ + cipher: c + } +} + fn test_chacha20_cipher_reset() ! { mut key := []u8{len: 32} mut nonce := []u8{len: 12}