From 2c8ab7e8ad9e4cfa8077711fe07a0a216b79dacc Mon Sep 17 00:00:00 2001 From: Hardcore Sushi Date: Sat, 13 Nov 2021 19:08:28 +0100 Subject: [PATCH] Password confirm --- src/bin/blocksize.rs | 15 ++-- src/bin/headers.rs | 8 +-- src/cli.rs | 37 +++++----- src/crypto.rs | 156 +++++++++++++++------------------------- src/lib.rs | 38 +++++----- src/main.rs | 51 +++++++------ tests/authentication.rs | 18 +++-- tests/cli.rs | 23 +++--- 8 files changed, 154 insertions(+), 192 deletions(-) diff --git a/src/bin/blocksize.rs b/src/bin/blocksize.rs index 5425f62..4dd8ecf 100644 --- a/src/bin/blocksize.rs +++ b/src/bin/blocksize.rs @@ -6,7 +6,7 @@ use std::{ }; use doby::{ encrypt, decrypt, - crypto::{ArgonParams, EncryptionParams, CipherAlgorithm, DobyCipher} + crypto::{EncryptionParams, CipherAlgorithm, DobyCipher} }; const MAX_BLOCK_SIZE: usize = 1_073_741_824; //1GB @@ -33,11 +33,10 @@ fn main() -> io::Result<()> { let input = File::open(&args[1])?; let output = OpenOptions::new().create(true).truncate(true).write(true).open(&args[2])?; - let params = EncryptionParams::new(ArgonParams{ - t_cost: 1, - m_cost: 8, - parallelism: 1, - }, CipherAlgorithm::AesCtr); + let params = EncryptionParams::new( + argon2::Params::new(8, 1, 1, None).unwrap(), + CipherAlgorithm::AesCtr + ); let mut best_encrypt_time = None; let mut best_encrypt_block_size = None; @@ -49,7 +48,7 @@ fn main() -> io::Result<()> { let mut reader = BufReader::with_capacity(block_size, &input); let mut writer = BufWriter::with_capacity(block_size, &output); - let cipher = DobyCipher::new(PASSWORD.into(), ¶ms).unwrap(); + let cipher = DobyCipher::new(PASSWORD.as_bytes(), ¶ms); let t_encrypt = Instant::now(); encrypt(&mut reader, &mut writer, ¶ms, cipher, block_size, None)?; writer.flush()?; @@ -59,7 +58,7 @@ fn main() -> io::Result<()> { reset(&mut reader)?; reset(&mut writer)?; - let cipher = DobyCipher::new(PASSWORD.into(), ¶ms).unwrap(); + let cipher = DobyCipher::new(PASSWORD.as_bytes(), ¶ms); let t_decrypt = Instant::now(); decrypt(&mut reader, &mut writer, cipher, block_size)?; writer.flush()?; diff --git a/src/bin/headers.rs b/src/bin/headers.rs index 8cf73e9..497da3a 100644 --- a/src/bin/headers.rs +++ b/src/bin/headers.rs @@ -10,12 +10,12 @@ fn main() -> io::Result<()> { if magic_bytes == MAGIC_BYTES { match EncryptionParams::read(&mut file)? { Some(params) => { - println!("Argon2 time cost: {}", params.argon2.t_cost); - println!("Argon2 memory cost: {}KB", params.argon2.m_cost); - println!("Argon2 parallelism: {}", params.argon2.parallelism); + println!("Argon2 time cost: {}", params.argon2.t_cost()); + println!("Argon2 memory cost: {}KB", params.argon2.m_cost()); + println!("Argon2 parallelism cost: {}", params.argon2.p_cost()); println!("Encryption cihpher: {}", params.cipher); } - None => eprintln!("Invalid cipher") + None => eprintln!("Invalid parameters") } } else { eprintln!("Doby format not recognized."); diff --git a/src/cli.rs b/src/cli.rs index c466589..27379a9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -5,14 +5,14 @@ use std::{ io::{stdin, stdout, Read}, }; use clap::{crate_name, crate_version, App, Arg, AppSettings}; -use crate::{LazyWriter, Password, crypto::{ArgonParams, CipherAlgorithm}}; +use crate::{LazyWriter, WrappedPassword, crypto::CipherAlgorithm}; cpufeatures::new!(aes_ni, "aes"); pub struct CliArgs { - pub password: Password, + pub password: WrappedPassword, pub force_encrypt: bool, - pub argon2_params: ArgonParams, + pub argon2_params: argon2::Params, pub cipher: CipherAlgorithm, pub block_size: usize, pub reader: Box, @@ -34,16 +34,15 @@ pub fn parse() -> Option { ) .arg( Arg::with_name("1_password") - .short("p") .long("password") .value_name("password") .help("Password used to derive encryption keys") ) .arg( Arg::with_name("2_t_cost") - .short("i") - .long("iterations") - .value_name("iterations") + .short("t") + .long("time-cost") + .value_name("number of iterations") .help("Argon2 time cost") .default_value("10") ) @@ -56,11 +55,11 @@ pub fn parse() -> Option { .default_value("4096") ) .arg( - Arg::with_name("4_parallelism") - .short("t") - .long("threads") - .value_name("threads") - .help("Argon2 parallelism (between 1 and 255)") + Arg::with_name("4_p_cost") + .short("p") + .long("parallelism") + .value_name("degree of parallelism") + .help("Argon2 parallelism cost") .default_value("4") ) .arg( @@ -85,14 +84,16 @@ pub fn parse() -> Option { let params = { let t_cost = number(app.value_of("2_t_cost").unwrap())?; let m_cost = number(app.value_of("3_m_cost").unwrap())?; - let parallelism = number(app.value_of("4_parallelism").unwrap())?; + let p_cost = number(app.value_of("4_p_cost").unwrap())?; - ArgonParams { - t_cost, - m_cost, - parallelism, + match argon2::Params::new(m_cost, t_cost, p_cost, None) { + Ok(params) => Some(params), + Err(e) => { + eprintln!("Invalid Argon2 parameters: {}", e); + None + } } - }; + }?; let cipher = app .value_of("cipher") diff --git a/src/crypto.rs b/src/crypto.rs index d5e94ac..9229f3c 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -1,4 +1,4 @@ -use std::{convert::{TryFrom, TryInto}, fmt::{self, Display, Formatter}, io::{self, Read, Write}}; +use std::{convert::TryFrom, fmt::{self, Display, Formatter}, io::{self, Read, Write}}; use num_enum::TryFromPrimitive; use chacha20::XChaCha20; use aes::{Aes256Ctr, cipher::{NewCipher, StreamCipher}}; @@ -7,7 +7,6 @@ use rand::{Rng, rngs::OsRng}; use argon2::{Argon2, Version, Algorithm}; use hkdf::Hkdf; use zeroize::Zeroize; -use crate::Password; pub const SALT_LEN: usize = 64; const AES_NONCE_LEN: usize = 16; @@ -15,20 +14,6 @@ const XCHACHA20_NONCE_LEN: usize = 24; pub const HASH_LEN: usize = 64; const KEY_LEN: usize = 32; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct ArgonParams { - pub t_cost: u32, - pub m_cost: u32, - pub parallelism: u8, -} - -impl TryFrom for argon2::Params { - type Error = argon2::Error; - fn try_from(params: ArgonParams) -> Result { - argon2::Params::new(params.m_cost, params.t_cost, params.parallelism.into(), None) - } -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, TryFromPrimitive)] #[repr(u8)] pub enum CipherAlgorithm { @@ -57,14 +42,14 @@ impl Display for CipherAlgorithm { #[derive(Debug, PartialEq, Eq)] pub struct EncryptionParams { salt: [u8; SALT_LEN], - pub argon2: ArgonParams, + pub argon2: argon2::Params, pub cipher: CipherAlgorithm, } impl EncryptionParams { - pub const LEN: usize = SALT_LEN + 4*2 + 2; + pub const LEN: usize = SALT_LEN + 4*3 + 1; - pub fn new(argon2_params: ArgonParams, cipher: CipherAlgorithm) -> EncryptionParams { + pub fn new(argon2_params: argon2::Params, cipher: CipherAlgorithm) -> EncryptionParams { let mut salt = [0; SALT_LEN]; OsRng.fill(&mut salt); EncryptionParams { @@ -76,9 +61,9 @@ impl EncryptionParams { pub fn write(&self, writer: &mut W) -> io::Result<()> { writer.write_all(&self.salt)?; - writer.write_all(&self.argon2.t_cost.to_be_bytes())?; - writer.write_all(&self.argon2.m_cost.to_be_bytes())?; - writer.write_all(&self.argon2.parallelism.to_be_bytes())?; + writer.write_all(&self.argon2.t_cost().to_be_bytes())?; + writer.write_all(&self.argon2.m_cost().to_be_bytes())?; + writer.write_all(&self.argon2.p_cost().to_be_bytes())?; writer.write_all(&(self.cipher as u8).to_be_bytes())?; Ok(()) } @@ -90,37 +75,25 @@ impl EncryptionParams { reader.read_exact(&mut t_cost)?; let mut m_cost = [0; 4]; reader.read_exact(&mut m_cost)?; - let mut parallelism = [0; 1]; - reader.read_exact(&mut parallelism)?; + let mut p_cost = [0; 4]; + reader.read_exact(&mut p_cost)?; let mut cipher_buff = [0; 1]; reader.read_exact(&mut cipher_buff)?; - match CipherAlgorithm::try_from(cipher_buff[0]) { - Ok(cipher) => { - let argon2_params = ArgonParams { - t_cost: u32::from_be_bytes(t_cost), - m_cost: u32::from_be_bytes(m_cost), - parallelism: u8::from_be_bytes(parallelism), - }; - - Ok(Some(EncryptionParams { + if let Ok(cipher) = CipherAlgorithm::try_from(cipher_buff[0]) { + if let Ok(argon2_params) = argon2::Params::new( + u32::from_be_bytes(m_cost), + u32::from_be_bytes(t_cost), + u32::from_be_bytes(p_cost), + None + ) { + return Ok(Some(EncryptionParams { salt, argon2: argon2_params, cipher, - })) + })); } - Err(_) => Ok(None) } - } -} - -trait ThenZeroize { - fn zeroize(self, v: T) -> Self; -} - -impl ThenZeroize for Result { - fn zeroize(self, mut v: T) -> Self { - v.zeroize(); - self + Ok(None) } } @@ -131,44 +104,35 @@ pub struct DobyCipher { } impl DobyCipher { - pub fn new(mut password: Password, params: &EncryptionParams) -> Result { - match params.argon2.try_into() { - Ok(argon2_params) => { - let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, argon2_params); - let mut master_key = [0; KEY_LEN]; - let password = password.unwrap_or_ask(); - argon2.hash_password_into(password.as_bytes(), ¶ms.salt, &mut master_key).zeroize(password)?; - let hkdf = Hkdf::::new(Some(¶ms.salt), &master_key); - master_key.zeroize(); - let mut nonce = vec![0; params.cipher.get_nonce_size()]; - hkdf.expand(b"doby_nonce", &mut nonce).unwrap(); - let mut encryption_key = [0; KEY_LEN]; - hkdf.expand(b"doby_encryption_key", &mut encryption_key).unwrap(); - let mut authentication_key = [0; KEY_LEN]; - hkdf.expand(b"doby_authentication_key", &mut authentication_key).unwrap(); + pub fn new(password: &[u8], params: &EncryptionParams) -> Self { + let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params.argon2.clone()); + let mut master_key = [0; KEY_LEN]; + argon2.hash_password_into(password, ¶ms.salt, &mut master_key).unwrap(); + let hkdf = Hkdf::::new(Some(¶ms.salt), &master_key); + master_key.zeroize(); + let mut nonce = vec![0; params.cipher.get_nonce_size()]; + hkdf.expand(b"doby_nonce", &mut nonce).unwrap(); + let mut encryption_key = [0; KEY_LEN]; + hkdf.expand(b"doby_encryption_key", &mut encryption_key).unwrap(); + let mut authentication_key = [0; KEY_LEN]; + hkdf.expand(b"doby_authentication_key", &mut authentication_key).unwrap(); - let mut encoded_params = Vec::with_capacity(EncryptionParams::LEN); - params.write(&mut encoded_params).unwrap(); - let mut hmac = Hmac::new_from_slice(&authentication_key).unwrap(); - authentication_key.zeroize(); - hmac.update(&encoded_params); + let mut encoded_params = Vec::with_capacity(EncryptionParams::LEN); + params.write(&mut encoded_params).unwrap(); + let mut hmac = Hmac::new_from_slice(&authentication_key).unwrap(); + authentication_key.zeroize(); + hmac.update(&encoded_params); - let cipher: Box = match params.cipher { - CipherAlgorithm::AesCtr => Box::new(Aes256Ctr::new_from_slices(&encryption_key, &nonce).unwrap()), - CipherAlgorithm::XChaCha20 => Box::new(XChaCha20::new_from_slices(&encryption_key, &nonce).unwrap()), - }; - encryption_key.zeroize(); + let cipher: Box = match params.cipher { + CipherAlgorithm::AesCtr => Box::new(Aes256Ctr::new_from_slices(&encryption_key, &nonce).unwrap()), + CipherAlgorithm::XChaCha20 => Box::new(XChaCha20::new_from_slices(&encryption_key, &nonce).unwrap()), + }; + encryption_key.zeroize(); - Ok(Self { - cipher, - hmac, - buffer: Vec::new(), - }) - } - Err(e) => { - password.zeroize(); - Err(e) - } + Self { + cipher, + hmac, + buffer: Vec::new(), } } @@ -209,24 +173,23 @@ impl DobyCipher { #[cfg(test)] mod tests { - use super::{ArgonParams, CipherAlgorithm, EncryptionParams, DobyCipher, HASH_LEN}; + use super::{CipherAlgorithm, EncryptionParams, DobyCipher, HASH_LEN}; #[test] fn encryption_params() { - let params = EncryptionParams::new(ArgonParams { - t_cost: 1, - m_cost: 8, - parallelism: 1, - }, CipherAlgorithm::XChaCha20); + let params = EncryptionParams::new( + argon2::Params::new(8, 1, 1, None).unwrap(), + CipherAlgorithm::XChaCha20 + ); - assert_eq!(EncryptionParams::LEN, 74); + assert_eq!(EncryptionParams::LEN, 77); let mut buff = Vec::with_capacity(74); params.write(&mut buff).unwrap(); assert_eq!(buff[..64], params.salt); assert_eq!(buff[64..68], vec![0, 0, 0, 0x01]); //t_cost assert_eq!(buff[68..72], vec![0, 0, 0, 0x08]); //m_cost - assert_eq!(buff[72], 0x01); //parallelism - assert_eq!(buff[73], CipherAlgorithm::XChaCha20 as u8); + assert_eq!(buff[72..76], vec![0, 0, 0, 0x01]); //p_cost + assert_eq!(buff[76], CipherAlgorithm::XChaCha20 as u8); let new_params = EncryptionParams::read(&mut buff.as_slice()).unwrap().unwrap(); assert_eq!(new_params, params); @@ -234,24 +197,23 @@ mod tests { #[test] fn doby_cipher() { - let params = EncryptionParams::new(ArgonParams { - t_cost: 1, - m_cost: 8, - parallelism: 1, - }, CipherAlgorithm::AesCtr); + let params = EncryptionParams::new( + argon2::Params::new(8, 1, 1, None).unwrap(), + CipherAlgorithm::AesCtr + ); let password = "I like spaghetti"; let plaintext = b"but I love so much to listen to HARDCORE music on big subwoofer"; let mut buff: [u8; 63] = *plaintext; let mut vec = Vec::with_capacity(buff.len()+HASH_LEN); - let mut enc_cipher = DobyCipher::new(password.into(), ¶ms).unwrap(); + let mut enc_cipher = DobyCipher::new(password.as_bytes(), ¶ms); enc_cipher.encrypt_chunk(&mut buff, &mut vec).unwrap(); assert_ne!(buff, *plaintext); assert_eq!(buff, vec.as_slice()); assert_eq!(enc_cipher.write_hmac(&mut vec).unwrap(), HASH_LEN); assert_eq!(vec.len(), buff.len()+HASH_LEN); - let mut dec_cipher = DobyCipher::new(password.into(), ¶ms).unwrap(); + let mut dec_cipher = DobyCipher::new(password.as_bytes(), ¶ms); let mut decrypted = vec![0; buff.len()+HASH_LEN]; let mut n = dec_cipher.decrypt_chunk(&mut vec.as_slice(), &mut decrypted[..]).unwrap(); assert_eq!(n, buff.len()); diff --git a/src/lib.rs b/src/lib.rs index c24aee6..6f60a6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,32 +7,36 @@ use zeroize::Zeroize; pub const MAGIC_BYTES: &[u8; 4] = b"DOBY"; -pub struct Password(Option); +pub struct WrappedPassword(Option); -impl Password { - fn unwrap_or_ask(self) -> String { - self.0.unwrap_or_else(|| rpassword::read_password_from_tty(Some("Password: ")).unwrap()) +impl WrappedPassword { + pub fn get(self, ask_confirm: bool) -> Option { + self.0.or_else(|| { + let mut password = rpassword::read_password_from_tty(Some("Password: ")).ok()?; + if ask_confirm { + let mut password_confirm = rpassword::read_password_from_tty(Some("Password (confirm): ")).ok()?; + if password == password_confirm { + password_confirm.zeroize(); + Some(password) + } else { + password.zeroize(); + password_confirm.zeroize(); + eprintln!("Passwords don't match"); + None + } + } else { + Some(password) + } + }) } } -impl From> for Password { +impl From> for WrappedPassword { fn from(s: Option<&str>) -> Self { Self(s.map(String::from)) } } -impl From<&str> for Password { - fn from(s: &str) -> Self { - Some(s).into() - } -} - -impl Zeroize for Password { - fn zeroize(&mut self) { - self.0.zeroize() - } -} - pub struct LazyWriter> { path: Option

, writer: Option>, diff --git a/src/main.rs b/src/main.rs index 683d7c4..86aa328 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use doby::{ decrypt, encrypt, }; +use zeroize::Zeroize; fn run() -> bool { let mut success = false; @@ -21,44 +22,42 @@ fn run() -> bool { Ok(params) => { match params { Some(params) => { - match DobyCipher::new(cli_args.password, ¶ms) { - Ok(cipher) => { - match decrypt(&mut reader, &mut writer, cipher, cli_args.block_size) { - Ok(verified) => { - if verified { - success = true - } else { - eprintln!("WARNING: HMAC verification failed !\nEither your password is incorrect or the ciphertext has been corrupted.\nBe careful, the data could have been altered by an attacker."); - } + if let Some(mut password) = cli_args.password.get(false) { + let cipher = DobyCipher::new(password.as_bytes(), ¶ms); + password.zeroize(); + match decrypt(&mut reader, &mut writer, cipher, cli_args.block_size) { + Ok(verified) => { + if verified { + success = true + } else { + eprintln!("WARNING: HMAC verification failed !\nEither your password is incorrect or the ciphertext has been corrupted.\nBe careful, the data could have been altered by an attacker."); } - Err(e) => eprintln!("I/O error while decrypting: {}", e) } + Err(e) => eprintln!("I/O error while decrypting: {}", e) } - Err(e) => eprintln!("Invalid argon2 params: {}", e) } } - None => eprintln!("Invalid cipher") + None => eprintln!("Invalid parameters") } } Err(e) => eprintln!("I/O error while reading headers: {}", e) } } else { //otherwise, encrypt let params = EncryptionParams::new(cli_args.argon2_params, cli_args.cipher); - match DobyCipher::new(cli_args.password, ¶ms) { - Ok(cipher) => { - match encrypt( - &mut reader, - &mut writer, - ¶ms, - cipher, - cli_args.block_size, - Some(&magic_bytes[..n]) - ) { - Ok(_) => success = true, - Err(e) => eprintln!("I/O error while encrypting: {}", e) - } + if let Some(mut password) = cli_args.password.get(true) { + let cipher = DobyCipher::new(password.as_bytes(), ¶ms); + password.zeroize(); + match encrypt( + &mut reader, + &mut writer, + ¶ms, + cipher, + cli_args.block_size, + Some(&magic_bytes[..n]) + ) { + Ok(_) => success = true, + Err(e) => eprintln!("I/O error while encrypting: {}", e) } - Err(e) => eprintln!("Invalid argon2 params: {}", e) } } } diff --git a/tests/authentication.rs b/tests/authentication.rs index 9385914..e578c3a 100644 --- a/tests/authentication.rs +++ b/tests/authentication.rs @@ -1,7 +1,6 @@ use rand::Rng; use doby::{ crypto::{ - ArgonParams, CipherAlgorithm, EncryptionParams, DobyCipher, @@ -19,15 +18,14 @@ fn different_elements(v1: &Vec, v2: &Vec) -> usize { fn authentication() { const BLOCK_SIZE: usize = 65536; const PLAINTEXT: &[u8; 13] = b"the plaintext"; - const CIPHERTEXT_SIZE: usize = PLAINTEXT.len()+142; + const CIPHERTEXT_SIZE: usize = PLAINTEXT.len()+145; const PASSWORD: &str = "the password"; - let params = EncryptionParams::new(ArgonParams { - t_cost: 1, - m_cost: 8, - parallelism: 1, - }, CipherAlgorithm::AesCtr); + let params = EncryptionParams::new( + argon2::Params::new(8, 1, 1, None).unwrap(), + CipherAlgorithm::AesCtr + ); - let encrypter = DobyCipher::new(PASSWORD.into(), ¶ms).unwrap(); + let encrypter = DobyCipher::new(PASSWORD.as_bytes(), ¶ms); let mut ciphertext = Vec::with_capacity(CIPHERTEXT_SIZE); encrypt(&mut &PLAINTEXT[..], &mut ciphertext, ¶ms, encrypter, BLOCK_SIZE, None).unwrap(); assert_eq!(ciphertext.len(), CIPHERTEXT_SIZE); @@ -38,13 +36,13 @@ fn authentication() { compromised[i] = rand::thread_rng().gen(); } assert_eq!(different_elements(&compromised, &ciphertext), 1); - let decrypter = DobyCipher::new(PASSWORD.into(), ¶ms).unwrap(); + let decrypter = DobyCipher::new(PASSWORD.as_bytes(), ¶ms); let mut decrypted = Vec::with_capacity(PLAINTEXT.len()); let verified = decrypt(&mut &compromised[..], &mut decrypted, decrypter, BLOCK_SIZE).unwrap(); assert_eq!(verified, false); } - let decrypter = DobyCipher::new(PASSWORD.into(), ¶ms).unwrap(); + let decrypter = DobyCipher::new(PASSWORD.as_bytes(), ¶ms); let mut decrypted = Vec::with_capacity(PLAINTEXT.len()); let verified = decrypt(&mut &ciphertext[4+EncryptionParams::LEN..], &mut decrypted, decrypter, BLOCK_SIZE).unwrap(); assert_eq!(decrypted, PLAINTEXT); diff --git a/tests/cli.rs b/tests/cli.rs index 575aa8c..e57f565 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -22,7 +22,7 @@ fn setup_files<'a>() -> io::Result<(PathBuf, PathBuf, PathBuf)> { fn doby_cmd() -> Result { let mut cmd = Command::cargo_bin("doby")?; - cmd.arg("-p").arg(PASSWORD); + cmd.arg("--password").arg(PASSWORD); Ok(cmd) } @@ -52,7 +52,7 @@ fn files() -> io::Result<()> { fn stdout() -> io::Result<()> { let (_, tmp_plaintext, tmp_ciphertext) = setup_files()?; - let shell_cmd = format!("{} -p \"{}\" {} > {}", cargo_bin("doby").to_str().unwrap(), PASSWORD, tmp_plaintext.to_str().unwrap(), tmp_ciphertext.to_str().unwrap()); + let shell_cmd = format!("{} --password \"{}\" {} > {}", cargo_bin("doby").to_str().unwrap(), PASSWORD, tmp_plaintext.to_str().unwrap(), tmp_ciphertext.to_str().unwrap()); bash_cmd().arg(shell_cmd).assert().success().stdout("").stderr(""); doby_cmd().unwrap().arg(tmp_ciphertext).assert().success().stdout(PLAINTEXT); @@ -64,10 +64,10 @@ fn stdout() -> io::Result<()> { fn stdin() -> io::Result<()> { let (_, tmp_plaintext, tmp_ciphertext) = setup_files()?; - let mut shell_cmd = format!("cat {} | {} -p \"{}\" - {}", tmp_plaintext.to_str().unwrap(), cargo_bin("doby").to_str().unwrap(), PASSWORD, tmp_ciphertext.to_str().unwrap()); + let mut shell_cmd = format!("cat {} | {} --password \"{}\" - {}", tmp_plaintext.to_str().unwrap(), cargo_bin("doby").to_str().unwrap(), PASSWORD, tmp_ciphertext.to_str().unwrap()); bash_cmd().arg(shell_cmd).assert().success().stdout("").stderr(""); - shell_cmd = format!("cat {} | {} -p \"{}\"", tmp_ciphertext.to_str().unwrap(), cargo_bin("doby").to_str().unwrap(), PASSWORD); + shell_cmd = format!("cat {} | {} --password \"{}\"", tmp_ciphertext.to_str().unwrap(), cargo_bin("doby").to_str().unwrap(), PASSWORD); bash_cmd().arg(shell_cmd).assert().success().stdout(PLAINTEXT); Ok(()) @@ -107,8 +107,8 @@ fn test_cipher(cipher_str: &str, cipher_algorithm: CipherAlgorithm) -> io::Resul doby_cmd().unwrap().arg("-c").arg(cipher_str).arg(tmp_plaintext).arg(&tmp_ciphertext).assert().success().stdout("").stderr(""); let ciphertext = fs::read(&tmp_ciphertext)?; - assert_eq!(ciphertext[4+SALT_LEN+4*2+1], cipher_algorithm as u8); - assert_eq!(ciphertext.len(), PLAINTEXT.len()+14+SALT_LEN+HASH_LEN); + assert_eq!(ciphertext[4+SALT_LEN+4*3], cipher_algorithm as u8); + assert_eq!(ciphertext.len(), PLAINTEXT.len()+17+SALT_LEN+HASH_LEN); doby_cmd().unwrap().arg(tmp_ciphertext).assert().success().stdout(PLAINTEXT).stderr(""); @@ -127,17 +127,16 @@ fn aes_cipher() -> io::Result<()> { Ok(()) } - #[test] fn argon2_params() -> io::Result<()> { - Command::cargo_bin("doby").unwrap().arg("-i").arg("0").assert().failure().stderr("Invalid argon2 params: time cost is too small\n"); - Command::cargo_bin("doby").unwrap().arg("-m").arg("0").assert().failure().stderr("Invalid argon2 params: memory cost is too small\n"); - Command::cargo_bin("doby").unwrap().arg("-t").arg("0").assert().failure().stderr("Invalid argon2 params: not enough threads\n"); + Command::cargo_bin("doby").unwrap().arg("-t").arg("0").assert().failure().stderr("Invalid Argon2 parameters: time cost is too small\n"); + Command::cargo_bin("doby").unwrap().arg("-m").arg("0").assert().failure().stderr("Invalid Argon2 parameters: memory cost is too small\n"); + Command::cargo_bin("doby").unwrap().arg("-p").arg("0").assert().failure().stderr("Invalid Argon2 parameters: not enough threads\n"); - let ciphertext = doby_cmd().unwrap().arg("-i").arg("8").arg("-m").arg("2048").arg("-t").arg("8").assert().success().stderr("").get_output().stdout.clone(); + let ciphertext = doby_cmd().unwrap().arg("-t").arg("8").arg("-m").arg("2048").arg("-p").arg("8").assert().success().stderr("").get_output().stdout.clone(); assert_eq!(u32::from_be_bytes(ciphertext[4+SALT_LEN..4+SALT_LEN+4].try_into().unwrap()), 8); //time cost assert_eq!(u32::from_be_bytes(ciphertext[4+SALT_LEN+4..4+SALT_LEN+8].try_into().unwrap()), 2048); //memory cost - assert_eq!(u8::from_be_bytes([ciphertext[4+SALT_LEN+8]]), 8); //parallelism + assert_eq!(u32::from_be_bytes(ciphertext[4+SALT_LEN+8..4+SALT_LEN+12].try_into().unwrap()), 8); //parallelism Ok(()) } \ No newline at end of file