use crate::error_chirho::ResultChirho;
use super::CipherChirho;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum CipherTypeChirho {
#[default]
NoneChirho,
SapphireChirho,
XorChirho,
}
impl CipherTypeChirho {
pub fn from_str_chirho(s_chirho: &str) -> Self {
match s_chirho.to_lowercase().as_str() {
"sapphire" | "sapphire2" => Self::SapphireChirho,
"xor" => Self::XorChirho,
_ => Self::NoneChirho,
}
}
}
#[derive(Debug, Clone)]
pub struct SwCipherChirho {
cipher_type_chirho: CipherTypeChirho,
key_chirho: String,
}
impl SwCipherChirho {
pub fn new_chirho(cipher_type_chirho: CipherTypeChirho, key_chirho: &str) -> Self {
Self {
cipher_type_chirho,
key_chirho: key_chirho.to_string(),
}
}
pub fn cipher_type_chirho(&self) -> CipherTypeChirho {
self.cipher_type_chirho
}
pub fn set_key_chirho(&mut self, key_chirho: &str) {
self.key_chirho = key_chirho.to_string();
}
pub fn key_chirho(&self) -> &str {
&self.key_chirho
}
}
#[derive(Debug, Clone)]
pub struct SapphireCipherChirho {
key_chirho: String,
}
impl SapphireCipherChirho {
pub fn new_chirho(key_chirho: &str) -> Self {
Self {
key_chirho: key_chirho.to_string(),
}
}
fn init_state_chirho(&self) -> SapphireStateChirho {
SapphireStateChirho::new_chirho(&self.key_chirho)
}
}
impl CipherChirho for SapphireCipherChirho {
fn encrypt_chirho(&self, data_chirho: &[u8]) -> ResultChirho<Vec<u8>> {
if self.key_chirho.is_empty() {
return Ok(data_chirho.to_vec());
}
let mut state_chirho = self.init_state_chirho();
let mut result_chirho = Vec::with_capacity(data_chirho.len());
for &byte_chirho in data_chirho {
result_chirho.push(byte_chirho ^ state_chirho.next_chirho());
}
Ok(result_chirho)
}
fn decrypt_chirho(&self, data_chirho: &[u8]) -> ResultChirho<Vec<u8>> {
self.encrypt_chirho(data_chirho)
}
fn name_chirho(&self) -> &str {
"Sapphire"
}
fn has_key_chirho(&self) -> bool {
!self.key_chirho.is_empty()
}
}
#[derive(Debug, Clone)]
struct SapphireStateChirho {
cards_chirho: [u8; 256],
rotor_chirho: u8,
ratchet_chirho: u8,
avalanche_chirho: u8,
last_plain_chirho: u8,
last_cipher_chirho: u8,
}
impl SapphireStateChirho {
fn new_chirho(key_chirho: &str) -> Self {
let mut state_chirho = Self {
cards_chirho: [0; 256],
rotor_chirho: 1,
ratchet_chirho: 3,
avalanche_chirho: 5,
last_plain_chirho: 7,
last_cipher_chirho: 11,
};
for i_chirho in 0..256 {
state_chirho.cards_chirho[i_chirho] = i_chirho as u8;
}
if !key_chirho.is_empty() {
let key_bytes_chirho = key_chirho.as_bytes();
let key_len_chirho = key_bytes_chirho.len();
for i_chirho in 0..256 {
let key_byte_chirho = key_bytes_chirho[i_chirho % key_len_chirho];
let swap_idx_chirho = ((key_byte_chirho as usize) + i_chirho) % 256;
state_chirho.cards_chirho.swap(i_chirho, swap_idx_chirho);
}
for _ in 0..256 {
state_chirho.next_chirho();
}
}
state_chirho
}
fn next_chirho(&mut self) -> u8 {
self.rotor_chirho = self.rotor_chirho.wrapping_add(1);
self.ratchet_chirho = self.ratchet_chirho.wrapping_add(
self.cards_chirho[self.rotor_chirho as usize]
);
self.cards_chirho.swap(
self.rotor_chirho as usize,
self.ratchet_chirho as usize
);
self.avalanche_chirho = self.avalanche_chirho.wrapping_add(
self.cards_chirho[self.ratchet_chirho as usize]
);
self.last_plain_chirho = self.cards_chirho[
self.avalanche_chirho.wrapping_add(
self.cards_chirho[
self.rotor_chirho.wrapping_add(
self.cards_chirho[self.last_plain_chirho as usize]
) as usize
]
) as usize
];
self.last_cipher_chirho = self.cards_chirho[
self.last_cipher_chirho.wrapping_add(
self.cards_chirho[
self.ratchet_chirho.wrapping_add(
self.cards_chirho[self.last_plain_chirho as usize]
) as usize
]
) as usize
];
self.last_cipher_chirho
}
}
#[derive(Debug, Clone)]
pub struct XorCipherChirho {
key_chirho: String,
}
impl XorCipherChirho {
pub fn new_chirho(key_chirho: &str) -> Self {
Self {
key_chirho: key_chirho.to_string(),
}
}
}
impl CipherChirho for XorCipherChirho {
fn encrypt_chirho(&self, data_chirho: &[u8]) -> ResultChirho<Vec<u8>> {
if self.key_chirho.is_empty() {
return Ok(data_chirho.to_vec());
}
let key_bytes_chirho = self.key_chirho.as_bytes();
let key_len_chirho = key_bytes_chirho.len();
let mut result_chirho = Vec::with_capacity(data_chirho.len());
for (i_chirho, &byte_chirho) in data_chirho.iter().enumerate() {
result_chirho.push(byte_chirho ^ key_bytes_chirho[i_chirho % key_len_chirho]);
}
Ok(result_chirho)
}
fn decrypt_chirho(&self, data_chirho: &[u8]) -> ResultChirho<Vec<u8>> {
self.encrypt_chirho(data_chirho)
}
fn name_chirho(&self) -> &str {
"XOR"
}
fn has_key_chirho(&self) -> bool {
!self.key_chirho.is_empty()
}
}
#[cfg(test)]
mod tests_chirho {
use super::*;
#[test]
fn test_sapphire_roundtrip_chirho() {
let cipher_chirho = SapphireCipherChirho::new_chirho("test_key");
let plaintext_chirho = b"In the beginning God created the heaven and the earth.";
let encrypted_chirho = cipher_chirho.encrypt_chirho(plaintext_chirho).unwrap();
assert_ne!(encrypted_chirho, plaintext_chirho);
let decrypted_chirho = cipher_chirho.decrypt_chirho(&encrypted_chirho).unwrap();
assert_eq!(decrypted_chirho, plaintext_chirho);
}
#[test]
fn test_sapphire_empty_key_chirho() {
let cipher_chirho = SapphireCipherChirho::new_chirho("");
let plaintext_chirho = b"Test data";
let encrypted_chirho = cipher_chirho.encrypt_chirho(plaintext_chirho).unwrap();
assert_eq!(encrypted_chirho, plaintext_chirho);
}
#[test]
fn test_sapphire_different_keys_chirho() {
let cipher1_chirho = SapphireCipherChirho::new_chirho("key1");
let cipher2_chirho = SapphireCipherChirho::new_chirho("key2");
let plaintext_chirho = b"Test data";
let encrypted1_chirho = cipher1_chirho.encrypt_chirho(plaintext_chirho).unwrap();
let encrypted2_chirho = cipher2_chirho.encrypt_chirho(plaintext_chirho).unwrap();
assert_ne!(encrypted1_chirho, encrypted2_chirho);
}
#[test]
fn test_xor_roundtrip_chirho() {
let cipher_chirho = XorCipherChirho::new_chirho("test_key");
let plaintext_chirho = b"In the beginning God created the heaven and the earth.";
let encrypted_chirho = cipher_chirho.encrypt_chirho(plaintext_chirho).unwrap();
assert_ne!(encrypted_chirho, plaintext_chirho);
let decrypted_chirho = cipher_chirho.decrypt_chirho(&encrypted_chirho).unwrap();
assert_eq!(decrypted_chirho, plaintext_chirho);
}
#[test]
fn test_xor_empty_key_chirho() {
let cipher_chirho = XorCipherChirho::new_chirho("");
let plaintext_chirho = b"Test data";
let encrypted_chirho = cipher_chirho.encrypt_chirho(plaintext_chirho).unwrap();
assert_eq!(encrypted_chirho, plaintext_chirho);
}
#[test]
fn test_cipher_type_from_str_chirho() {
assert_eq!(CipherTypeChirho::from_str_chirho("sapphire"), CipherTypeChirho::SapphireChirho);
assert_eq!(CipherTypeChirho::from_str_chirho("SAPPHIRE"), CipherTypeChirho::SapphireChirho);
assert_eq!(CipherTypeChirho::from_str_chirho("sapphire2"), CipherTypeChirho::SapphireChirho);
assert_eq!(CipherTypeChirho::from_str_chirho("xor"), CipherTypeChirho::XorChirho);
assert_eq!(CipherTypeChirho::from_str_chirho("unknown"), CipherTypeChirho::NoneChirho);
}
#[test]
fn test_sw_cipher_chirho() {
let mut cipher_chirho = SwCipherChirho::new_chirho(CipherTypeChirho::SapphireChirho, "key1");
assert_eq!(cipher_chirho.cipher_type_chirho(), CipherTypeChirho::SapphireChirho);
assert_eq!(cipher_chirho.key_chirho(), "key1");
cipher_chirho.set_key_chirho("key2");
assert_eq!(cipher_chirho.key_chirho(), "key2");
}
#[test]
fn test_sapphire_long_data_chirho() {
let cipher_chirho = SapphireCipherChirho::new_chirho("long_key_for_testing");
let plaintext_chirho: Vec<u8> = (0..1000).map(|i| (i % 256) as u8).collect();
let encrypted_chirho = cipher_chirho.encrypt_chirho(&plaintext_chirho).unwrap();
assert_eq!(encrypted_chirho.len(), plaintext_chirho.len());
assert_ne!(encrypted_chirho, plaintext_chirho);
let decrypted_chirho = cipher_chirho.decrypt_chirho(&encrypted_chirho).unwrap();
assert_eq!(decrypted_chirho, plaintext_chirho);
}
#[test]
fn test_has_key_chirho() {
let cipher_with_key_chirho = SapphireCipherChirho::new_chirho("key");
let cipher_no_key_chirho = SapphireCipherChirho::new_chirho("");
assert!(cipher_with_key_chirho.has_key_chirho());
assert!(!cipher_no_key_chirho.has_key_chirho());
}
}