master
Avril 4 years ago
parent 988f49d3bd
commit f324132f18
Signed by: flanchan
GPG Key ID: 284488987C31F630

1
Cargo.lock generated

@ -775,6 +775,7 @@ dependencies = [
"hex-literal",
"lazy_static",
"libc",
"once_cell",
"pin-project",
"recolored",
"rustc_version",

@ -35,6 +35,7 @@ base64 = "0.12.3"
hex = "0.4.2"
async-trait = "0.1.40"
hex-literal = "0.3.1"
once_cell = "1.4.1"
#serde_json = "1.0.57" # serde not suitable for our text formatting :/ maybe just use `cbor` -> base64 with text header? would be a PEM-like format. sounds good imo
[build-dependencies]

@ -82,7 +82,7 @@ impl Header for KeyHeader
fn hash(&self) -> Sha256Hash
{
let mut output = Vec::new();
self.write_bytes(&mut output, None).now_or_never().unwrap().expect("Failed to write bytes to in-memory buffer");
self.write_bytes(&mut output, |_| None).now_or_never().unwrap().expect("Failed to write bytes to in-memory buffer");
crypto::sha256::compute_slice(output)
}
}
@ -135,19 +135,37 @@ impl KeyHeader
}
/// Write this superheader as text bytes to this stream
#[instrument(err, skip(out))]
pub async fn write_text<T: AsyncWrite+Unpin+?Sized>(&self, out: &mut T, passwd: Option<&Password>) -> Result<usize, eyre::Report>
#[instrument(err, skip(out, passwd))]
pub async fn write_text<T: AsyncWrite+Unpin+?Sized, F: FnOnce(&SaltGen) -> Option<Password>>(&self, out: &mut T, passwd: F) -> Result<usize, eyre::Report>
{
let text = serialise::into_text(self)
.wrap_err_with(|| eyre::eyre!("Failed to serialise header to text"))
let salt = SaltGen::new();
let (mut written, passwd)= match passwd(&salt) {
Some(passwd) => {
let mut salt = salt.into_inner().ok_or_else(|| eyre::eyre!("Password function returned a password not bound to the provided salt generator"))
.with_warning(|| "This is a bug, and should never happen")
.with_section(|| passwd.to_string().header("Unbound returned password was"))?;
salt.as_mut()[0] |= 1u8; // make sure no conflict with NOPASS
let salt = encode_salt_to_string(&salt);
out.write_all(salt.as_bytes()).await?;
out.write_u8(b'\n').await?;
debug_assert_eq!(salt.len(), TEXT_NOPASS.len());
(salt.len() + 1, Some(passwd))
},
None => {
out.write_all(TEXT_NOPASS).await?;
out.write_u8(b'\n').await?;
(TEXT_NOPASS.len() + 1, None)
},
};
let text = if let Some(passwd) = passwd {
let aes = passwd.create_aes();
serialise::into_text_with_key_async(self, &aes).await
} else {
serialise::into_text(self)
}.wrap_err_with(|| eyre::eyre!("Failed to serialise header to text"))
.with_section(|| format!("{:?}", self).header("Header was"))?;
let mut written={
out.write_all(TEXT_NOPASS).await?;
out.write_u8(b'\n').await?;
TEXT_NOPASS.len() + 1
};
for bytes in text.as_bytes().chunks(16) {
out.write_all(bytes).await?;
out.write_u8(b'\n').await?;
@ -252,7 +270,7 @@ impl KeyHeader
None
} else {
Some(decode_salt(&pass_part[..])
.with_section(move || pass_part.header("Password string part was"))?)
.with_section(move || pass_part.header("Password salt string part was"))?)
}
};
trace!("Decoded hex");
@ -274,14 +292,30 @@ impl KeyHeader
warn!("Buffer contained no end-of-entry delimiter");
}
//let = take_one!("Expected header line");
if let Some(salt) = password {
todo!()
} else {
Ok::<Self, eyre::Report>(serialise::from_text(&enc[..])
.wrap_err_with(|| eyre::eyre!("Failed to deserialise string"))
.with_section(|| enc.header("Read string was"))?)
match password {
Some(salt) => {
match passwd(&salt) {
Some(passwd) => {
let aes = passwd.create_aes();
Ok::<Self, eyre::Report>(serialise::from_text_with_key_async(&enc[..], &aes).await
.wrap_err_with(|| eyre::eyre!("Failed to deserialise encrypted string"))
.with_section(|| aes.to_string().header("Derived key was"))
.with_section(|| salt.to_hex_string().header("Embedded salt was"))
.with_section(|| enc.header("Read string was"))
.with_note(|| "Did you enter the wrong password?")?)
},
None => return Err(eyre::eyre!("Container is password encrypted but no password was provided"))
.with_section(|| enc.header("Read (encrypted) string was"))
.with_section(|| salt.to_hex_string().header("Embedded salt was"))
.with_note(|| "This key must be loaded with `-p` or `-P`"),
}
}
None => {
Ok::<Self, eyre::Report>(serialise::from_text(&enc[..])
.wrap_err_with(|| eyre::eyre!("Failed to deserialise string"))
.with_section(|| enc.header("Read string was"))?)
}
}
};
tokio::pin!(line_sender);
@ -301,8 +335,8 @@ impl KeyHeader
}
}
/// Write this key header as bytes to this stream
#[instrument(err, skip(out))]
pub async fn write_bytes<T: AsyncWrite+Unpin+?Sized>(&self, out: &mut T, passwd: Option<&Password>) -> Result<usize, eyre::Report>
#[instrument(err, skip(out, passwd))]
pub async fn write_bytes<T: AsyncWrite+Unpin+?Sized, F: FnOnce(&SaltGen) -> Option<Password>>(&self, out: &mut T, passwd: F) -> Result<usize, eyre::Report>
{
out.write_u8(self.kind as u8).await?;
let desc = {
@ -361,7 +395,7 @@ impl KeyHeader
impl serialise::BinarySerialisable for KeyHeader
{
#[inline(always)] fn serialise_bytes<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized>(&'a self, out: &'b mut T, passwd: Option<&'b Password>) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
#[inline(always)] fn serialise_bytes<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized,F: for<'r> FnOnce(&'r SaltGen) -> Option<Password>+ 'b>(&'a self, out: &'b mut T, passwd: F) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
{
self.write_bytes(out, passwd).boxed_local()
}
@ -374,7 +408,7 @@ impl serialise::BinarySerialisable for KeyHeader
impl serialise::TextSerialiseable for KeyHeader
{
#[inline(always)] fn serialise_text<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized>(&'a self, out: &'b mut T, passwd: Option<&'b Password>) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
#[inline(always)] fn serialise_text<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized, F: for<'r> FnOnce(&'r SaltGen) -> Option<Password> + 'b>(&'a self, out: &'b mut T, passwd: F) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
{
self.write_text(out, passwd).boxed_local()
}
@ -414,18 +448,22 @@ mod tests
let header = KeyHeader::new_now(KeyHeaderKind::Aes, Default::default(), Default::default());
let mut ser = Vec::new();
let password = Password::derive("hello world", &Default::default());
const PASSWORD: &str = "hello world";
fn derive(salt: &Salt) -> Option<Password>
{
Some(Password::derive(PASSWORD, salt))
}
let superheader = SuperHeader::<KeyHeader>::new_for(&header);
println!("Writing: {:?} + {:?}", superheader, header);
let written = superheader.serialise_bytes(&mut ser, Some(&password)).await? +
header.write_bytes(&mut ser,Some(&password)).await?;
let written = superheader.serialise_bytes(&mut ser, |s| derive(s.get())).await? +
header.write_bytes(&mut ser, |s| derive(s.get())).await?;
println!("Wrote {} bytes", written);
println!("{}\n", ser.fmt_view());
let mut read = &ser[..];
let reads = SuperHeader::deserialise_bytes(&mut read, |_| Some(password.clone())).await?;
let reads = SuperHeader::deserialise_bytes(&mut read, |s| derive(s)).await?;
println!("Read super: {:?}", reads);
let readheader = KeyHeader::deserialise_bytes(&mut read, |_| Some(password.clone())).await?;
let readheader = KeyHeader::deserialise_bytes(&mut read, |s| derive(s)).await?;
println!("Read real: {:?}", readheader);
reads.verify_for(&header)?;
@ -441,7 +479,7 @@ mod tests
let header = KeyHeader::new_now(KeyHeaderKind::Aes, Default::default(), Default::default());
let mut ser = Vec::new();
println!("Writing {:?}", header);
let val = header.write_bytes(&mut ser, None).await?;
let val = header.write_bytes(&mut ser, |_| None).await?;
println!("Wrote {} bytes:", val);
println!("{}\n", ser.fmt_view());
@ -458,7 +496,7 @@ mod tests
let header = KeyHeader::new_now(KeyHeaderKind::Aes, Default::default(), Default::default());
let mut ser = Vec::new();
println!("Writing {:?}", header);
let val = header.write_text(&mut ser, None).await?;
let val = header.write_text(&mut ser, |_| None).await?;
println!("Wrote {} bytes:", val);
println!("{}\n", ser.fmt_view());
@ -477,8 +515,8 @@ mod tests
let mut ser = Vec::new();
let superheader = SuperHeader::<KeyHeader>::new_for(&header);
println!("Writing: {:?} + {:?}", superheader, header);
let written = superheader.write_text(&mut ser, None).await?;
ser.extend(header.into_memory(serialise::Mode::Text, None)?); //header.write_text(&mut ser).await?;
let written = superheader.write_text(&mut ser, |_| None).await?;
ser.extend(header.into_memory(serialise::Mode::Text, |_| None)?); //header.write_text(&mut ser).await?;
println!("Wrote {} bytes", written);
println!("{}\n", ser.fmt_view());

@ -21,6 +21,7 @@ use tokio::{
};
use version::Version;
use crypto::password::{Password,Salt};
use serialise::SaltGen;
/// Trait RAE headers implement
pub trait Header: fmt::Debug
@ -72,8 +73,8 @@ const MAX_TEXT_SZ: Option<usize> = Some(1024 * 1024);
impl<H: Header +?Sized> SuperHeader<H>
{
/// Write this superheader as text bytes to this stream
#[instrument(err, skip(out))]
pub async fn write_text<T: AsyncWrite+Unpin+?Sized>(&self, out: &mut T, passwd: Option<&Password>) -> Result<usize, eyre::Report>
#[instrument(err, skip(out, passwd))]
pub async fn write_text<T: AsyncWrite+Unpin+?Sized, F: FnOnce(&SaltGen) -> Option<Password>>(&self, out: &mut T, passwd: F) -> Result<usize, eyre::Report>
{
let string = format!(r#"--- {} v{}-{:x} ({}) {} ---
"#, std::str::from_utf8(&self.head[..])
@ -82,7 +83,7 @@ impl<H: Header +?Sized> SuperHeader<H>
.with_section(|| self.head.fmt_view().to_string().header("Head bytes were"))?,
self.vers,
self.vers.to_u32(),
self.header_hash.to_hex_string(),
self.header_hash.to_hex_string(), // this is what gets encrypted by password
H::NAME);
out.write_all(string.as_bytes()).await?;
Ok(string.len())
@ -197,13 +198,13 @@ impl<H: Header +?Sized> SuperHeader<H>
}
/// Write this superheader as bytes to this stream
#[instrument(err, skip(out))]
pub async fn write_bytes<T: AsyncWrite+Unpin+?Sized>(&self, out: &mut T, passwd: Option<&Password>) -> Result<usize, eyre::Report>
#[instrument(err, skip(out, passwd))]
pub async fn write_bytes<T: AsyncWrite+Unpin+?Sized, F: FnOnce(&SaltGen) -> Option<Password>>(&self, out: &mut T, passwd: F) -> Result<usize, eyre::Report>
{
Ok({out.write_all(&self.head[..]).await?; self.head.len()} +
{out.write_all(self.vers.as_bytes()).await?; std::mem::size_of::<Version>()} +
{out.write_u16(self.chk).await?; 2} +
{out.write_all(self.header_hash.as_ref()).await?; std::mem::size_of::<crypto::sha256::Sha256Hash>()})
{out.write_all(self.header_hash.as_ref()).await?; std::mem::size_of::<crypto::sha256::Sha256Hash>()}) //this is what gets encrypted by password
}
/// Read a superheader as bytes from this stream
#[instrument(err, skip(input, passwd))]
@ -323,7 +324,7 @@ impl<H: Header+?Sized> fmt::Display for VerificationError<H>
impl<H: Header+?Sized> serialise::BinarySerialisable for SuperHeader<H>
{
#[inline(always)] fn serialise_bytes<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized>(&'a self, out: &'b mut T, passwd: Option<&'b Password>) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
#[inline(always)] fn serialise_bytes<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized, F: for<'r> FnOnce(&'r SaltGen) -> Option<Password> + 'b>(&'a self, out: &'b mut T, passwd: F) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
{
self.write_bytes(out, passwd).boxed_local()
}
@ -336,7 +337,7 @@ impl<H: Header+?Sized> serialise::BinarySerialisable for SuperHeader<H>
impl<H: Header+?Sized> serialise::TextSerialiseable for SuperHeader<H>
{
#[inline(always)] fn serialise_text<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized>(&'a self, out: &'b mut T, passwd: Option<&'b Password>) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
#[inline(always)] fn serialise_text<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized, F: for<'r> FnOnce(&'r SaltGen) -> Option<Password> + 'b>(&'a self, out: &'b mut T, passwd: F) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
{
self.write_text(out, passwd).boxed_local()
}

@ -148,8 +148,8 @@ async fn fuck() -> eyre::Result<()>
let mut ser = Vec::new();
let superheader = SuperHeader::<KeyHeader>::new_for(&header);
println!("Writing: {:?} + {:?}", superheader, header);
let written = superheader.write_text(&mut ser, None).await?;
ser.extend(header.into_memory(serialise::Mode::Text, None)?); //header.write_text(&mut ser).await?;
let written = superheader.write_text(&mut ser, |_| None).await?;
ser.extend(header.into_memory(serialise::Mode::Text, |_| None)?); //header.write_text(&mut ser).await?;
println!("Wrote {} bytes", written);
println!("{}\n", ser.fmt_view());

@ -10,7 +10,72 @@ use crypto::{
Salt,
Password,
},
aes::{self, AesKey,},
};
use once_cell::sync::OnceCell;
/// Used to lazily generate a salt
pub struct SaltGen
{
salt: OnceCell<Salt>,
}
impl SaltGen
{
/// Create a new salt generator
pub fn new() -> Self
{
Self {salt:OnceCell::new()}
}
/// Get or generate the salt
#[inline] pub fn get(&self) -> &Salt
{
self.salt.get_or_init(|| Salt::random().expect("Failed to generate random salt")) //is panicking here desired? I think so
}
/// Is this instancce initialised?
#[inline] pub fn is_set(&self) -> bool
{
self.salt.get().is_some()
}
/// Get value if it is inisialised
#[inline] pub fn try_get(&self) -> Option<&Salt>
{
self.salt.get()
}
/// Set the salt to a specific value. Will panic if already set.
pub fn set(&self, with: Salt) -> &Salt
{
self.salt.set(with).unwrap_or_else(|e| panic!("Tried to set `SaltGen` salt multiple times. New value was {:?}", e));
unsafe {
self.salt.get_unchecked() // is initialised at this point
}
}
/// Consume into an instance of `Salt` if it has been initialised yet
#[inline] pub fn into_inner(self) -> Option<Salt>
{
self.salt.into_inner()
}
}
impl AsRef<Salt> for SaltGen
{
#[inline] fn as_ref(&self) -> &Salt
{
self.get()
}
}
impl std::ops::Deref for SaltGen
{
type Target = Salt;
#[inline] fn deref(&self) -> &Self::Target {
self.get()
}
}
///// The callback to get a derrived password
//pub trait PasswordFn: for<'r> FnOnce(&'r Salt) -> Option<Password>{}
@ -19,7 +84,7 @@ use crypto::{
pub trait TextSerialiseable: Sized
{
fn serialise_text<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized>(&'a self, out: &'b mut T, passwd: Option<&'b Password>) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>;
fn serialise_text<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized, F: for<'r> FnOnce(&'r SaltGen) -> Option<Password> + 'b>(&'a self, out: &'b mut T, passwd: F) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>;
fn deserialise_text<'a, T: AsyncBufRead+Unpin+?Sized, F: for<'r> FnOnce(&'r Salt) -> Option<Password> + 'a>(input: &'a mut T, passwd: F) -> LocalBoxFuture<'a, Result<Self, eyre::Report>>
where Self: 'a;
#[inline] fn size_hint(&self) -> (usize, Option<usize>)
@ -31,7 +96,7 @@ pub trait TextSerialiseable: Sized
pub trait BinarySerialisable: Sized
{
fn serialise_bytes<'a, 'b, T: AsyncWrite+Unpin+?Sized>(&'a self, out: &'b mut T, passwd: Option<&'b Password>) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
fn serialise_bytes<'a, 'b, T: AsyncWrite+Unpin+?Sized,F: for<'r> FnOnce(&'r SaltGen) -> Option<Password> + 'b>(&'a self, out: &'b mut T, passwd: F) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
where 'b: 'a;
fn deserialise_bytes<'b , T: AsyncRead+Unpin+?Sized, F: for<'r> FnOnce(&'r Salt) -> Option<Password> + 'b>(input: &'b mut T, passwd: F) -> LocalBoxFuture<'b, Result<Self, eyre::Report>>
where Self: 'b;
@ -51,8 +116,8 @@ pub trait Serialisable: BinarySerialisable + TextSerialiseable
///
/// # Notes
/// This function will fail if any `await`ed future within the `serialise_*` method cannot complete immediately.
#[instrument(skip(self))]
fn into_memory(&self, mode: Mode, passwd: Option<&Password>) -> Result<Vec<u8>, eyre::Report>
#[instrument(skip(self, passwd))]
fn into_memory<F: FnOnce(&SaltGen) -> Option<Password>>(&self, mode: Mode, passwd: F) -> Result<Vec<u8>, eyre::Report>
{
let mut output = match mode.size_hint(self)
{
@ -156,12 +221,30 @@ pub fn into_text<T: Serialize>(value: &T) -> Result<String, Error>
Ok(base64::encode(bytes))
}
/// Serialise this object into encrypted base64 text
///
/// # TODO
/// Line wrapping
#[instrument(err, skip(value), fields(value_type=?std::any::type_name::<T>()))]
pub async fn into_text_with_key_async<T: Serialize>(value: &T, k: &AesKey) -> Result<String, Error>
{
let bytes = serde_cbor::to_vec(value).map_err(Error::Serialise)?;
let mut output = Vec::with_capacity(bytes.len());
trace!("Encrypting stream");
let b = aes::encrypt_stream(k, &mut &bytes[..], &mut output).await.map_err(Error::Encryption)?;
trace!("Encrypted {} bytes (from {} -> {})", b, bytes.len(), output.len());
Ok(base64::encode(output))
}
#[derive(Debug)]
pub enum Error
{
Base64(base64::DecodeError),
Serialise(serde_cbor::Error),
Deserialise(serde_cbor::Error),
Encryption(aes::Error),
Decryption(aes::Error),
}
impl std::error::Error for Error
@ -171,6 +254,8 @@ impl std::error::Error for Error
Self::Base64(b) => Some(b),
Self::Serialise(b) => Some(b),
Self::Deserialise(b) => Some(b),
Self::Encryption(b) => Some(b),
Self::Decryption(b) => Some(b),
}
}
}
@ -183,6 +268,8 @@ impl std::fmt::Display for Error
Self::Base64(_) => write!(f, "base64 decode failed"),
Self::Serialise(_) => write!(f, "serialisation failed"),
Self::Deserialise(_) => write!(f, "deserialisation failed"),
Self::Encryption(_) => write!(f, "encryption failed"),
Self::Decryption(_) => write!(f, "decryption failed"),
}
}
}
@ -195,6 +282,19 @@ pub fn from_text<T: serde::de::DeserializeOwned>(string: impl AsRef<[u8]>) -> Re
serde_cbor::from_reader(&bytes[..]).map_err(Error::Deserialise)
}
/// Try to deserialise this encrypted object from text.
#[instrument(err, skip(string), fields(string = ?string.as_ref()))]
pub async fn from_text_with_key_async<T: serde::de::DeserializeOwned>(string: impl AsRef<[u8]>, k: &AesKey) -> Result<T, Error>
{
let bytes = base64::decode(string).map_err(Error::Base64)?;
let mut output = Vec::with_capacity(bytes.len());
trace!("Decrypting stream");
let b = aes::decrypt_stream(k, &mut &bytes[..], &mut output).await.map_err(Error::Decryption)?;
trace!("Decrypted {} bytes (from {} -> {})", b, bytes.len(), output.len());
serde_cbor::from_reader(&output[..]).map_err(Error::Deserialise)
}
#[cfg(test)]
mod tests
{

Loading…
Cancel
Save