deadbolt-crypto 0.1.1

Cryptography wrapper for deadbolt
Documentation
#![allow(dead_code)]
#![allow(unused_imports)]

extern crate secrecy;

use secrecy::{Secret, SecretString};

pub mod encryption;
pub mod hash;
pub mod rand;

#[cfg(test)]
mod tests {
    use secrecy::ExposeSecret;
    use secrecy::Secret;
    use secrecy::SecretString;

    use crate::encryption;
    use crate::encryption::Encryption;
    use crate::encryption::StreamEncryption;
    use crate::hash::Hash;
    use crate::hash::Hkdf;
    use crate::hash::Hmac;
    use crate::hash::PasswordHash;

    use super::*;

    #[test]
    fn test_aes_encryption() {
        let key = Secret::new(b"32_bytes_master_key_of_AES-256!!".to_vec());
        let plaintext = b"yellow_submarine";
        let mut aes = Encryption::new(&key);
        let ciphertext = aes.encrypt(plaintext.to_vec(), 1).unwrap();

        let decrypted = aes.decrypt(ciphertext.nonce, ciphertext.data, 1).unwrap();
        assert_eq!(decrypted.data, plaintext);
    }

    #[test]
    fn test_chacha_encryption() {
        let key = Secret::new(b"32_bytes_master_key_of_ChaCha20!".to_vec());
        let plaintext = b"yellow_submarine";
        let mut aes = Encryption::new(&key);
        let ciphertext = aes.encrypt(plaintext.to_vec(), 2).unwrap();

        let decrypted = aes.decrypt(ciphertext.nonce, ciphertext.data, 2).unwrap();
        assert_eq!(decrypted.data, plaintext);
    }

    #[test]
    fn test_failed_decryption() {
        let key = Secret::new(b"32_bytes_master_key_of_AES-256!!".to_vec());
        let plaintext = b"yellow_submarine";
        let mut aes = Encryption::new(&key);
        let ciphertext = aes.encrypt(plaintext.to_vec(), 1).unwrap();

        let incorrect_key = Secret::new(b"32_bytes_master_key_of_AES-256??".to_vec());
        aes = Encryption::new(&incorrect_key);
        let decrypted = aes.decrypt(ciphertext.nonce, ciphertext.data, 1);

        assert!(decrypted.is_err());
    }

    #[test]
    fn test_stream_encryption() {
        let key = Secret::new(b"32_bytes_master_key_of_ChaCha8!!".to_vec());
        let plaintext = b"yellow_submarine";
        let ciphertext = StreamEncryption::encrypt(&key, plaintext.as_ref());

        let decrypted = StreamEncryption::decrypt(&key, &ciphertext);
        assert_eq!(decrypted, plaintext);
    }

    #[test]
    fn test_hash() {
        let message = b"yellow_submarine";
        let digest = Hash::sha256(&message.to_vec());

        assert_eq!(
            "482ea0629467352543559ecbc2ce0c2010c2d0fac069ffc304f5cf15af0ff85e",
            hex::encode(digest)
        );
    }

    #[test]
    fn test_hmac() {
        let secret = Secret::new(b"some_secret!!".to_vec());
        let digest_to_compare =
            hex::decode("aa504f4e415b461fd97296b18ed12514e389743a4cb2599511d55557afa6729d")
                .unwrap();
        let mut mac = Hmac::new(&secret);
        mac.update(b"test".as_ref());

        assert!(mac.verify(&digest_to_compare).is_ok());
    }

    #[test]
    fn test_key_derivation() {
        let password: SecretString = SecretString::new("yellow_submarine".to_string());
        let key_material =
            PasswordHash::argon2d(password, "yellow_submarine".as_bytes(), 2, 1, 19 * 1024);

        assert_eq!(key_material.expose_secret().len(), 32);
        let output_key_material = Hkdf::expand(key_material);

        let expected = hex::decode(
            "\
                a6956358323fb84f92b0e0ef12f6df793423e76589b89da56d0f0ed018d6dc54\
                8735c1432cda528f981f25fc374fd6609cec138a56264c20f002d34a77b652c6",
        )
        .unwrap();

        assert_eq!(output_key_material.expose_secret().to_vec(), expected);
    }

    #[test]
    fn test_check_aes_reused_nonce() {
        let key = Secret::new(b"32_bytes_master_key_of_AES-256!!".to_vec());
        let plaintext = b"yellow_submarine";
        let mut aes = Encryption::new(&key);
        let ciphertext1 = aes.encrypt(plaintext.to_vec(), 1).unwrap();
        let ciphertext2 = aes.encrypt(plaintext.to_vec(), 1).unwrap();

        assert_ne!(ciphertext1.nonce, ciphertext2.nonce);
    }

    #[test]
    fn test_check_chacha_reused_nonce() {
        let key = Secret::new(b"32_bytes_master_key_of_ChaCha20!".to_vec());
        let plaintext = b"yellow_submarine";
        let mut aes = Encryption::new(&key);
        let ciphertext1 = aes.encrypt(plaintext.to_vec(), 2).unwrap();
        let ciphertext2 = aes.encrypt(plaintext.to_vec(), 2).unwrap();

        assert_ne!(ciphertext1.nonce, ciphertext2.nonce);
    }

    #[test]
    fn test_check_aes_tamper_resistant() {
        let key = Secret::new(b"32_bytes_master_key_of_AES-256!!".to_vec());
        let plaintext = b"yellow_submarine";
        let mut aes = Encryption::new(&key);
        let mut ciphertext = aes.encrypt(plaintext.to_vec(), 1).unwrap();

        ciphertext.data[0] ^= 1;
        let decryption1 = aes.decrypt(ciphertext.nonce, ciphertext.data.clone(), 1);

        ciphertext.nonce[0] ^= 1;
        let decryption2 = aes.decrypt(ciphertext.nonce, ciphertext.data, 1);

        assert!(decryption1.is_err());
        assert!(decryption2.is_err());
    }

    #[test]
    fn test_check_chacha_tamper_resistant() {
        let key = Secret::new(b"32_bytes_master_key_of_AES-256!!".to_vec());
        let plaintext = b"yellow_submarine";
        let mut aes = Encryption::new(&key);
        let mut ciphertext = aes.encrypt(plaintext.to_vec(), 2).unwrap();

        ciphertext.data[0] ^= 1;
        let decryption1 = aes.decrypt(ciphertext.nonce, ciphertext.data.clone(), 2);

        ciphertext.nonce[0] ^= 1;
        let decryption2 = aes.decrypt(ciphertext.nonce, ciphertext.data, 2);

        assert!(decryption1.is_err());
        assert!(decryption2.is_err());
    }
}