parent
f324132f18
commit
439663539b
@ -0,0 +1,177 @@
|
||||
//! 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 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()[..]);
|
||||
}
|
||||
/// 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(32);
|
||||
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"))?)
|
||||
}
|
||||
}
|
Loading…
Reference in new issue