use crate::{
AtomClass,
AtomType,
CaseInsensitiveCiphertext,
cipher::{
Cipher,
Decrypt,
Encrypt,
Key,
shift_byte,
shift_cipher::remove_non_ascii_letter_bytes,
},
CryptoError,
CryptographicAtom,
util::text_to_mono_case,
};
pub struct CaesarContext {
atom_class: AtomClass,
atom_type: AtomType,
is_uppercase: bool,
key: Option<Vec<u8>>,
}
impl CaesarContext {
pub fn new() -> CaesarContext {
CaesarContext {
atom_class: AtomClass::Cipher,
atom_type: AtomType::Caesar,
is_uppercase: true,
key: None,
}
}
}
impl CaseInsensitiveCiphertext for CaesarContext {
fn ciphertext_is_capitalized(&self) -> Option<bool> { Some(self.is_uppercase) }
fn set_ciphertext_capitalization(
&mut self,
capitalized: bool,
) {
if self.is_uppercase != capitalized {
self.is_uppercase = capitalized;
if let Some(key) = &self.key {
self.key = Some(text_to_mono_case(key, self.is_uppercase));
}
}
}
}
impl Cipher for CaesarContext {}
impl CryptographicAtom for CaesarContext {
fn get_atom_class(&self) -> AtomClass { self.atom_class }
fn get_atom_type(&self) -> AtomType { self.atom_type }
}
impl Decrypt for CaesarContext {
fn decrypt(
&mut self,
ciphertext: &Vec<u8>,
) -> Result<Vec<u8>, CryptoError> {
let original_key = if let Some(key) = &self.key {
key[0]
} else {
return Err(CryptoError::MissingKey("For Caesar cipher decryption!".to_string()));
};
let correction = if self.is_uppercase { 0x41 } else { 0x61 };
let decrypt_key = vec![
(26 - (original_key - correction)) + correction
];
self.key = Some(decrypt_key);
let plaintext = self.encrypt(ciphertext).unwrap();
self.key = Some(vec![original_key]);
Ok(plaintext)
}
}
impl Encrypt for CaesarContext {
fn encrypt(
&mut self,
plaintext: &Vec<u8>,
) -> Result<Vec<u8>, CryptoError> {
let cleaned_plaintext = remove_non_ascii_letter_bytes(plaintext);
let mono_cased_plaintext = text_to_mono_case(
&cleaned_plaintext, self.is_uppercase,
);
let mut ciphertext = Vec::new();
let key = if let Some(key) = &self.key {
key.get(0).unwrap().clone() - if self.is_uppercase { 0x41 } else { 0x61 }
} else {
return Err(CryptoError::MissingKey("For Caesar cipher encryption!".to_string()));
};
for mut m in mono_cased_plaintext {
m = m - if self.is_uppercase { 0x41 } else { 0x61 };
let c = shift_byte(
m,
key,
false,
26,
);
ciphertext.push(c + if self.is_uppercase { 0x41 } else { 0x61 });
}
Ok(ciphertext)
}
}
impl Key for CaesarContext {
fn get_key(
&self
) -> Option<&Vec<u8>> {
if let Some(key) = &self.key {
Some(key)
} else {
None
}
}
fn set_key(
&mut self,
key: &Vec<u8>,
) -> Result<(), CryptoError> {
let mut clean_key = remove_non_ascii_letter_bytes(key);
if clean_key.len() > 1 {
clean_key.truncate(1);
}
if clean_key.is_empty() {
return Err(CryptoError::InvalidKey(
"For Caesar cipher! Key is empty!".to_string(),
key.clone(),
));
}
if clean_key[0] == 0x41 || clean_key[0] == 0x61 {
return Err(CryptoError::InvalidKey(
"For Caesar cipher! Illegal character!".to_string(),
clean_key.clone(),
));
}
let mono_case_key = text_to_mono_case(
&clean_key, self.is_uppercase
);
self.key = Some(mono_case_key);
Ok(())
}
}
#[cfg(any(test, feature = "doc_tests"))]
mod tests {
use super::*;
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_01() {
let ctx = CaesarContext::new();
assert_eq![ctx.get_atom_type(), AtomType::Caesar];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_02() {
let ctx = CaesarContext::new();
assert_eq![ctx.ciphertext_is_capitalized(), Some(true)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_03() {
let mut ctx = CaesarContext::new();
ctx.set_ciphertext_capitalization(false);
assert_eq![ctx.ciphertext_is_capitalized(), Some(false)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_04() {
let mut ctx = CaesarContext::new();
ctx.set_ciphertext_capitalization(false);
ctx.set_ciphertext_capitalization(true);
assert_eq![ctx.ciphertext_is_capitalized(), Some(true)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_05() {
let mut ctx = CaesarContext::new();
ctx.set_ciphertext_capitalization(true);
assert_eq![ctx.ciphertext_is_capitalized(), Some(true)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_06() {
let ciphertext = vec![
0x46, 0x59, 0x59,
0x66, 0x68, 0x70,
0x46, 0x59, 0x49,
0x66, 0x62, 0x73,
];
let key = vec![0x46];
let expected_plaintext = vec![
0x41, 0x54, 0x54,
0x41, 0x43, 0x4b,
0x41, 0x54, 0x44,
0x41, 0x57, 0x4e,
];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key), Ok(())];
let plaintext = ctx.decrypt(&ciphertext);
assert_eq![plaintext, Ok(expected_plaintext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_07() {
let ciphertext = vec![
0x77, 0x6b, 0x68,
0x54, 0x58, 0x4c,
0x66, 0x6e, 0x65,
0x55, 0x52, 0x5a,
0x71, 0x69, 0x72,
0x41, 0x4d, 0x58,
0x70, 0x73, 0x76,
0x52, 0x59, 0x48,
0x75, 0x77, 0x6b,
0x48, 0x4f, 0x44,
0x63, 0x62, 0x67,
0x52, 0x4a,
];
let key = vec![0x64];
let expected_plaintext = vec![
0x74, 0x68, 0x65,
0x71, 0x75, 0x69,
0x63, 0x6b, 0x62,
0x72, 0x6f, 0x77,
0x6e, 0x66, 0x6f,
0x78, 0x6a, 0x75,
0x6d, 0x70, 0x73,
0x6f, 0x76, 0x65,
0x72, 0x74, 0x68,
0x65, 0x6c, 0x61,
0x7a, 0x79, 0x64,
0x6f, 0x67,
];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key), Ok(())];
ctx.set_ciphertext_capitalization(false);
let plaintext = ctx.decrypt(&ciphertext);
assert_eq![plaintext, Ok(expected_plaintext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_08() {
let ciphertext = vec![
0x63, 0x6c, 0x4c,
0x79, 0x58, 0x4f,
];
let key = vec![0x58];
let expected_plaintext = vec![
0x46, 0x4f, 0x4f,
0x42, 0x41, 0x52,
];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key), Ok(())];
let plaintext = ctx.decrypt(&ciphertext);
assert_eq![plaintext, Ok(expected_plaintext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_09() {
let ciphertext = vec![];
let mut ctx = CaesarContext::new();
assert_eq![ctx.decrypt(&ciphertext),
Err(CryptoError::MissingKey("For Caesar cipher decryption!".to_string()))];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_10() {
let ciphertext = vec![];
let key = vec![0x62];
let expected_key = vec![0x42];
let expected_plaintext = vec![];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key), Ok(())];
assert_eq![ctx.key, Some(expected_key.clone())];
assert_eq![ctx.decrypt(&ciphertext), Ok(expected_plaintext)];
assert_eq![ctx.get_key(), Some(&expected_key)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_11() {
let plaintext = vec![
0x61, 0x74, 0x74,
0x61, 0x63, 0x6b,
0x61, 0x74, 0x64,
0x61, 0x77, 0x6e,
];
let key = vec![0x46];
let expected_ciphertext = vec![
0x66, 0x79, 0x79,
0x66, 0x68, 0x70,
0x66, 0x79, 0x69,
0x66, 0x62, 0x73,
];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key), Ok(())];
ctx.set_ciphertext_capitalization(false);
let ciphertext = ctx.encrypt(&plaintext);
assert_eq![ciphertext, Ok(expected_ciphertext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_12() {
let plaintext = vec![
0x74, 0x68, 0x65,
0x71, 0x75, 0x69,
0x63, 0x6b, 0x62,
0x72, 0x6f, 0x77,
0x6e, 0x66, 0x6f,
0x78, 0x6a, 0x75,
0x6d, 0x70, 0x73,
0x6f, 0x76, 0x65,
0x72, 0x74, 0x68,
0x65, 0x6c, 0x61,
0x7a, 0x79, 0x64,
0x6f, 0x67,
];
let key = vec![0x44];
let expected_ciphertext = vec![
0x57, 0x4b, 0x48,
0x54, 0x58, 0x4c,
0x46, 0x4e, 0x45,
0x55, 0x52, 0x5a,
0x51, 0x49, 0x52,
0x41, 0x4d, 0x58,
0x50, 0x53, 0x56,
0x52, 0x59, 0x48,
0x55, 0x57, 0x4b,
0x48, 0x4f, 0x44,
0x43, 0x42, 0x47,
0x52, 0x4a,
];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key), Ok(())];
let ciphertext = ctx.encrypt(&plaintext);
assert_eq![ciphertext, Ok(expected_ciphertext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_13() {
let plaintext = vec![
0x66, 0x6f, 0x6f,
0x62, 0x61, 0x72,
];
let key = vec![0x58];
let expected_ciphertext = vec![
0x63, 0x6c, 0x6c,
0x79, 0x78, 0x6f,
];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key), Ok(())];
ctx.set_ciphertext_capitalization(false);
let ciphertext = ctx.encrypt(&plaintext);
assert_eq![ciphertext, Ok(expected_ciphertext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_14() {
let plaintext = vec![];
let mut ctx = CaesarContext::new();
assert_eq![ctx.encrypt(&plaintext),
Err(CryptoError::MissingKey("For Caesar cipher encryption!".to_string()))];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_15() {
let ctx = CaesarContext::new();
assert_eq![ctx.get_key(), None];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_16() {
let key = vec![
0x46
];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key), Ok(())];
assert_eq![ctx.get_key(), Some(&key)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_17() {
let key = vec![
0x46, 0x41, 0x41, 0x41,
];
let expected_key = vec![
0x46
];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key), Ok(())];
assert_eq![ctx.get_key(), Some(&expected_key)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_18() {
let key = vec![];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key), Err(CryptoError::InvalidKey(
"For Caesar cipher! Key is empty!".to_string(),
key,
))];
assert_eq![ctx.get_key(), None];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_19() {
let key = vec![
0x40, 0x00, 0xff, 0xcc,
];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key), Err(CryptoError::InvalidKey(
"For Caesar cipher! Key is empty!".to_string(),
key,
))];
assert_eq![ctx.get_key(), None];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_20() {
let key_uppercase_a = vec![0x41];
let key_lowercase_a = vec![0x61];
let mut ctx = CaesarContext::new();
assert_eq![ctx.set_key(&key_uppercase_a), Err(CryptoError::InvalidKey(
"For Caesar cipher! Illegal character!".to_string(),
key_uppercase_a,
))];
assert_eq![ctx.get_key(), None];
assert_eq![ctx.set_key(&key_lowercase_a), Err(CryptoError::InvalidKey(
"For Caesar cipher! Illegal character!".to_string(),
key_lowercase_a,
))];
assert_eq![ctx.get_key(), None];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_21() {
let key_lowercase = vec![0x62];
let key_uppercase = vec![0x42];
let mut ctx = CaesarContext::new();
ctx.set_ciphertext_capitalization(true);
assert_eq![ctx.set_key(&key_lowercase), Ok(())];
assert_eq![ctx.get_key(), Some(&key_uppercase)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_22() {
let key_uppercase = vec![0x42];
let key_lowercase = vec![0x62];
let mut ctx = CaesarContext::new();
ctx.set_ciphertext_capitalization(false);
assert_eq![ctx.set_key(&key_uppercase), Ok(())];
assert_eq![ctx.get_key(), Some(&key_lowercase)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_23() {
let ctx = CaesarContext::new();
assert_eq![ctx.get_atom_class(), AtomClass::Cipher];
}
}