crypto.cipher: make Stream.xor_key_stream implementers require a mutable receiver (#21974)

This commit is contained in:
Coachonko 2024-08-01 15:04:09 +02:00 committed by GitHub
parent 485983ebd2
commit a4b8768146
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 125 additions and 37 deletions

View File

@ -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())
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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.
//

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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())
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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()

View File

@ -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}