Skip to content

Commit 7cea702

Browse files
committed
cipher: add dummy stream cipher tests
1 parent 06e4e1a commit 7cea702

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed

cipher/tests/stream.rs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
use cipher::{
2+
BlockSizeUser, IvSizeUser, KeyIvInit, KeySizeUser, ParBlocksSizeUser, StreamCipher,
3+
StreamCipherBackend, StreamCipherClosure, StreamCipherCore, StreamCipherCoreWrapper,
4+
StreamCipherSeek, StreamCipherSeekCore,
5+
consts::{U1, U4, U16},
6+
};
7+
8+
const KEY: [u8; 4] = [0, 1, 2, 3];
9+
const IV: [u8; 4] = [4, 5, 6, 7];
10+
11+
/// Dummy insecure stream cipher.
12+
pub struct DummyStreamCipherCore {
13+
key_iv: u64,
14+
pos: u64,
15+
}
16+
17+
impl KeySizeUser for DummyStreamCipherCore {
18+
type KeySize = U4;
19+
}
20+
21+
impl IvSizeUser for DummyStreamCipherCore {
22+
type IvSize = U4;
23+
}
24+
25+
impl KeyIvInit for DummyStreamCipherCore {
26+
fn new(key: &cipher::Key<Self>, iv: &cipher::Iv<Self>) -> Self {
27+
let mut buf = [0u8; 8];
28+
buf[..4].copy_from_slice(key);
29+
buf[4..].copy_from_slice(iv);
30+
let pos = u64::from_le_bytes(buf);
31+
Self {
32+
key_iv: pos,
33+
pos: 0,
34+
}
35+
}
36+
}
37+
38+
impl BlockSizeUser for DummyStreamCipherCore {
39+
type BlockSize = U16;
40+
}
41+
42+
impl StreamCipherCore for DummyStreamCipherCore {
43+
fn remaining_blocks(&self) -> Option<usize> {
44+
let rem = u64::MAX - self.pos;
45+
usize::try_from(rem).ok()
46+
}
47+
48+
fn process_with_backend(&mut self, f: impl StreamCipherClosure<BlockSize = U16>) {
49+
f.call(self);
50+
}
51+
}
52+
53+
impl ParBlocksSizeUser for DummyStreamCipherCore {
54+
type ParBlocksSize = U1;
55+
}
56+
57+
impl StreamCipherBackend for DummyStreamCipherCore {
58+
fn gen_ks_block(&mut self, block: &mut cipher::Block<Self>) {
59+
const C1: u64 = 0x87c3_7b91_1142_53d5;
60+
const C2: u64 = 0x4cf5_ad43_2745_937f;
61+
62+
let a = self.key_iv ^ C1;
63+
let b = self.pos ^ C2;
64+
let a = a.rotate_left(13).wrapping_mul(b);
65+
let b = b.rotate_left(13).wrapping_mul(a);
66+
67+
block[..8].copy_from_slice(&a.to_le_bytes());
68+
block[8..].copy_from_slice(&b.to_le_bytes());
69+
self.pos = self.pos.wrapping_add(1);
70+
}
71+
}
72+
73+
impl StreamCipherSeekCore for DummyStreamCipherCore {
74+
type Counter = u64;
75+
76+
fn get_block_pos(&self) -> Self::Counter {
77+
self.pos
78+
}
79+
80+
fn set_block_pos(&mut self, pos: Self::Counter) {
81+
self.pos = pos;
82+
}
83+
}
84+
85+
#[cfg(feature = "stream-wrapper")]
86+
pub type DummyStreamCipher = StreamCipherCoreWrapper<DummyStreamCipherCore>;
87+
88+
#[test]
89+
#[cfg(feature = "stream-wrapper")]
90+
fn dummy_stream_cipher() {
91+
let mut cipher = DummyStreamCipher::new(&KEY.into(), &IV.into());
92+
93+
assert_eq!(cipher.current_pos::<u64>(), 0);
94+
95+
let mut buf = [0u8; 20];
96+
97+
cipher.apply_keystream(&mut buf);
98+
assert_eq!(cipher.current_pos::<usize>(), buf.len());
99+
100+
let expected = [
101+
232, 35, 147, 84, 60, 201, 96, 137, 48, 81, 22, 0, 58, 65, 122, 204, 208, 115, 56, 74,
102+
];
103+
assert_eq!(buf, expected);
104+
105+
const SEEK_POS: usize = 500;
106+
107+
cipher.seek(SEEK_POS);
108+
cipher.apply_keystream(&mut buf);
109+
assert_eq!(cipher.current_pos::<usize>(), SEEK_POS + buf.len());
110+
111+
let expected = [
112+
107, 1, 76, 106, 60, 55, 107, 19, 196, 114, 5, 144, 210, 97, 71, 197, 235, 243, 52, 197,
113+
];
114+
assert_eq!(buf, expected);
115+
}
116+
117+
#[test]
118+
#[cfg(feature = "stream-wrapper")]
119+
fn dummy_stream_cipher_seek_limit() {
120+
let mut cipher = DummyStreamCipher::new(&KEY.into(), &IV.into());
121+
122+
let pos = ((u64::MAX as u128) << 4) - 20;
123+
cipher.try_seek(pos).unwrap();
124+
125+
let mut buf = [0u8; 30];
126+
let res = cipher.try_apply_keystream(&mut buf);
127+
assert!(res.is_err());
128+
let cur_pos: u128 = cipher.current_pos();
129+
assert_eq!(cur_pos, pos);
130+
131+
let res = cipher.try_apply_keystream(&mut buf[..19]);
132+
assert!(res.is_ok());
133+
let cur_pos: u128 = cipher.current_pos();
134+
assert_eq!(cur_pos, pos + 19);
135+
136+
cipher.try_seek(pos).unwrap();
137+
138+
// TODO: fix as part of https://github.com/RustCrypto/traits/issues/1808
139+
// let res = cipher.try_apply_keystream(&mut buf[..20]);
140+
// assert!(res.is_err());
141+
}
142+
143+
#[cfg(all(feature = "dev", feature = "stream-wrapper"))]
144+
cipher::stream_cipher_seek_test!(dummy_stream_cipher_seek, DummyStreamCipher);

0 commit comments

Comments
 (0)