ciftl/crypter/
chacha20.rs

1use ::chacha20::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek};
2use ::chacha20::ChaCha20 as ExChaCha20;
3
4use crate::crypter::{
5    CipherAlgorithmBaseTrait, CipherAlgorithmTrait, CipherAlgorithmType, IVKeyNewTrait,
6    StreamGenerator, StreamGeneratorMode, StringCrypter,
7};
8use crate::*;
9
10/// ChaCha20的IV长度
11pub const CHACHA20_IV_LENGTH: usize = 12;
12/// ChaCha20的Key长度
13pub const CHACHA20_KEY_LENGTH: usize = 32;
14
15/// ChaCha20密码算法
16pub struct ChaCha20CipherAlgorithm {
17    m_algo: ExChaCha20,
18}
19
20impl CipherAlgorithmBaseTrait for ChaCha20CipherAlgorithm {
21    const IV_LENGTH: usize = CHACHA20_IV_LENGTH;
22    const KEY_LENGTH: usize = CHACHA20_KEY_LENGTH;
23    const CIPHER_ALGORITHM_TYPE: CipherAlgorithmType = CipherAlgorithmType::Stream;
24}
25
26impl CipherAlgorithmTrait for ChaCha20CipherAlgorithm {
27    fn crypt(&mut self, src_data: &[u8], dst_data: &mut [u8]) -> Result<()> {
28        // 这里为了减少拷贝次数,先将src复制到dst中
29        memcpy(dst_data, &src_data)?;
30        self.m_algo.apply_keystream(dst_data);
31        Ok(())
32    }
33}
34
35impl IVKeyNewTrait for ChaCha20CipherAlgorithm {
36    fn new(iv: &[u8], key: &[u8]) -> Result<Self>
37    where
38        Self: Sized,
39    {
40        if iv.len() != Self::IV_LENGTH {
41            return Err(CIPHER_ALGORITHM_UNSATISFIED_IV_LENGTH.clone());
42        }
43        if key.len() != Self::KEY_LENGTH {
44            return Err(CIPHER_ALGORITHM_UNSATISFIED_KEY_LENGTH.clone());
45        }
46        let cipher: ExChaCha20 = ExChaCha20::new(key.into(), iv.into());
47        Ok(ChaCha20CipherAlgorithm { m_algo: cipher })
48    }
49}
50
51#[cfg(test)]
52mod tests {
53
54    use crypter::StringCrypterTrait;
55    use hash::sha1::Sha1Hasher;
56    use hash::sha512::Sha512Hasher;
57
58    use super::*;
59    use crate::encoding::hex::HexEncoding;
60    use crate::encoding::EncodingTrait;
61
62    #[test]
63    fn test_chacha20() {
64        let string_crypter = StringCrypter::<ChaCha20CipherAlgorithm>::default();
65        let ciphertext = string_crypter.encrypt("123456", "123456").unwrap();
66        println!("ciphertext: {ciphertext}");
67        let plaintext = string_crypter.decrypt(&ciphertext, "123456").unwrap();
68        println!("plaintext: {plaintext}");
69        assert_eq!(plaintext, "123456");
70    }
71}