Skip to content

Commit

Permalink
Merge branch 'feat/zippy-rc4' into 'master'
Browse files Browse the repository at this point in the history
RC4 implementation and support for RC encryption in Cippy

See merge request joamag/boytacean!57
  • Loading branch information
joamag committed Aug 8, 2024
2 parents 20e1d46 + 60d0d7c commit 01610ae
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 38 deletions.
4 changes: 2 additions & 2 deletions benches/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn benchmark_encoding(c: &mut Criterion) {

group.bench_function("encode_zippy", |b| {
b.iter(|| {
let encoded = encode_zippy(black_box(&data), None).unwrap();
let encoded = encode_zippy(black_box(&data), None, None).unwrap();
black_box(encoded);
})
});
Expand All @@ -40,7 +40,7 @@ fn benchmark_decoding(c: &mut Criterion) {
let data = generate_data(10_000_000_usize);
let encoded_huffman = encode_huffman(black_box(&data)).unwrap();
let encoded_rle = encode_rle(black_box(&data));
let encoded_zippy = encode_zippy(black_box(&data), None).unwrap();
let encoded_zippy = encode_zippy(black_box(&data), None, None).unwrap();

let mut group = c.benchmark_group("decoding");
group.throughput(Throughput::Bytes(data.len() as u64));
Expand Down
10 changes: 8 additions & 2 deletions crates/common/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ use std::{
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
InvalidData,
InvalidKey,
RomSize,
IncompatibleBootRom,
MissingOption(String),
IoError(String),
InvalidParameter(String),
CustomError(String),
}
Expand All @@ -28,8 +31,11 @@ impl Error {
pub fn description(&self) -> String {
match self {
Error::InvalidData => String::from("Invalid data format"),
Error::InvalidKey => String::from("Invalid key"),
Error::RomSize => String::from("Invalid ROM size"),
Error::IncompatibleBootRom => String::from("Incompatible Boot ROM"),
Error::MissingOption(option) => format!("Missing option: {}", option),
Error::IoError(message) => format!("IO error: {}", message),
Error::InvalidParameter(message) => format!("Invalid parameter: {}", message),
Error::CustomError(message) => String::from(message),
}
Expand All @@ -43,8 +49,8 @@ impl Display for Error {
}

impl From<io::Error> for Error {
fn from(_error: io::Error) -> Self {
Error::CustomError(String::from("IO error"))
fn from(error: io::Error) -> Self {
Error::IoError(error.to_string())
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/encoding/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod huffman;
pub mod rc4;
pub mod rle;
pub mod zippy;
122 changes: 122 additions & 0 deletions crates/encoding/src/rc4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
pub struct Rc4 {
s: [u8; 256],
i: u8,
j: u8,
}

impl Rc4 {
pub fn new(key: &[u8]) -> Self {
let mut s: [u8; 256] = [0; 256];
for (i, v) in s.iter_mut().enumerate() {
*v = i as u8;
}

let key_len = key.len();
if key_len > 0 {
let mut j = 0;
for i in 0..256 {
j = (j + s[i] as usize + key[i % key_len] as usize) % 256;
s.swap(i, j);
}
}

Rc4 { s, i: 0, j: 0 }
}

pub fn process(&mut self, data: &mut [u8]) {
for byte in data.iter_mut() {
self.i = self.i.wrapping_add(1);
self.j = self.j.wrapping_add(self.s[self.i as usize]);
self.s.swap(self.i as usize, self.j as usize);
let k =
self.s[(self.s[self.i as usize].wrapping_add(self.s[self.j as usize])) as usize];
*byte ^= k;
}
}
}

pub fn rc4_encrypt(key: &[u8], data: &mut [u8]) {
let mut rc4 = Rc4::new(key);
rc4.process(data);
}

pub fn rc4_decrypt(key: &[u8], data: &mut [u8]) {
rc4_encrypt(key, data)
}

#[cfg(test)]
mod tests {
use super::Rc4;

#[test]
fn test_rc4_initialization() {
let key = b"key";
let rc4 = Rc4::new(key);
assert_eq!(rc4.s.len(), 256);
}

#[test]
fn test_rc4_encryption_decryption() {
let key = b"supersecretkey";
let plaintext = b"hello world";
let mut data = plaintext.to_vec();

let mut rc4 = Rc4::new(key);
rc4.process(&mut data);
assert_ne!(&data, plaintext);

let mut rc4 = Rc4::new(key);
rc4.process(&mut data);
assert_eq!(&data, plaintext);
}

#[test]
fn test_rc4_empty_key() {
let key = b"";
let mut data = b"hello world".to_vec();

let mut rc4 = Rc4::new(key);
rc4.process(&mut data);

let mut rc4 = Rc4::new(key);
rc4.process(&mut data);
assert_eq!(data, b"hello world");
}

#[test]
fn test_rc4_empty_data() {
let key = b"supersecretkey";
let mut data: Vec<u8> = vec![];

let mut rc4 = Rc4::new(key);
rc4.process(&mut data);

let mut rc4 = Rc4::new(key);
rc4.process(&mut data);
assert!(data.is_empty());
}

#[test]
fn test_rc4_with_different_keys() {
let key1 = b"key1";
let key2 = b"key2";
let plaintext = b"hello world";
let mut data1 = plaintext.to_vec();
let mut data2 = plaintext.to_vec();

let mut rc4 = Rc4::new(key1);
rc4.process(&mut data1);

let mut rc4 = Rc4::new(key2);
rc4.process(&mut data2);
assert_ne!(data1, data2);

let mut rc4 = Rc4::new(key1);
rc4.process(&mut data1);

let mut rc4 = Rc4::new(key2);
rc4.process(&mut data2);
assert_eq!(data1, plaintext);
assert_eq!(data2, plaintext);
}
}
Loading

0 comments on commit 01610ae

Please sign in to comment.