-
Notifications
You must be signed in to change notification settings - Fork 3
/
rc4.rs
81 lines (74 loc) · 2.18 KB
/
rc4.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Implementation of the stream cipher RC4
// Based on https://github.com/DaGenix/rust-crypto/blob/master/src/rc4.rs
#[derive(Clone, Copy)]
pub struct Rc4 {
i: u8,
j: u8,
state: [u8; 256],
}
impl Rc4 {
#[allow(clippy::needless_range_loop)]
pub fn new(key: &[u8]) -> Self {
assert!(!key.is_empty() && key.len() <= 256);
let mut state = [0; 256];
for i in 0..256 {
state[i] = i as u8
}
let mut j: u8 = 0;
for i in 0..256 {
j = j.wrapping_add(state[i]).wrapping_add(key[i % key.len()]);
state.swap(i, j as usize);
}
Self { i: 0, j: 0, state }
}
pub fn crypt(&mut self, buf: &mut [u8]) {
for i in buf.iter_mut() {
self.i = self.i.wrapping_add(1);
self.j = self.j.wrapping_add(self.state[self.i as usize]);
self.state.swap(self.i as usize, self.j as usize);
let j = self.state[self.i as usize].wrapping_add(self.state[self.j as usize]);
*i ^= self.state[j as usize];
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::std_alloc::Vec;
struct Test {
key: &'static str,
input: &'static str,
output: Vec<u8>,
}
#[rustfmt::skip]
fn wikipedia_tests() -> Vec<Test> {
vec![
Test {
key: "Key",
input: "Plaintext",
output: vec![0xbb, 0xf3, 0x16, 0xe8, 0xd9, 0x40, 0xaf, 0x0a, 0xd3],
},
Test {
key: "Wiki",
input: "pedia",
output: vec![0x10, 0x21, 0xbf, 0x04, 0x20],
},
Test {
key: "Secret",
input: "Attack at dawn",
output: vec![0x45, 0xa0, 0x1f, 0x64, 0x5f, 0xc3, 0x5b,
0x38, 0x35, 0x52, 0x54, 0x4b, 0x9b, 0xf5,
],
},
]
}
#[test]
fn test_crypt() {
for t in wikipedia_tests().iter() {
let mut rc4 = Rc4::new(t.key.as_bytes());
let mut buf = t.input.as_bytes().to_vec();
rc4.crypt(&mut buf);
assert_eq!(t.output, buf);
}
}
}