1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
pub use crate::orchestrate::encrypt::encrypt;
pub use crate::orchestrate::decrypt::decrypt;
pub use crate::config::DecryptConfig;
pub use crate::config::EncryptConfig;
pub use crate::config::EndecConfig;
pub use crate::header::strategy::Verbosity;
pub use crate::key::Key;
pub use crate::key::KeySource;
pub use crate::util::FedResult;

#[cfg(feature = "expose")]
pub use crate::files::mockfile::generate_test_file_content_for_test;
#[cfg(feature = "expose")]
pub use crate::header::strategy::get_current_version_strategy;
#[cfg(feature = "expose")]
pub use crate::key::hash::hash_argon2i;
#[cfg(feature = "expose")]
pub use crate::key::hash::hash_bcrypt;
#[cfg(feature = "expose")]
pub use crate::key::hash::hash_sha256;
#[cfg(feature = "expose")]
pub use crate::key::key::StretchKey;
#[cfg(feature = "expose")]
pub use crate::key::stretch::stretch_key;
#[cfg(feature = "expose")]
pub use crate::key::Salt;
#[cfg(feature = "expose")]
pub use crate::symmetric::decrypt::decrypt_aes256;
#[cfg(feature = "expose")]
pub use crate::symmetric::decrypt::decrypt_twofish;
#[cfg(feature = "expose")]
pub use crate::symmetric::encrypt::encrypt_aes256;
#[cfg(feature = "expose")]
pub use crate::symmetric::encrypt::encrypt_twofish;

mod config;
mod e2e;
mod files;
mod header;
mod key;
mod orchestrate;
mod progress;
mod symmetric;
mod util;

#[cfg(test)]
mod tests {
    use ::aes::Aes256;
    use ::block_modes::block_padding::Iso7816;
    use ::block_modes::BlockMode;
    use ::block_modes::Cbc;
    use ::lazy_static::lazy_static;
    use ::regex::Regex;
    use ::secstr::SecVec;

    use crate::key::key::Key;

    type Aes256Cbc = Cbc<Aes256, Iso7816>;

    lazy_static! {
        static ref COMPAT_KEY: Key = Key::new(" LP0y#shbogtwhGjM=*jFFZPmNd&qBO+ ");
        static ref COMPAT_FILE_RE: Regex = Regex::new(r"^original_v(\d+\.\d+\.\d+).png$").unwrap();
    }

    /// The demo used in this blog post:
    /// https://markv.nl/blog/symmetric-encryption-in-rust
    #[test]
    fn demo() {
        // Key must be 32 bytes for Aes256. It should probably be the hashed
        // version of the input key, so is not limited to printable ascii.
        // SecVec has several advantages in preventing the key from leaking.
        let key = SecVec::from(b"RvzQW3Mwrc!_y5-DpPZl8rP3,=HsD1,!".to_vec());

        // The initialization vector (like salt or nonce) must be 16 bytes for
        // this block size. It could be generated using a secure randon generator,
        // and should be different each time. It is not a secret.
        let iv = vec![
            89, 63, 254, 34, 209, 155, 236, 158, 195, 104, 11, 16, 240, 4, 26, 76,
        ];

        // This is the data that is to be encrypted.
        let plaintext: Vec<u8> = b"Hello world! This is the secret text...".to_vec();

        // Encryption.
        // Fails if the key or iv are the wrong length, so it is safe to unwrap
        // as we have the correct lengths. Key length depends on algorithm, iv length
        // depends on the block size. If it's not documented, experiment with 16 or 32.
        let cipher = Aes256Cbc::new_var(key.unsecure(), &iv).unwrap();
        let ciphertext = cipher.encrypt_vec(&plaintext);

        // Check that it worked.
        assert_eq!(
            &ciphertext,
            &vec![
                216, 56, 166, 254, 171, 163, 243, 167, 235, 179, 189, 132, 0, 202, 44, 73, 10, 68,
                229, 90, 69, 212, 24, 22, 87, 109, 34, 92, 254, 136, 141, 154, 57, 189, 176, 221,
                140, 8, 114, 141, 103, 248, 108, 182, 247, 156, 113, 127,
            ]
        );

        // Decryption.
        let cipher = Aes256Cbc::new_var(key.unsecure(), &iv).unwrap();
        let decrypted_ciphertext = cipher.decrypt_vec(&ciphertext).unwrap();

        // Check that we got the original input back.
        assert_eq!(decrypted_ciphertext, plaintext);
    }
}