pub mod cli; pub mod crypto; use std::{fs::File, path::Path, io::{self, Read, Write}}; use crypto::{DobyCipher, EncryptionParams}; use zeroize::Zeroize; pub const MAGIC_BYTES: &[u8; 4] = b"DOBY"; pub struct WrappedPassword(Option); 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 WrappedPassword { fn from(s: Option<&str>) -> Self { Self(s.map(String::from)) } } pub struct LazyWriter> { path: Option

, writer: Option>, } impl> LazyWriter

{ fn from_path(path: P) -> Self { Self { path: Some(path), writer: None, } } fn from_writer(writer: T) -> Self { Self { path: None, writer: Some(Box::new(writer)), } } } impl> Write for LazyWriter

{ fn write(&mut self, buf: &[u8]) -> io::Result { if self.writer.is_none() { self.writer = Some(Box::new(File::create(self.path.as_ref().unwrap()).unwrap())); } self.writer.as_mut().unwrap().write(buf) } fn flush(&mut self) -> io::Result<()> { self.writer.as_mut().unwrap().flush() } } pub fn encrypt(reader: &mut R, writer: &mut W, params: &EncryptionParams, mut cipher: DobyCipher, block_size: usize, already_read: Option<&[u8]>) -> io::Result<()> { writer.write_all(MAGIC_BYTES)?; params.write(writer)?; let mut buff = vec![0; block_size]; let mut n = 1; if let Some(already_read) = already_read { buff[..already_read.len()].clone_from_slice(&already_read); n = reader.read(&mut buff[already_read.len()..])?; cipher.encrypt_chunk(&mut buff[..n+already_read.len()], writer)?; } if n > 0 { loop { n = reader.read(&mut buff)?; if n == 0 { break; } else { cipher.encrypt_chunk(&mut buff[..n], writer)?; } } } cipher.write_hmac(writer)?; Ok(()) } pub fn decrypt(reader: &mut R, writer: &mut W, mut cipher: DobyCipher, block_size: usize) -> io::Result { let mut buff = vec![0; block_size]; loop { let n = cipher.decrypt_chunk(reader, &mut buff)?; if n == 0 { break; } else { writer.write_all(&buff[..n])?; } } Ok(cipher.verify_hmac()) }