2021-06-25 23:01:50 +02:00
|
|
|
pub mod cli;
|
|
|
|
pub mod crypto;
|
|
|
|
|
2021-11-13 19:34:46 +01:00
|
|
|
use std::{fmt::Display, fs::OpenOptions, io::{self, BufWriter, Read, Write}, path::Path};
|
2021-06-27 20:35:23 +02:00
|
|
|
use crypto::{DobyCipher, EncryptionParams};
|
2021-07-04 16:24:44 +02:00
|
|
|
use zeroize::Zeroize;
|
2021-06-25 23:01:50 +02:00
|
|
|
|
|
|
|
pub const MAGIC_BYTES: &[u8; 4] = b"DOBY";
|
|
|
|
|
2021-11-13 19:08:28 +01:00
|
|
|
pub struct WrappedPassword(Option<String>);
|
2021-07-04 16:24:44 +02:00
|
|
|
|
2021-11-13 19:08:28 +01:00
|
|
|
impl WrappedPassword {
|
|
|
|
pub fn get(self, ask_confirm: bool) -> Option<String> {
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
})
|
2021-07-04 16:24:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-13 19:08:28 +01:00
|
|
|
impl From<Option<&str>> for WrappedPassword {
|
2021-07-04 16:24:44 +02:00
|
|
|
fn from(s: Option<&str>) -> Self {
|
2021-08-31 11:23:15 +02:00
|
|
|
Self(s.map(String::from))
|
2021-07-04 16:24:44 +02:00
|
|
|
}
|
|
|
|
}
|
2021-11-13 19:34:46 +01:00
|
|
|
pub enum WrappedWriter<P: AsRef<Path>> {
|
|
|
|
PATH {
|
|
|
|
path: P
|
|
|
|
},
|
|
|
|
WRITER {
|
|
|
|
writer: Box<dyn Write>
|
|
|
|
}
|
2021-07-04 19:24:20 +02:00
|
|
|
}
|
|
|
|
|
2021-11-13 19:34:46 +01:00
|
|
|
impl<P: AsRef<Path> + Display> WrappedWriter<P> {
|
2021-07-04 19:24:20 +02:00
|
|
|
fn from_path(path: P) -> Self {
|
2021-11-13 19:34:46 +01:00
|
|
|
Self::PATH { path }
|
2021-07-04 19:24:20 +02:00
|
|
|
}
|
|
|
|
|
2021-11-13 19:34:46 +01:00
|
|
|
fn from_writer<T: 'static + Write>(writer: T) -> Self {
|
|
|
|
Self::WRITER { writer: Box::new(writer) }
|
2021-07-04 19:24:20 +02:00
|
|
|
}
|
|
|
|
|
2021-11-13 19:34:46 +01:00
|
|
|
pub fn into_buf_writer(self) -> Option<BufWriter<Box<dyn Write>>> {
|
|
|
|
Some(BufWriter::new(match self {
|
|
|
|
Self::PATH { path } => Box::new(
|
|
|
|
OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
|
|
|
|
.map_err(|e| eprintln!("{}: {}", path, e))
|
|
|
|
.ok()?
|
|
|
|
) as Box<dyn Write>,
|
|
|
|
Self::WRITER { writer } => writer,
|
|
|
|
}))
|
2021-07-04 19:24:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-31 11:23:15 +02:00
|
|
|
pub fn encrypt<R: Read, W: Write>(reader: &mut R, writer: &mut W, params: &EncryptionParams, mut cipher: DobyCipher, block_size: usize, already_read: Option<&[u8]>) -> io::Result<()> {
|
2021-06-25 23:01:50 +02:00
|
|
|
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)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-07-08 12:21:14 +02:00
|
|
|
cipher.write_hmac(writer)?;
|
2021-06-25 23:01:50 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-06-27 20:35:23 +02:00
|
|
|
pub fn decrypt<R: Read, W: Write>(reader: &mut R, writer: &mut W, mut cipher: DobyCipher, block_size: usize) -> io::Result<bool> {
|
2021-06-25 23:01:50 +02:00
|
|
|
let mut buff = vec![0; block_size];
|
|
|
|
loop {
|
|
|
|
let n = cipher.decrypt_chunk(reader, &mut buff)?;
|
|
|
|
if n == 0 {
|
|
|
|
break;
|
|
|
|
} else {
|
2021-08-31 11:23:15 +02:00
|
|
|
writer.write_all(&buff[..n])?;
|
2021-06-25 23:01:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(cipher.verify_hmac())
|
|
|
|
}
|