parent
f996d34bdf
commit
def20d1e22
@ -0,0 +1,97 @@
|
|||||||
|
//! RSA key serialisation
|
||||||
|
use super::*;
|
||||||
|
use crypto::{aes, rsa};
|
||||||
|
use eyre::eyre;
|
||||||
|
const PADDING_SZ: usize = 16;
|
||||||
|
|
||||||
|
fn new_padding() -> [u8; PADDING_SZ]
|
||||||
|
{
|
||||||
|
let mut buf = [0u8; PADDING_SZ];
|
||||||
|
getrandom::getrandom(&mut buf[..]).expect("Not enough entropy");
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An RSA key body
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum RsaBody
|
||||||
|
{
|
||||||
|
Public(RsaPublicBody),
|
||||||
|
Private(!)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RsaBody
|
||||||
|
{
|
||||||
|
#[cold] fn kind_name(&self) -> &'static str
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Public(_) => "Public",
|
||||||
|
Self::Private(_) => "Private",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Write this RSA key body to a PEM string
|
||||||
|
pub fn to_pem_string(&self) -> eyre::Result<String>
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Public(public) => public.to_pem_string(),
|
||||||
|
}
|
||||||
|
.wrap_err_with(|| eyre!("Failed to write RSA key body to PEM string"))
|
||||||
|
.with_section(|| self.kind_name().header("Kind was"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this key a public part
|
||||||
|
pub fn is_public(&self) -> bool
|
||||||
|
{
|
||||||
|
if let Self::Public(_) = self {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this key a private part
|
||||||
|
pub fn is_private(&self) -> bool
|
||||||
|
{
|
||||||
|
if let Self::Private(_) = self {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write RSA body to a binary stream
|
||||||
|
#[instrument(skip(out))]
|
||||||
|
pub async fn write_bytes<T: AsyncWrite+?Sized+Unpin>(&self, out: &mut T, ses_enc: &AesKey) -> Result<usize, eyre::Report>
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Public(public) => public.write_bytes(out, ses_enc).await,
|
||||||
|
}
|
||||||
|
.wrap_err_with(|| eyre!("Failed to write RSA key body to binary stream"))
|
||||||
|
.with_section(|| self.kind_name().header("Kind was"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write an RSA body to a text stream
|
||||||
|
#[instrument(skip(out))]
|
||||||
|
pub async fn write_text<T: AsyncWrite+Unpin+?Sized>(&self, out: &mut T, ses_enc: &AesKey) -> Result<usize, eyre::Report>
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Public(public) => public.write_text(out, ses_enc).await,
|
||||||
|
}
|
||||||
|
.wrap_err_with(|| eyre!("Failed to write RSA key body to text stream"))
|
||||||
|
.with_section(|| self.kind_name().header("Kind was"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyBodySerialisable for RsaBody
|
||||||
|
{
|
||||||
|
#[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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod public;
|
||||||
|
pub use public::*;
|
@ -0,0 +1,179 @@
|
|||||||
|
//! RSA public key serialisation
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// A container of RSA public key
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct RsaPublicBody
|
||||||
|
{
|
||||||
|
garbage: [u8; PADDING_SZ],
|
||||||
|
key: rsa::RsaPublicKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RsaPublicBody
|
||||||
|
{
|
||||||
|
/// Create a new body container from this RSA public key
|
||||||
|
pub fn new_key(key: rsa::RsaPublicKey) -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
garbage: new_padding(),
|
||||||
|
key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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)
|
||||||
|
{
|
||||||
|
self.garbage = new_padding();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume into the internal key
|
||||||
|
pub fn into_key(self) -> rsa::RsaPublicKey
|
||||||
|
{
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The internal key
|
||||||
|
pub fn key(&self) -> &rsa::RsaPublicKey
|
||||||
|
{
|
||||||
|
&self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mutable reference to the internal key
|
||||||
|
pub fn key_mut(&mut self) -> &mut rsa::RsaPublicKey
|
||||||
|
{
|
||||||
|
&mut self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write this body's key to a PEM string
|
||||||
|
pub fn to_pem_string(&self) -> eyre::Result<String>
|
||||||
|
{
|
||||||
|
self.key.to_pem()
|
||||||
|
.wrap_err_with(|| eyre!("Failed to write public key body to PEM string"))
|
||||||
|
.with_section(|| format!("{:?}", self.key).header("Key body data was"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read this body from a PEM string encoded key
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
/// This creates new padding for the returned body
|
||||||
|
pub fn from_pem(pem: impl AsRef<str>) -> eyre::Result<Self>
|
||||||
|
{
|
||||||
|
let pem = pem.as_ref();
|
||||||
|
Ok(Self::new_key(rsa::RsaPublicKey::from_pem(pem)
|
||||||
|
.wrap_err_with(|| eyre!("Failed to read public key body from PEM string"))
|
||||||
|
.with_section(|| pem.to_owned().header("PEM string was"))?))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write RSA public 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: Vec<u8> = self.key.to_bytes();
|
||||||
|
buf.extend_from_slice(&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 RSA public 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 output = Vec::with_capacity(tbuf.len());
|
||||||
|
|
||||||
|
aes::decrypt_stream(ses_enc, &mut &tbuf[..], &mut output).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 output.len() < PADDING_SZ {
|
||||||
|
return Err(eyre!("Padding is invalid"))
|
||||||
|
.with_section(|| tbuf.to_view_string().header("Decrypted body stream was"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut garbage = [0u8; PADDING_SZ];
|
||||||
|
bytes::copy_slice(&mut garbage[..], &output[output.len()-PADDING_SZ..]);
|
||||||
|
|
||||||
|
let key = rsa::RsaPublicKey::from_bytes(&output[..output.len()-PADDING_SZ])
|
||||||
|
.wrap_err_with(|| eyre!("Failed to instantiate key from body"))
|
||||||
|
.with_section(|| tbuf.to_view_string().header("Decrypted body stream was"))?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
key, garbage
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Write an RSA public 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(|| format!("{:?}", self.key).header("Body key was"))
|
||||||
|
.with_section(|| ses_enc.to_string().header("Header key was"))?;
|
||||||
|
|
||||||
|
Ok(write_chunked_text!(out, text))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read an RSA public 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 whole = read_chunked_text!(input);
|
||||||
|
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 RsaPublicBody
|
||||||
|
{
|
||||||
|
#[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 RsaPublicBody
|
||||||
|
{
|
||||||
|
#[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()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue