use crate::{CryptoError, Result};
use cipher::block_padding::NoPadding;
use cipher::{BlockDecryptMut, BlockEncryptMut, KeyInit, KeyIvInit};
pub fn ecb_decrypt(key: &[u8], data: &[u8]) -> Result<Vec<u8>> {
ecb::Decryptor::<des::Des>::new_from_slice(key)
.map_err(|_| CryptoError::KeyLength {
expected: 8,
got: key.len(),
})?
.decrypt_padded_vec_mut::<NoPadding>(data)
.map_err(|_| CryptoError::NotBlockAligned(data.len(), 8))
}
pub fn ecb_encrypt(key: &[u8], data: &[u8]) -> Result<Vec<u8>> {
if data.len() % 8 != 0 {
return Err(CryptoError::NotBlockAligned(data.len(), 8));
}
Ok(ecb::Encryptor::<des::Des>::new_from_slice(key)
.map_err(|_| CryptoError::KeyLength {
expected: 8,
got: key.len(),
})?
.encrypt_padded_vec_mut::<NoPadding>(data))
}
pub fn cbc_decrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>> {
cbc::Decryptor::<des::Des>::new_from_slices(key, iv)
.map_err(|_| CryptoError::IvLength {
expected: 8,
got: iv.len(),
})?
.decrypt_padded_vec_mut::<NoPadding>(data)
.map_err(|_| CryptoError::NotBlockAligned(data.len(), 8))
}
pub fn cbc_encrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>> {
if data.len() % 8 != 0 {
return Err(CryptoError::NotBlockAligned(data.len(), 8));
}
Ok(cbc::Encryptor::<des::Des>::new_from_slices(key, iv)
.map_err(|_| CryptoError::IvLength {
expected: 8,
got: iv.len(),
})?
.encrypt_padded_vec_mut::<NoPadding>(data))
}
pub fn fix_key(key: &[u8]) -> Vec<u8> {
key.iter()
.map(|&b| {
let fold = b
^ (b << 1)
^ (b << 2)
^ (b << 3)
^ (b << 4)
^ (b << 5)
^ (b << 6)
^ (b << 7)
^ 0x80;
b ^ (fold & 0x80)
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ecb_round_trip() {
let key = b"8bytekey";
let plain = b"eReader content page bytes here!"; let ct = ecb_encrypt(key, plain).unwrap();
assert_eq!(ecb_decrypt(key, &ct).unwrap(), plain);
assert_ne!(&ct[..], &plain[..]);
}
#[test]
fn ecb_rejects_unaligned() {
assert!(matches!(
ecb_encrypt(b"8bytekey", b"seven!!"),
Err(CryptoError::NotBlockAligned(7, 8))
));
}
#[test]
fn cbc_round_trip() {
let key = b"8bytekey";
let iv = b"initves8";
let plain = b"Android V2 obfuscation payload!!"; let ct = cbc_encrypt(key, iv, plain).unwrap();
assert_eq!(cbc_decrypt(key, iv, &ct).unwrap(), plain);
assert_ne!(&ct[..], &plain[..]);
}
}