use crate::{
AtomClass,
AtomType,
CaseInsensitiveCiphertext,
cipher::{
self,
Cipher,
Decrypt,
Encrypt,
Key,
shift_cipher::remove_non_ascii_letter_bytes,
},
CryptoError,
CryptographicAtom,
util::text_to_mono_case,
};
pub struct VigenereContext {
atom_class: AtomClass,
atom_type: AtomType,
key: Option<Vec<u8>>,
is_capitalized: bool,
}
impl VigenereContext {
fn calculate(
text: &Vec<u8>,
key: &Vec<u8>,
is_capitalized: bool,
encode: bool,
) -> Vec<u8> {
let mut result_text = Vec::new();
let mut key_index = 0;
for l in text {
let k = key[key_index];
let c = cipher::shift_byte(
if is_capitalized {
*l - 0x41
} else {
*l - 0x61
},
if is_capitalized {
k - 0x41
} else {
k - 0x61
},
!encode,
26,
);
result_text.push(
if is_capitalized {
c + 0x41
} else {
c + 0x61
}
);
key_index = (key_index + 1) % key.len();
}
result_text
}
pub fn new() -> VigenereContext {
VigenereContext {
atom_class: AtomClass::Cipher,
atom_type: AtomType::Vigenere,
key: None,
is_capitalized: true,
}
}
}
impl CaseInsensitiveCiphertext for VigenereContext {
fn ciphertext_is_capitalized(&self) -> Option<bool> { Some(self.is_capitalized) }
fn set_ciphertext_capitalization(
&mut self,
capitalized: bool,
) {
if self.is_capitalized != capitalized {
self.is_capitalized = capitalized;
if let Some(key) = &self.key {
self.key = Some(text_to_mono_case(
key, self.is_capitalized,
));
}
}
}
}
impl Cipher for VigenereContext {}
impl CryptographicAtom for VigenereContext {
fn get_atom_class(&self) -> AtomClass { self.atom_class }
fn get_atom_type(&self) -> AtomType { self.atom_type }
}
impl Decrypt for VigenereContext {
fn decrypt(
&mut self,
ciphertext: &Vec<u8>,
) -> Result<Vec<u8>, CryptoError> {
if self.key.is_none() {
return Err(CryptoError::MissingKey("Missing key for Vigenère decryption!".to_string()));
}
let clean_ciphertext = remove_non_ascii_letter_bytes(ciphertext);
let mono_case_ciphertext = text_to_mono_case(
&clean_ciphertext, self.is_capitalized,
);
Ok(VigenereContext::calculate(
&mono_case_ciphertext, self.key.as_ref().unwrap(), self.is_capitalized,
false,
))
}
}
impl Encrypt for VigenereContext {
fn encrypt(
&mut self,
plaintext: &Vec<u8>,
) -> Result<Vec<u8>, CryptoError> {
if self.key.is_none() {
return Err(CryptoError::MissingKey("Missing key for Vigenère encryption!".to_string()));
}
let clean_plaintext = remove_non_ascii_letter_bytes(plaintext);
let mono_case_plaintext = text_to_mono_case(
&clean_plaintext, self.is_capitalized,
);
Ok(VigenereContext::calculate(
&mono_case_plaintext, self.key.as_ref().unwrap(), self.is_capitalized, true,
))
}
}
impl Key for VigenereContext {
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 clean_key = remove_non_ascii_letter_bytes(&key);
if clean_key.is_empty() {
Err(CryptoError::InvalidKey(
"For Vigenère cipher! Key is empty!".to_string(),
key.clone(),
))
} else {
let mono_case_key = text_to_mono_case(
&clean_key, self.is_capitalized,
);
self.key = Some(mono_case_key);
Ok(())
}
}
}
#[cfg(any(feature = "doc_tests", test))]
mod tests {
use super::*;
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_00() {
let plaintext = vec![
0x54, 0x68, 0x69, 0x73, 0x20,
0x69, 0x73, 0x20,
0x61, 0x20,
0x66, 0x75, 0x6c, 0x6c, 0x20,
0x74, 0x65, 0x73, 0x74, 0x20,
0x6f, 0x66, 0x20,
0x74, 0x68, 0x65, 0x20,
0x56, 0x69, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x65, 0x20,
0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e,
];
let key = vec![
0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x78,
];
let expected_key = vec![
0x45, 0x4e, 0x43, 0x4f, 0x44, 0x45, 0x58,
];
let expected_ciphertext = vec![
0x58, 0x55, 0x4b,
0x47, 0x4c, 0x57,
0x58, 0x4a, 0x48,
0x4e, 0x5a, 0x57,
0x49, 0x50, 0x58,
0x42, 0x48, 0x48,
0x4b, 0x49, 0x53,
0x4d, 0x54, 0x47,
0x42, 0x48, 0x56,
0x42, 0x47, 0x42,
0x50, 0x48, 0x48,
0x42, 0x51,
];
let expected_plaintext = vec![
0x74, 0x68, 0x69, 0x73,
0x69, 0x73,
0x61,
0x66, 0x75, 0x6c, 0x6c,
0x74, 0x65, 0x73, 0x74,
0x6f, 0x66,
0x74, 0x68, 0x65,
0x76, 0x69, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x65,
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
];
let mut ctx = VigenereContext::new();
assert_eq![ctx.get_key(), None];
assert_eq![ctx.ciphertext_is_capitalized(), Some(true)];
ctx.set_ciphertext_capitalization(false);
assert_eq![ctx.ciphertext_is_capitalized(), Some(false)];
ctx.set_ciphertext_capitalization(true);
assert_eq![ctx.ciphertext_is_capitalized(), Some(true)];
assert_eq![ctx.set_key(&key), Ok(())];
assert_eq![ctx.get_key(), Some(&expected_key)];
let ciphertext = ctx.encrypt(&plaintext);
assert_eq![ciphertext, Ok(expected_ciphertext.clone())];
ctx.set_ciphertext_capitalization(false);
assert_eq![ctx.ciphertext_is_capitalized(), Some(false)];
let plaintext = ctx.decrypt(&expected_ciphertext);
assert_eq![plaintext, Ok(expected_plaintext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_01() {
let ctx = VigenereContext::new();
assert_eq![ctx.get_atom_type(), AtomType::Vigenere];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_02() {
let ctx = VigenereContext::new();
assert_eq![ctx.ciphertext_is_capitalized(), Some(true)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_03() {
let mut ctx = VigenereContext::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 = VigenereContext::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 ciphertext = vec![
0x4c, 0x58, 0x46, 0x4f, 0x50, 0x56, 0x45, 0x46, 0x52, 0x4e, 0x48, 0x52,
];
let key = vec![0x4c, 0x45, 0x4d, 0x4f, 0x4e];
let expected_plaintext = vec![
0x41, 0x54, 0x54, 0x41, 0x43, 0x4b, 0x41, 0x54, 0x44, 0x41, 0x57, 0x4e,
];
let mut ctx = VigenereContext::new();
ctx.key = Some(key);
let plaintext = ctx.decrypt(&ciphertext);
assert_eq![plaintext, Ok(expected_plaintext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_06() {
let ciphertext = vec![
0x43, 0x53, 0x41, 0x53, 0x54, 0x50, 0x4b, 0x56, 0x53, 0x49, 0x51, 0x55, 0x54, 0x47,
0x51, 0x55, 0x43, 0x53, 0x41, 0x53, 0x54, 0x50, 0x49, 0x55, 0x41, 0x51, 0x4a, 0x42,
];
let key = vec![0x41, 0x42, 0x43, 0x44];
let expected_plaintext = vec![
0x43, 0x52, 0x59, 0x50, 0x54, 0x4f, 0x49, 0x53, 0x53, 0x48, 0x4f, 0x52, 0x54, 0x46,
0x4f, 0x52, 0x43, 0x52, 0x59, 0x50, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x50, 0x48, 0x59,
];
let mut ctx = VigenereContext::new();
ctx.key = Some(key);
let plaintext = ctx.decrypt(&ciphertext);
assert_eq![plaintext, Ok(expected_plaintext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_07() {
let ciphertext = vec![
0x6f, 0x70, 0x6b, 0x75, 0x68, 0x6d, 0x74,
0x6f, 0x77, 0x7a, 0x75, 0x61, 0x61, 0x6a,
0x66, 0x62, 0x65, 0x63, 0x73, 0x74, 0x66,
0x73, 0x6d, 0x49, 0x4d, 0x42, 0x4e, 0x49,
0x59, 0x45, 0x51, 0x43, 0x59, 0x57, 0x4d,
];
let key = vec![0x76, 0x69, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x65];
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 = VigenereContext::new();
ctx.key = Some(key);
ctx.is_capitalized = false;
let plaintext = ctx.decrypt(&ciphertext);
assert_eq![plaintext, Ok(expected_plaintext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_08() {
let key = vec![
0x26, 0x26, 0x2f, 0x24,
0x24, 0x22, 0x5b, 0x5b,
0x21, 0x3f, 0x7e, 0x7e,
];
let mut ctx = VigenereContext::new();
assert_eq![ctx.set_key(&key), Err(CryptoError::InvalidKey(
"For Vigenère cipher! Key is empty!".to_string(),
key,
))];
assert_eq![ctx.get_key(), None];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_09() {
let plaintext = vec![
0x61, 0x74, 0x74, 0x61,
0x63, 0x6b, 0x61, 0x74,
0x64, 0x61, 0x77, 0x6e,
];
let key = vec![0x6c, 0x65, 0x6d, 0x6f, 0x6e];
let expected_ciphertext = vec![
0x6c, 0x78, 0x66, 0x6f,
0x70, 0x76, 0x65, 0x66,
0x72, 0x6e, 0x68, 0x72,
];
let mut ctx = VigenereContext::new();
ctx.key = Some(key);
ctx.is_capitalized = false;
let ciphertext = ctx.encrypt(&plaintext);
assert_eq![ciphertext, Ok(expected_ciphertext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_10() {
let plaintext = vec![
0x43, 0x52, 0x59, 0x50, 0x54, 0x4f, 0x69, 0x73, 0x53, 0x48, 0x4f, 0x52, 0x54, 0x66,
0x6f, 0x72, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x47, 0x72, 0x41, 0x70, 0x48, 0x79,
];
let key = vec![0x41, 0x42, 0x43, 0x44];
let expected_ciphertext = vec![
0x43, 0x53, 0x41, 0x53, 0x54, 0x50, 0x4b, 0x56, 0x53, 0x49, 0x51, 0x55, 0x54, 0x47,
0x51, 0x55, 0x43, 0x53, 0x41, 0x53, 0x54, 0x50, 0x49, 0x55, 0x41, 0x51, 0x4a, 0x42,
];
let mut ctx = VigenereContext::new();
ctx.key = Some(key);
let ciphertext = ctx.encrypt(&plaintext);
assert_eq![ciphertext, Ok(expected_ciphertext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_11() {
let plaintext = vec![
0x54, 0x48, 0x45, 0x51, 0x55, 0x49, 0x43,
0x4b, 0x42, 0x52, 0x4f, 0x57, 0x4e, 0x46,
0x4f, 0x58, 0x4a, 0x55, 0x4d, 0x50, 0x53,
0x4f, 0x56, 0x45, 0x52, 0x54, 0x48, 0x45,
0x4c, 0x41, 0x5a, 0x59, 0x44, 0x4f, 0x47,
];
let key = vec![0x56, 0x49, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x45];
let expected_ciphertext = vec![
0x4f, 0x50, 0x4b, 0x55, 0x48, 0x4d, 0x54,
0x4f, 0x57, 0x5a, 0x55, 0x41, 0x41, 0x4a,
0x46, 0x42, 0x45, 0x43, 0x53, 0x54, 0x46,
0x53, 0x4d, 0x49, 0x4d, 0x42, 0x4e, 0x49,
0x59, 0x45, 0x51, 0x43, 0x59, 0x57, 0x4d,
];
let mut ctx = VigenereContext::new();
ctx.key = Some(key);
let ciphertext = ctx.encrypt(&plaintext);
assert_eq![ciphertext, Ok(expected_ciphertext)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_12() {
let text = vec![];
let mut ctx = VigenereContext::new();
assert_eq![ctx.encrypt(&text),
Err(CryptoError::MissingKey(
"Missing key for Vigenère encryption!".to_string()
))];
assert_eq![ctx.decrypt(&text),
Err(CryptoError::MissingKey(
"Missing key for Vigenère decryption!".to_string()
))]
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_13() {
let key = vec![0x76, 0x69, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x65];
let expected_key = vec![0x56, 0x49, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x45];
let mut ctx = VigenereContext::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_14() {
let key = vec![0x56, 0x49, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x45];
let expected_key = vec![0x76, 0x69, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x65];
let mut ctx = VigenereContext::new();
ctx.is_capitalized = false;
assert_eq![ctx.set_key(&key), Ok(())];
assert_eq![ctx.key, Some(expected_key)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_15() {
let key = vec![0x56, 0x49, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x45, 0x7e];
let expected_key = vec![0x76, 0x69, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x65];
let mut ctx = VigenereContext::new();
ctx.is_capitalized = false;
assert_eq![ctx.set_key(&key), Ok(())];
assert_eq![ctx.key, Some(expected_key)];
}
#[cfg_attr(not(feature = "doc_tests"), test)]
fn test_16() {
let ctx = VigenereContext::new();
assert_eq![ctx.get_atom_class(), AtomClass::Cipher];
}
}