ciftl/crypter/
mod.rs

1pub mod chacha20;
2
3use std::cmp::min;
4use std::marker;
5use std::vec;
6
7use num_derive::FromPrimitive;
8use num_traits::FromPrimitive;
9use rand::prelude::*;
10
11use crate::encoding::base64::Base64Encoding;
12use crate::encoding::EncodingTrait as _;
13use crate::hash::crc::Crc32cHasher;
14use crate::hash::crc::CRC32_OUTPUT_LENGTH;
15use crate::hash::sha256::Sha256Hasher;
16use crate::hash::HasherTrait;
17use crate::*;
18
19/// 目前支持的所有算法
20pub enum CipherAlgorithm {
21    ChaCha20,
22}
23
24/// 密码算法的类型
25#[derive(Clone)]
26pub enum CipherAlgorithmType {
27    Stream,
28    Block(usize),
29}
30
31/// 原始的密码算法trait
32pub trait CipherAlgorithmBaseTrait {
33    const IV_LENGTH: usize;
34    const KEY_LENGTH: usize;
35    const CIPHER_ALGORITHM_TYPE: CipherAlgorithmType;
36
37    /// 返回IV的长度
38    fn iv_length() -> usize {
39        Self::IV_LENGTH
40    }
41
42    /// Key的长度
43    fn key_length() -> usize {
44        Self::KEY_LENGTH
45    }
46
47    /// 返回当前加密算法的类型(流密码还是分组密码)
48    fn cipher_algorithm_type() -> CipherAlgorithmType {
49        Self::CIPHER_ALGORITHM_TYPE
50    }
51}
52
53/// 密码算法trait
54pub trait CipherAlgorithmTrait: CipherAlgorithmBaseTrait {
55    /// 加密算法原始的加密处理,对一串长度为分组长度倍数的数组进行加密
56    /// 所有加密算法应强制保证完整的加密了一个分组,不应有漏加密或者剩余的情况,
57    /// 也应当保证src_data和dst_data之间长度相等
58    fn crypt(&mut self, src_data: &[u8], dst_data: &mut [u8]) -> Result<()>;
59}
60
61/// 通过IV和Key生成一个实例
62pub trait IVKeyNewTrait {
63    /// 创建一个加密算法器
64    fn new(iv: &[u8], key: &[u8]) -> Result<Self>
65    where
66        Self: Sized;
67}
68
69/// 密码流生成器的trait
70pub trait StreamGeneratorTrait {
71    /// 生成密码流
72    fn generate(&mut self, len: usize) -> Result<ByteVector>;
73}
74
75/// 字符串加密器trait
76pub trait StringCrypterTrait {
77    fn encrypt(&self, data: &str, password: &str) -> Result<String>;
78    fn decrypt(&self, data: &str, password: &str) -> Result<String>;
79}
80
81//------------------------------------------------具体实现------------------------------------------------//
82/// 密码流生成器模式
83#[derive(FromPrimitive, Clone)]
84pub enum StreamGeneratorMode {
85    Short = 1,
86    Medium = 32,
87    Large = 1024,
88}
89/// 获取不同模式下的缓存区的分组块数量
90#[inline]
91const fn stream_temp_block_count(m: StreamGeneratorMode) -> usize {
92    return m as usize * 64;
93}
94
95/// 获取不同模式下的缓存区的长度
96#[inline]
97const fn stream_temp_buffer_size(m: StreamGeneratorMode) -> usize {
98    return m as usize * 1024;
99}
100
101/// StreamGenerator是ciftl自己实现的一个流生成器,具体逻辑是传入一个实现了CipherAlgorithmTrait和
102/// IVKeyNewTrait的密码算法结构体,然后通过调用密码算法的加密函数实现自定义的字符串加密器
103pub struct StreamGenerator<CA: CipherAlgorithmTrait + IVKeyNewTrait> {
104    /// 加密算法器实例
105    m_cipher_algorithm: CA,
106    /// 密码流生成器模式
107    m_mode: StreamGeneratorMode,
108    /// 缓冲区的最大容量
109    m_max_buffer_size: usize,
110    /// 当前的索引
111    m_current_index: usize,
112    /// 当前的缓冲区
113    m_current_buffer: ByteVector,
114    /// 初始的明文内容
115    m_plaintext_buffer: ByteVector,
116}
117
118impl<CA: CipherAlgorithmTrait + IVKeyNewTrait> StreamGenerator<CA> {
119    /// 新建一个密码流生成器
120    fn new(iv: &[u8], key: &[u8], mode: StreamGeneratorMode) -> Result<Self> {
121        let calc_stream_temp_buffer_size = |mode: StreamGeneratorMode| -> usize {
122            if let CipherAlgorithmType::Block(n) = CA::cipher_algorithm_type() {
123                return stream_temp_block_count(mode) * n;
124            }
125            stream_temp_buffer_size(mode)
126        };
127        let buffer_size = calc_stream_temp_buffer_size(mode.clone());
128        Ok(StreamGenerator::<CA> {
129            m_cipher_algorithm: CA::new(iv, key)?,
130            m_mode: mode.clone(),
131            // 当前的下标应该在缓冲区的最后,因为最开始并没有初始化
132            m_current_index: buffer_size,
133            m_max_buffer_size: buffer_size,
134            m_current_buffer: vec![0x00; buffer_size],
135            m_plaintext_buffer: vec![0x00; buffer_size],
136        })
137    }
138
139    /// 刷新缓冲区
140    fn flush(&mut self) -> Result<()> {
141        if self.m_current_index != self.m_max_buffer_size {
142            return Err(CURRENT_INDEX_NOT_AT_THE_END_OF_BUFFER_WHEN_FLUSHING.clone());
143        }
144        self.m_cipher_algorithm
145            .crypt(&self.m_plaintext_buffer, &mut self.m_current_buffer)?;
146        self.m_current_index = 0;
147        Ok(())
148    }
149}
150
151impl<CA: CipherAlgorithmTrait + IVKeyNewTrait> IVKeyNewTrait for StreamGenerator<CA> {
152    /// 新建一个密码流生成器
153    fn new(iv: &[u8], key: &[u8]) -> Result<Self> {
154        Self::new(iv, key, StreamGeneratorMode::Medium)
155    }
156}
157
158impl<CA: CipherAlgorithmTrait + IVKeyNewTrait> StreamGeneratorTrait for StreamGenerator<CA> {
159    fn generate(&mut self, len: usize) -> Result<ByteVector> {
160        if len == 0 {
161            return Ok(ByteVector::new());
162        }
163        // 如果当前缓冲区中无更多内容则刷新
164        if self.m_current_index >= self.m_max_buffer_size {
165            self.flush()?;
166        }
167        // 生成的结果
168        let mut dst_data = vec![0x00 as u8; len];
169        // 当前生成到的字节索引
170        let mut index: usize = 0;
171        // 记录缓冲区还能生成的字节的最大数量
172        let mut once_gen: usize = self.m_max_buffer_size - self.m_current_index;
173        // 如果要产生新的buffer,则不断的循环这一步骤
174        while index + once_gen < len {
175            memcpy(
176                &mut dst_data[index..index + once_gen],
177                &self.m_current_buffer[self.m_current_index..self.m_current_index + once_gen],
178            )?;
179            index += once_gen;
180            self.m_current_index += once_gen;
181            self.flush()?;
182            once_gen = self.m_max_buffer_size - self.m_current_index;
183        }
184        // 将剩余部份拷贝
185        let last_gen = len - index;
186        memcpy(
187            &mut dst_data[index..index + last_gen],
188            &self.m_current_buffer[self.m_current_index..self.m_current_index + last_gen],
189        )?;
190        index += last_gen;
191        self.m_current_index += last_gen;
192        Ok(dst_data)
193    }
194}
195
196/// 随机生成IV
197#[inline]
198fn rand_iv(n: usize) -> ByteVector {
199    let mut res = vec![0x00; n];
200    let mut rng = rand::thread_rng();
201    rng.fill_bytes(&mut res);
202    res
203}
204
205/// 该函数用于从密码生成密钥流,其原理是将密码进行sha256哈希,将哈希值拷贝到给定长度为N的ByteArray中
206/// 如果一次sha256的长度不足N,则将上一次的哈希值与原文拼接继续进行一次哈希,并将值继续拷贝到ByteArray中,重复该步骤直到长度大于N为止
207#[inline]
208fn generate_key_from_password<HR: HasherTrait + Default>(password: &str, n: usize) -> ByteVector {
209    // 生成加密所需的密钥
210    let mut hasher = HR::default();
211    hasher.update_message(password);
212    let mut buffer = hasher.finalize();
213    let mut cnt: usize = 0;
214    let mut res = vec![0x00; n];
215    while cnt < n {
216        // 计算下次填充的长度
217        let once_gen = min(n - cnt, buffer.len());
218        // 拷贝
219        for i in 0..once_gen {
220            res[cnt + i] = buffer[i];
221        }
222        cnt += once_gen;
223        if cnt >= n {
224            break;
225        }
226        // 长度不足对结果进行二次哈希
227        hasher.update_bytes(&buffer);
228        buffer = hasher.finalize();
229    }
230    res
231}
232
233/// StringCrypter是ciftl自己实现的一个文本加密器
234pub struct StringCrypter<
235    CA: CipherAlgorithmTrait + IVKeyNewTrait,
236    HR: HasherTrait + Default = Crc32cHasher,
237> {
238    _ca: marker::PhantomData<CA>,
239    _hr: marker::PhantomData<HR>,
240}
241
242impl<CA: CipherAlgorithmTrait + IVKeyNewTrait, HR: HasherTrait + Default> StringCrypter<CA, HR> {
243    pub fn rand_iv(n: usize) -> ByteVector {
244        crate::crypter::rand_iv(n)
245    }
246
247    pub fn generate_key_from_password(password: &str, n: usize) -> ByteVector {
248        generate_key_from_password::<Sha256Hasher>(password, n)
249    }
250}
251
252impl<CA: CipherAlgorithmTrait + IVKeyNewTrait, HR: HasherTrait + Default> Default
253    for StringCrypter<CA, HR>
254{
255    fn default() -> Self {
256        StringCrypter::<CA, HR> {
257            _ca: marker::PhantomData::<CA>,
258            _hr: marker::PhantomData::<HR>,
259        }
260    }
261}
262
263impl<CA: CipherAlgorithmTrait + IVKeyNewTrait, HR: HasherTrait + Default> StringCrypterTrait
264    for StringCrypter<CA, HR>
265{
266    fn encrypt(&self, data: &str, password: &str) -> Result<String> {
267        if data.is_empty() {
268            return Err(CANNOT_DO_CRYPTION_TO_EMPTY_STRING.clone());
269        }
270        if password.is_empty() {
271            return Err(PASSWORD_CANNOT_BE_EMPTY.clone());
272        }
273        
274        // 创建一个密码流生成器
275        let iv = rand_iv(CA::IV_LENGTH);
276        let key = Self::generate_key_from_password(password, CA::KEY_LENGTH);
277        let mut stream_generator =
278            StreamGenerator::<CA>::new(&iv, &key, StreamGeneratorMode::Short)?;
279        // 获取明文的字节流
280        let plain_data_bytes = data.as_bytes();
281        // 获取明文的校验值
282        let plain_data_checksum = {
283            let mut c = HR::default();
284            c.update_bytes(&plain_data_bytes);
285            c.finalize()
286        };
287        // 生成密码流进行加密
288        let cipher_data_bytes = {
289            let cipher_stream = stream_generator.generate(plain_data_bytes.len())?;
290            xor(&cipher_stream, plain_data_bytes)?
291        };
292        // 继续加密校验值
293        let cipher_data_checksum = {
294            let cipher_stream = stream_generator.generate(plain_data_checksum.len())?;
295            xor(&cipher_stream, &plain_data_checksum)?
296        };
297        let res = [&iv[..], &cipher_data_checksum[..], &cipher_data_bytes[..]].concat();
298        // 对结果进行编码
299        Ok(Base64Encoding::default().encode(&res))
300    }
301
302    fn decrypt(&self, data: &str, password: &str) -> Result<String> {
303        if data.is_empty() {
304            return Err(CANNOT_DO_CRYPTION_TO_EMPTY_STRING.clone());
305        }
306        if password.is_empty() {
307            return Err(PASSWORD_CANNOT_BE_EMPTY.clone());
308        }
309
310        // 对密文进行解码
311        let b64 = Base64Encoding::default();
312        let data = b64.decode(data)?;
313        // 从原文中获取数据
314        let mut iv = vec![0u8; CA::IV_LENGTH];
315        let mut cipher_data_checksum = vec![0u8; HR::OUTPUT_LENGTH];
316        let mut mt = MemoryTaker::new(&data);
317        let cipher_data_bytes = mt
318            .take(&mut iv)?
319            .take(&mut cipher_data_checksum)?
320            .take_all()?;
321        // 创建一个密码流生成器
322        let key = Self::generate_key_from_password(password, CA::KEY_LENGTH);
323        let mut stream_generator =
324            StreamGenerator::<CA>::new(&iv, &key, StreamGeneratorMode::Short)?;
325        // 生成密码流进行解密
326        let plain_data_bytes = {
327            let cipher_stream = stream_generator.generate(cipher_data_bytes.len())?;
328            xor(&cipher_data_bytes, &cipher_stream)?
329        };
330        // 解密原文的校验值
331        let plain_data_checksum = {
332            let cipher_stream = stream_generator.generate(cipher_data_checksum.len())?;
333            xor(&cipher_data_checksum, &cipher_stream)?
334        };
335        // 计算解密后的内容的校验值
336        let calced_plain_data_checksum = {
337            let mut c = HR::default();
338            c.update_bytes(&plain_data_bytes);
339            c.finalize()
340        };
341        if plain_data_checksum != calced_plain_data_checksum {
342            return Err(FAILED_WHEN_CHECKING_CRC32_VALUE_OF_DECRYPTED_CONTENT.clone());
343        }
344        Ok(String::from_utf8(plain_data_bytes)
345            .map_err(|e| FAILED_WHEN_DECODING_STRING.add_opt_mess(&format!("{:?}", e)))?)
346    }
347}
348
349#[cfg(test)]
350mod tests {
351
352    use super::*;
353    use crate::encoding::hex::HexEncoding;
354    use crate::encoding::EncodingTrait;
355
356    #[test]
357    fn test_generate_key_from_password() {
358        let hexe = HexEncoding::default();
359        // 123456 32bytes
360        let res = generate_key_from_password::<Sha256Hasher>("123456", 32);
361        assert_eq!(
362            "8D969EEF6ECAD3C29A3A629280E686CF0C3F5D5A86AFF3CA12020C923ADC6C92".to_string(),
363            hexe.encode(&res)
364        );
365        // 123456 48bytes
366        let res = generate_key_from_password::<Sha256Hasher>("123456", 48);
367        assert_eq!("8D969EEF6ECAD3C29A3A629280E686CF0C3F5D5A86AFF3CA12020C923ADC6C9213619CFEA04EEB088EA04D789731EFED".to_string(), hexe.encode(&res));
368    }
369}