#![allow(dead_code)]
#![allow(unused_assignments)]
pub mod chacha20;
pub mod sm4;
use std::cmp::min;
use std::marker;
use std::vec;
use rand::prelude::*;
use crate::encoding::EncodingTrait as _;
use crate::encoding::base64::Base64Encoding;
use crate::hash::HasherTrait;
use crate::hash::crc::Crc32cHasher;
use crate::hash::sha256::Sha256Hasher;
use crate::*;
pub enum CipherAlgorithm {
ChaCha20,
Sm4,
}
#[derive(Clone)]
pub enum CipherAlgorithmType {
Stream,
Block(usize),
}
pub trait CipherAlgorithmBaseTrait {
const IV_LENGTH: usize;
const KEY_LENGTH: usize;
const CIPHER_ALGORITHM_TYPE: CipherAlgorithmType;
fn iv_length() -> usize {
Self::IV_LENGTH
}
fn key_length() -> usize {
Self::KEY_LENGTH
}
fn cipher_algorithm_type() -> CipherAlgorithmType {
Self::CIPHER_ALGORITHM_TYPE
}
}
pub trait CipherAlgorithmTrait: CipherAlgorithmBaseTrait {
fn crypt(&mut self, src_data: &[u8], dst_data: &mut [u8]) -> Result<()>;
}
pub trait IVKeyNewTrait {
fn new(iv: &[u8], key: &[u8]) -> Result<Self>
where
Self: Sized;
}
pub trait StreamGeneratorTrait {
fn generate(&mut self, len: usize) -> Result<ByteVector>;
}
pub trait StringCrypterTrait {
fn encrypt(&self, data: &str, password: &str) -> Result<String>;
fn decrypt(&self, data: &str, password: &str) -> Result<String>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StreamGeneratorMode {
Short = 1,
Medium = 32,
Large = 1024,
}
#[inline]
const fn stream_temp_block_count(m: StreamGeneratorMode) -> usize {
return m as usize * 64;
}
#[inline]
const fn stream_temp_buffer_size(m: StreamGeneratorMode) -> usize {
return m as usize * 1024;
}
pub struct StreamGenerator<CA: CipherAlgorithmTrait + IVKeyNewTrait> {
m_cipher_algorithm: CA,
m_mode: StreamGeneratorMode,
m_max_buffer_size: usize,
m_current_index: usize,
m_current_buffer: ByteVector,
m_plaintext_buffer: ByteVector,
}
impl<CA: CipherAlgorithmTrait + IVKeyNewTrait> StreamGenerator<CA> {
fn new(iv: &[u8], key: &[u8], mode: StreamGeneratorMode) -> Result<Self> {
let calc_stream_temp_buffer_size = |mode: StreamGeneratorMode| -> usize {
if let CipherAlgorithmType::Block(n) = CA::cipher_algorithm_type() {
return stream_temp_block_count(mode) * n;
}
stream_temp_buffer_size(mode)
};
let buffer_size = calc_stream_temp_buffer_size(mode.clone());
Ok(StreamGenerator::<CA> {
m_cipher_algorithm: CA::new(iv, key)?,
m_mode: mode.clone(),
m_current_index: buffer_size,
m_max_buffer_size: buffer_size,
m_current_buffer: vec![0x00; buffer_size],
m_plaintext_buffer: vec![0x00; buffer_size],
})
}
fn flush(&mut self) -> Result<()> {
if self.m_current_index != self.m_max_buffer_size {
return Err(CrypterError::BufferFlushFailed.into());
}
self.m_cipher_algorithm
.crypt(&self.m_plaintext_buffer, &mut self.m_current_buffer)?;
self.m_current_index = 0;
Ok(())
}
}
impl<CA: CipherAlgorithmTrait + IVKeyNewTrait> IVKeyNewTrait for StreamGenerator<CA> {
fn new(iv: &[u8], key: &[u8]) -> Result<Self> {
Self::new(iv, key, StreamGeneratorMode::Medium)
}
}
impl<CA: CipherAlgorithmTrait + IVKeyNewTrait> StreamGeneratorTrait for StreamGenerator<CA> {
fn generate(&mut self, len: usize) -> Result<ByteVector> {
if len == 0 {
return Ok(ByteVector::new());
}
if self.m_current_index >= self.m_max_buffer_size {
self.flush()?;
}
let mut dst_data = vec![0x00 as u8; len];
let mut index: usize = 0;
let mut once_gen: usize = self.m_max_buffer_size - self.m_current_index;
while index + once_gen < len {
memcpy(
&mut dst_data[index..index + once_gen],
&self.m_current_buffer[self.m_current_index..self.m_current_index + once_gen],
)?;
index += once_gen;
self.m_current_index += once_gen;
self.flush()?;
once_gen = self.m_max_buffer_size - self.m_current_index;
}
let last_gen = len - index;
memcpy(
&mut dst_data[index..index + last_gen],
&self.m_current_buffer[self.m_current_index..self.m_current_index + last_gen],
)?;
index += last_gen;
self.m_current_index += last_gen;
Ok(dst_data)
}
}
#[inline]
fn rand_iv(n: usize) -> ByteVector {
let mut res = vec![0x00; n];
let mut rng = rand::thread_rng();
rng.fill_bytes(&mut res);
res
}
#[inline]
fn generate_key_from_password<HR: HasherTrait + Default>(password: &str, n: usize) -> ByteVector {
let mut hasher = HR::default();
hasher.update_message(password);
let mut buffer = hasher.finalize();
let mut cnt: usize = 0;
let mut res = vec![0x00; n];
while cnt < n {
let once_gen = min(n - cnt, buffer.len());
for i in 0..once_gen {
res[cnt + i] = buffer[i];
}
cnt += once_gen;
if cnt >= n {
break;
}
hasher.update_bytes(&buffer);
buffer = hasher.finalize();
}
res
}
pub struct StringCrypter<
CA: CipherAlgorithmTrait + IVKeyNewTrait,
HR: HasherTrait + Default = Crc32cHasher,
> {
_ca: marker::PhantomData<CA>,
_hr: marker::PhantomData<HR>,
}
impl<CA: CipherAlgorithmTrait + IVKeyNewTrait, HR: HasherTrait + Default> StringCrypter<CA, HR> {
pub fn rand_iv(n: usize) -> ByteVector {
crate::crypter::rand_iv(n)
}
pub fn generate_key_from_password(password: &str, n: usize) -> ByteVector {
generate_key_from_password::<Sha256Hasher>(password, n)
}
}
impl<CA: CipherAlgorithmTrait + IVKeyNewTrait, HR: HasherTrait + Default> Default
for StringCrypter<CA, HR>
{
fn default() -> Self {
StringCrypter::<CA, HR> {
_ca: marker::PhantomData::<CA>,
_hr: marker::PhantomData::<HR>,
}
}
}
impl<CA: CipherAlgorithmTrait + IVKeyNewTrait, HR: HasherTrait + Default> StringCrypterTrait
for StringCrypter<CA, HR>
{
fn encrypt(&self, data: &str, password: &str) -> Result<String> {
if data.is_empty() {
return Err(CrypterError::EmptyStringNotAllowed.into());
}
if password.is_empty() {
return Err(CrypterError::EmptyPasswordNotAllowed.into());
}
let iv = rand_iv(CA::IV_LENGTH);
let key = Self::generate_key_from_password(password, CA::KEY_LENGTH);
let mut stream_generator =
StreamGenerator::<CA>::new(&iv, &key, StreamGeneratorMode::Short)?;
let plain_data_bytes = data.as_bytes();
let plain_data_checksum = {
let mut c = HR::default();
c.update_bytes(&plain_data_bytes);
c.finalize()
};
let cipher_data_bytes = {
let cipher_stream = stream_generator.generate(plain_data_bytes.len())?;
xor(&cipher_stream, plain_data_bytes)?
};
let cipher_data_checksum = {
let cipher_stream = stream_generator.generate(plain_data_checksum.len())?;
xor(&cipher_stream, &plain_data_checksum)?
};
let res = [&iv[..], &cipher_data_checksum[..], &cipher_data_bytes[..]].concat();
Ok(Base64Encoding::default().encode(&res))
}
fn decrypt(&self, data: &str, password: &str) -> Result<String> {
if data.is_empty() {
return Err(CrypterError::EmptyStringNotAllowed.into());
}
if password.is_empty() {
return Err(CrypterError::EmptyPasswordNotAllowed.into());
}
let b64 = Base64Encoding::default();
let data = b64.decode(data)?;
let mut iv = vec![0u8; CA::IV_LENGTH];
let mut cipher_data_checksum = vec![0u8; HR::OUTPUT_LENGTH];
let mut mt = MemoryTaker::new(&data);
let cipher_data_bytes = mt
.take(&mut iv)?
.take(&mut cipher_data_checksum)?
.take_all()?;
let key = Self::generate_key_from_password(password, CA::KEY_LENGTH);
let mut stream_generator =
StreamGenerator::<CA>::new(&iv, &key, StreamGeneratorMode::Short)?;
let plain_data_bytes = {
let cipher_stream = stream_generator.generate(cipher_data_bytes.len())?;
xor(&cipher_data_bytes, &cipher_stream)?
};
let plain_data_checksum = {
let cipher_stream = stream_generator.generate(cipher_data_checksum.len())?;
xor(&cipher_data_checksum, &cipher_stream)?
};
let calced_plain_data_checksum = {
let mut c = HR::default();
c.update_bytes(&plain_data_bytes);
c.finalize()
};
if plain_data_checksum != calced_plain_data_checksum {
return Err(CrypterError::ChecksumValidationFailed.into());
}
Ok(String::from_utf8(plain_data_bytes)
.map_err(|_| Into::<Error>::into(CrypterError::StringDecodingFailed))?)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::encoding::EncodingTrait;
use crate::encoding::hex::HexEncoding;
#[test]
fn test_generate_key_from_password() {
let hexe = HexEncoding::default();
let res = generate_key_from_password::<Sha256Hasher>("123456", 32);
assert_eq!(
"8D969EEF6ECAD3C29A3A629280E686CF0C3F5D5A86AFF3CA12020C923ADC6C92".to_string(),
hexe.encode(&res)
);
let res = generate_key_from_password::<Sha256Hasher>("123456", 48);
assert_eq!("8D969EEF6ECAD3C29A3A629280E686CF0C3F5D5A86AFF3CA12020C923ADC6C9213619CFEA04EEB088EA04D789731EFED".to_string(), hexe.encode(&res));
}
}