rsa private body

master
Avril 4 years ago
parent f24116ded9
commit b8d549bebb
Signed by: flanchan
GPG Key ID: 284488987C31F630

79
Cargo.lock generated

@ -179,6 +179,18 @@ dependencies = [
"tracing-error",
]
[[package]]
name = "config_struct"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aefd4a90b45fed157c31d107f8fdd9f8aaee79f0df625cefb773a9a1a10059f"
dependencies = [
"failure",
"linear-map",
"quote",
"toml",
]
[[package]]
name = "cpuid-bool"
version = "0.1.2"
@ -206,9 +218,9 @@ dependencies = [
[[package]]
name = "cryptohelpers"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "487ef8c0290bfb3137440389d02c638341b3cb944c39e475ed543584ec596f7c"
checksum = "2cfc491baaffd7cbd6acc02ebd23564760d83a2c17e1a47e6a04a8d5a86e7fb5"
dependencies = [
"crc",
"getrandom 0.1.15",
@ -242,6 +254,28 @@ dependencies = [
"once_cell",
]
[[package]]
name = "failure"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
dependencies = [
"backtrace",
"failure_derive",
]
[[package]]
name = "failure_derive"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -492,6 +526,16 @@ version = "0.2.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
[[package]]
name = "linear-map"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee"
dependencies = [
"serde",
"serde_test",
]
[[package]]
name = "log"
version = "0.4.11"
@ -780,6 +824,7 @@ dependencies = [
"cfg-if",
"chrono",
"color-eyre",
"config_struct",
"cryptohelpers",
"futures",
"getrandom 0.2.0",
@ -959,6 +1004,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_test"
version = "1.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "923edec3f1ab4a2f489f384e117dc4f826fd977a9d189b28717cba8474dd5c6b"
dependencies = [
"serde",
]
[[package]]
name = "sha2"
version = "0.9.1"
@ -1041,6 +1095,18 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "synstructure"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [
"proc-macro2",
"quote",
"syn",
"unicode-xid",
]
[[package]]
name = "thread_local"
version = "1.0.1"
@ -1096,6 +1162,15 @@ dependencies = [
"syn",
]
[[package]]
name = "toml"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
dependencies = [
"serde",
]
[[package]]
name = "tracing"
version = "0.1.19"

@ -19,7 +19,7 @@ local-time = []
[dependencies]
color-eyre = "0.5.3"
lazy_static = "1.4.0"
crypto = {package= "cryptohelpers", version = "1.5.0", features=["full", "async", "serialise"]}
crypto = {package= "cryptohelpers", version = "1.5.1", features=["full", "async", "serialise"]}
cfg-if = "0.1.10"
tokio = {version = "0.2", features=["full"]}
serde = {version ="1.0.116", features=["derive"]}

@ -1,9 +1,10 @@
//! RSA key serialisation
use super::*;
use crypto::{aes, rsa};
use crypto::{aes, rsa, password::{Password,}};
use eyre::eyre;
const PADDING_SZ: usize = 16;
#[instrument]
fn new_padding() -> [u8; PADDING_SZ]
{
let mut buf = [0u8; PADDING_SZ];
@ -16,7 +17,7 @@ fn new_padding() -> [u8; PADDING_SZ]
pub enum RsaBody
{
Public(RsaPublicBody),
Private(!)
Private(RsaPrivateBody)
}
impl RsaBody
@ -29,10 +30,14 @@ impl RsaBody
}
}
/// Write this RSA key body to a PEM string
pub fn to_pem_string(&self) -> eyre::Result<String>
///
/// # Notes
/// Password is only applicable with Private keys
pub fn to_pem_string(&self, passwd: Option<&Password>) -> eyre::Result<String>
{
match self {
Self::Public(public) => public.to_pem_string(),
Self::Private(private) => private.to_pem_string(passwd),
}
.wrap_err_with(|| eyre!("Failed to write RSA key body to PEM string"))
.with_section(|| self.kind_name().header("Kind was"))
@ -64,6 +69,7 @@ impl RsaBody
{
match self {
Self::Public(public) => public.write_bytes(out, ses_enc).await,
Self::Private(private) => private.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"))
@ -75,6 +81,7 @@ impl RsaBody
{
match self {
Self::Public(public) => public.write_text(out, ses_enc).await,
Self::Private(private) => private.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"))
@ -95,3 +102,6 @@ impl KeyBodySerialisable for RsaBody
mod public;
pub use public::*;
mod private;
pub use private::*;

@ -0,0 +1,187 @@
//! RSA Private key serialisation
use super::*;
/// A container of RSA private key
#[derive(Debug, Serialize, Deserialize)]
pub struct RsaPrivateBody
{
garbage: [u8; PADDING_SZ],
key: rsa::RsaPrivateKey,
}
impl RsaPrivateBody
{
/// Create a new body container from this RSA private key
pub fn new_key(key: rsa::RsaPrivateKey) -> Self
{
Self {
garbage: new_padding(),
key,
}
}
/// Create an instace of public body from the public parts of this private key
pub fn get_public(&self) -> RsaPublicBody
{
RsaPublicBody::new_key(self.key.get_public_parts())
}
/// 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::RsaPrivateKey
{
self.key
}
/// The internal key
pub fn key(&self) -> &rsa::RsaPrivateKey
{
&self.key
}
/// Mutable reference to the internal key
pub fn key_mut(&mut self) -> &mut rsa::RsaPrivateKey
{
&mut self.key
}
/// Write this body's key to a PEM string
pub fn to_pem_string(&self, pw: Option<&Password>) -> eyre::Result<String>
{
self.key.to_pem(pw)
.wrap_err_with(|| eyre!("Failed to write private 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<F: FnOnce() -> Option<Password>>(pem: impl AsRef<str>, pw: F) -> eyre::Result<Self>
{
let pem = pem.as_ref();
Ok(Self::new_key(rsa::RsaPrivateKey::from_pem(pem, pw)
.wrap_err_with(|| eyre!("Failed to read private key body from PEM string"))
.with_section(|| pem.to_owned().header("PEM string was"))?))
}
/// Write RSA private 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 private 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::RsaPrivateKey::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 private 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 private 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 RsaPrivateBody
{
#[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 RsaPrivateBody
{
#[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…
Cancel
Save