You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

213 lines
7.0 KiB

//! AES key serialisation
use super::*;
use crypto::{
aes::{
self,
AesKey,
},
consts::{AES_IVSIZE, AES_KEYSIZE},
};
use eyre::eyre;
const PADDING_SZ: usize = AES_KEYSIZE + AES_IVSIZE;
fn new_padding() -> [u8; PADDING_SZ]
{
let mut buf = [0u8; PADDING_SZ];
getrandom::getrandom(&mut buf[..]).expect("Not enough entropy");
buf
}
/// Contains the body of an AES key
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct AesBody
{
key: AesKey,
garbage: [u8; PADDING_SZ],
}
impl AesBody
{
/// Compute the sha256 hash of this body instance
#[inline] pub fn compute_hash(&self) -> Sha256Hash
{
debug_assert_ne!(self.garbage, [0u8; PADDING_SZ], "Empty padding is unwise");
let mut cbuf = [0u8; PADDING_SZ + AES_KEYSIZE+ AES_IVSIZE];
bytes::copy_slice(&mut cbuf[..AES_KEYSIZE+ AES_IVSIZE], self.key.as_ref());
bytes::copy_slice(&mut cbuf[AES_KEYSIZE+AES_IVSIZE..], &self.garbage[..]);
crypto::sha256::compute_slice(cbuf)
}
/// Create a new body container from this key
pub fn new_key(key: AesKey) -> Self
{
Self { key, garbage: new_padding() }
}
/// Create a new body with a random key
pub fn new_random() -> Self
{
Self::new_key(AesKey::generate().expect("Not enough entropy"))
}
/// Create an empty, keyless body
///
/// # Important
/// This creates an instance with all 0 padding. Use `with_padding` or `give_padding` pls.
pub const fn empty() -> Self
{
Self { key: AesKey::empty(), garbage: [0u8; PADDING_SZ] }
}
/// Create a new instance with new padding
pub fn with_padding(self) -> Self
{
Self {
garbage: new_padding(),
..self
}
}
/// Give this body new padding
pub fn give_padding(&mut self)
{
//bytes::copy_slice(&mut self.garbage[..], &new_padding()[..]);
self.garbage = new_padding();
}
/// Consume into the internal aes key
pub fn into_key(self) -> AesKey
{
self.key
}
/// Get the internal body key
pub fn key(&self) -> &AesKey
{
&self.key
}
/// Get the internal body key
pub fn key_mut(&mut self) -> &mut AesKey
{
&mut self.key
}
/// Write an aes body to a binary stream
#[instrument(skip(out), err)]
pub async fn write_bytes<T: AsyncWrite+?Sized+Unpin>(&self, out: &mut T, ses_enc: &AesKey) -> Result<usize, eyre::Report>
{
if self.garbage == [0u8; PADDING_SZ] {
warn!("Writing empty-padded body");
}
let mut buf = [0u8; AES_KEYSIZE +AES_IVSIZE + PADDING_SZ];
bytes::copy_slice(&mut buf[..AES_KEYSIZE], self.key.k());
bytes::copy_slice(&mut buf[AES_KEYSIZE..], self.key.i());
bytes::copy_slice(&mut buf[AES_KEYSIZE+ AES_IVSIZE..], &self.garbage[..]);
let mut tbuf = Vec::with_capacity(buf.len()); //eh, i need to do calculating instead of these dumb temp buffers...
aes::encrypt_stream(ses_enc, &mut &buf[..], &mut tbuf).await
.wrap_err_with(|| eyre!("Failed to encrypt body stream with header key"))
.with_section(|| format!("{}", buf.fmt_view()).header("Body stream was"))
.with_section(|| ses_enc.to_string().header("Header key was"))?;
out.write_u64(try_usize!(<- tbuf.len())?).await?;
out.write_all(&tbuf[..]).await?;
Ok(8 + tbuf.len())
}
/// Read an aes body from a binary stream
#[instrument(skip(input), err)]
pub async fn read_bytes<T: AsyncRead+?Sized+Unpin>(input: &mut T, ses_enc: &AesKey) -> Result<Self, eyre::Report>
{
let sz = try_usize!(-> input.read_u64().await?)?;
let mut tbuf = vec![0u8; sz];
input.read_exact(&mut tbuf[..]).await?;
let mut buf = [0u8; AES_KEYSIZE + AES_IVSIZE + PADDING_SZ];
let mut cbuf = std::io::Cursor::new(&mut buf[..]);
let written = aes::decrypt_stream(ses_enc, &mut &tbuf[..], &mut cbuf).await
.wrap_err_with(|| eyre!("Failed to decrypt body stream with header key"))
.with_section(|| format!("{}", tbuf.fmt_view()).header("Body stream was"))
.with_section(|| ses_enc.to_string().header("Header key was"))?;
if written != buf.len() {
return Err(eyre::eyre!("Decrypted buffer length {} is not equal to expected AES key size {}", written, buf.len()))
.with_section(|| format!("{}", (&buf[..written]).fmt_view()).header("Decrypted buffer was"))
.with_note(|| "This likeley indicates bad decrypted data");
}
let mut key = AesKey::default();
bytes::copy_slice(key.k_mut(), &buf[..AES_KEYSIZE]);
bytes::copy_slice(key.i_mut(), &buf[AES_KEYSIZE..]);
let mut garbage = [0u8; PADDING_SZ];
bytes::copy_slice(&mut garbage[..], &buf[AES_KEYSIZE + AES_IVSIZE..]);
if garbage == [0u8; PADDING_SZ] {
warn!("Read empty-padded body");
}
Ok(Self{
key,
garbage,
})
}
/// Write an aes body to a text stream
#[instrument(err, skip(out))]
pub async fn write_text<T: AsyncWrite+Unpin+?Sized>(&self, out: &mut T, ses_enc: &AesKey) -> Result<usize, eyre::Report>
{
let text = serialise::into_text_with_key_async(self, ses_enc).await
.wrap_err_with(|| eyre!("Failed to serialise body to text"))
.with_section(|| self.key.to_string().header("Body was"))
.with_section(|| ses_enc.to_string().header("Header key was"))?;
let mut written = 0;
trace!("Writing whole {:?}", text);
for bytes in text.as_bytes().chunks(TEXT_CHUNK_SIZE) {
out.write_all(bytes).await?;
out.write_u8(b'\n').await?;
written += bytes.len() + 1;
}
Ok(written)
}
/// Read an AES body from a text stream
#[instrument(err, skip(input))]
pub async fn read_text<T: AsyncBufRead+Unpin+?Sized>(input: &mut T, ses_enc: &AesKey) -> Result<Self, eyre::Report>
{
let mut whole = String::new();
let mut buf = String::with_capacity(TEXT_CHUNK_SIZE);
loop {
match input.read_line(&mut buf).await? {
0 => break,
_ => {
whole.push_str(buf.trim());
buf.clear();
},
}
}
trace!("Read whole {:?}", whole);
Ok(serialise::from_text_with_key_async(&whole[..], ses_enc).await
.wrap_err_with(|| eyre!("Failed to deserialise body from text"))
.with_section(move|| whole.header("Body was"))
.with_section(|| ses_enc.to_string().header("Header key was"))?)
}
}
impl KeyBodySerialisable for AesBody
{
#[inline] fn serialise_text<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized>(&'a self, out: &'b mut T, ses_enc: &'b AesKey) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
{
self.write_text(out, ses_enc).boxed_local()
}
#[inline] fn serialise_bytes<'a, 'b: 'a, T: AsyncWrite+Unpin+?Sized>(&'a self, out: &'b mut T, ses_enc: &'b AesKey) -> LocalBoxFuture<'a, Result<usize, eyre::Report>>
{
self.write_bytes(out, ses_enc).boxed_local()
}
}
impl KeyBodyDeserialisable for AesBody
{
#[inline] fn deserialise_bytes<'a, T: AsyncBufRead+Unpin+?Sized>(input: &'a mut T, ses_enc: &'a AesKey) -> LocalBoxFuture<'a, Result<Self, eyre::Report>>
where Self: 'a
{
Self::read_bytes(input, ses_enc).boxed_local()
}
#[inline] fn deserialise_text<'a, T: AsyncBufRead+Unpin+?Sized>(input: &'a mut T, ses_enc: &'a AesKey) -> LocalBoxFuture<'a, Result<Self, eyre::Report>>
where Self: 'a
{
Self::read_text(input, ses_enc).boxed_local()
}
}