From f6be53890f7357abe97b3cefe29f6ab1f60e37b7 Mon Sep 17 00:00:00 2001 From: Avril Date: Tue, 25 Aug 2020 23:52:06 +0100 Subject: [PATCH] working~ --- Cargo.toml | 4 +- src/bytes.rs | 24 +++ src/consts.rs | 18 +- src/error/mod.rs | 2 + src/error/rsa.rs | 103 ++++++++++ src/lib.rs | 7 +- src/rsa/components.rs | 67 +++++++ src/rsa/containers.rs | 100 +++++++++ src/rsa/crypt.rs | 226 +++++++++++++++++++++ src/rsa/mod.rs | 37 ++++ src/rsa/offsets.rs | 109 ++++++++++ src/rsa/private.rs | 402 +++++++++++++++++++++++++++++++++++++ src/rsa/private_offsets.rs | 78 +++++++ src/rsa/public.rs | 320 +++++++++++++++++++++++++++++ src/rsa/public_offsets.rs | 37 ++++ src/rsa/sign.rs | 255 +++++++++++++++++++++++ 16 files changed, 1786 insertions(+), 3 deletions(-) create mode 100644 src/error/rsa.rs create mode 100644 src/rsa/components.rs create mode 100644 src/rsa/containers.rs create mode 100644 src/rsa/crypt.rs create mode 100644 src/rsa/mod.rs create mode 100644 src/rsa/offsets.rs create mode 100644 src/rsa/private.rs create mode 100644 src/rsa/private_offsets.rs create mode 100644 src/rsa/public.rs create mode 100644 src/rsa/public_offsets.rs create mode 100644 src/rsa/sign.rs diff --git a/Cargo.toml b/Cargo.toml index b9b802e..67a344f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,13 +27,15 @@ full = [ "sha256", "password", "aes", - "checksum" + "checksum", + "rsa" ] sha256 = ["sha2"] password = ["sha256", "pbkdf2", "hex-literal", "hmac", "getrandom"] aes = ["openssl", "getrandom"] checksum = ["crc"] +rsa = ["openssl", "password"] [build-dependencies] rustc_version = "0.2" diff --git a/src/bytes.rs b/src/bytes.rs index 4233c19..4e42840 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -46,3 +46,27 @@ pub fn refer_mut(value: &mut T) -> &mut [u8] slice::from_raw_parts_mut(value as *mut T as *mut u8, mem::size_of_val(value)) } } + +/// Get a type from its bytes +/// +/// # Notes +/// This function omits bounds checks in production builds +pub fn derefer(bytes: &[u8]) -> &T +{ + #[cfg(debug_assertions)] assert!(bytes.len() >= mem::size_of::(), "not enough bytes "); + unsafe { + &*(&bytes[0] as *const u8 as *const T) + } +} + +/// Get a mutable reference to a type from its bytes +/// +/// # Notes +/// This function omits bounds checks in production builds +pub fn derefer_mut(bytes: &mut [u8]) -> &mut T +{ + #[cfg(debug_assertions)] assert!(bytes.len() >= mem::size_of::(), "not enough bytes "); + unsafe { + &mut *(&mut bytes[0] as *mut u8 as *mut T) + } +} diff --git a/src/consts.rs b/src/consts.rs index c6fbfa1..d61119f 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,4 +1,7 @@ -//! Constants +//! Constants used throughout +//! +//! # Notes +//! Probably best to not change these unless you know what you're doing. /// Default buffer size for most things pub const BUFFER_SIZE: usize = 4096; @@ -20,3 +23,16 @@ pub const AES_KEYSIZE: usize = 16; /// Aes IV size in bytes pub const AES_IVSIZE: usize = 16; + +/// The number of bits used for RSA key +pub const RSA_KEY_BITS: u32 = 4096; + +/// Size of an RSA signature +pub const RSA_SIG_SIZE: usize = 512; + +/// The number of bytes the RSA padding requires +pub const RSA_PADDING_NEEDS: usize = 11; + +/// The padding used for RSA operations +#[cfg(feature="rsa")] +pub const RSA_PADDING: openssl::rsa::Padding = openssl::rsa::Padding::PKCS1; diff --git a/src/error/mod.rs b/src/error/mod.rs index 173a100..81f3291 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -7,3 +7,5 @@ use std::{ pub mod password; #[cfg(feature="aes")] pub mod aes; +#[cfg(feature="rsa")] +pub mod rsa; diff --git a/src/error/rsa.rs b/src/error/rsa.rs new file mode 100644 index 0000000..2e7ae5f --- /dev/null +++ b/src/error/rsa.rs @@ -0,0 +1,103 @@ +//! RSA errors +use std::{ + fmt, + io, + error, + num::TryFromIntError, +}; +use openssl::{ + error::ErrorStack, +}; + +/// Binary error reason +#[derive(Debug)] +pub enum BinaryErrorKind { + Unknown, + Length{expected: Option, got: Option}, + Corruption, +} + +/// Represents an error for RSA operations +#[derive(Debug)] +pub enum Error { + Encrypt, + Decrypt, + + Integer, + Key, + Password, + PEM, + Binary(BinaryErrorKind), + Utf8, + OpenSSLInternal(ErrorStack), + IO(io::Error), + Unknown, +} + +impl error::Error for Error +{ + fn source(&self) -> Option<&(dyn error::Error + 'static)> + { + Some(match &self { + Self::IO(io) => io, + Self::OpenSSLInternal(ssl) => ssl, + _ => return None, + }) + } +} +impl std::fmt::Display for Error +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self { + Self::Encrypt => write!(f, "encryption failed"), + Self::Decrypt => write!(f, "decryption failed"), + Self::Integer => write!(f, "integer operation exceeded bounds (overflow/underflow)"), + Self::Key => write!(f, "invalid key"), + Self::Password => write!(f, "a password is needed but none was provided"), + Self::PEM => write!(f, "invalid PEM string"), + Self::Binary(BinaryErrorKind::Length{expected: Some(expected), got: Some(got)}) => write!(f, "invalid binary representation: bad length (expected {} got {})", expected, got), + Self::Binary(BinaryErrorKind::Length{expected: Some(expected), ..}) => write!(f, "invalid binary representation: bad length (expected {})", expected), + Self::Binary(BinaryErrorKind::Length{got: Some(got), ..}) => write!(f, "invalid binary representation: bad length (got {})", got), + Self::Binary(BinaryErrorKind::Length{..}) => write!(f, "invalid binary representation: bad length"), + Self::Binary(BinaryErrorKind::Corruption) => write!(f, "invalid binary representation: corrupted data"), + Self::Binary(_) => write!(f, "invalid binary representation"), + Self::Utf8 => write!(f, "text contained invalid utf8"), + Self::IO(io) => write!(f, "i/o error: {}", io), + Self::OpenSSLInternal(ssl) => write!(f, "openssl error: {}", ssl), + _ => write!(f, "unknown error"), + } + } +} + +impl From for Error +{ + #[inline] fn from(from: ErrorStack) -> Self + { + Self::OpenSSLInternal(from) + } +} + +impl From for Error +{ + fn from(from: io::Error) -> Self + { + Self::IO(from) + } +} + +impl From for Error +{ + fn from(_: std::str::Utf8Error) -> Self + { + Self::Utf8 + } +} + +impl From for Error +{ + fn from(_: TryFromIntError) -> Self + { + Self::Integer + } +} diff --git a/src/lib.rs b/src/lib.rs index 76def3a..10712fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,13 @@ #![allow(dead_code)] -mod consts; +pub mod consts; +#[allow(unused_imports)] use consts::*; pub mod util; pub mod bytes; +#[allow(unused_imports)] mod error; // Actual things @@ -18,3 +20,6 @@ pub mod password; pub mod aes; #[cfg(feature="checksum")] pub mod crc; + +#[cfg(feature="rsa")] +pub mod rsa; diff --git a/src/rsa/components.rs b/src/rsa/components.rs new file mode 100644 index 0000000..d578b15 --- /dev/null +++ b/src/rsa/components.rs @@ -0,0 +1,67 @@ +//! Traits for objects with RSA key components +use openssl::{ + bn::BigNum, +}; +pub trait HasComponents +{ + fn raw(&self) -> &[u8]; +} + +pub trait HasPublicComponents: HasComponents +{ + fn e(&self) -> &[u8]; + fn n(&self) -> &[u8]; + + /// Get the modulus component as a new `BigNum`. + /// + /// # Notes + /// This can panic if the internal state of the instance is incorrect + #[inline] fn num_n(&self) -> BigNum + { + BigNum::from_slice(self.n()).unwrap() //we assume things like this succeed because we assume the internal stat is consistant + } + + /// Get the exponent component as a new `BigNum` + /// + /// # Notes + /// This can panic if the internal state of the instance is incorrect + #[inline] fn num_e(&self) -> BigNum + { + BigNum::from_slice(self.n()).unwrap() + } +} + +pub trait HasPrivateComponents: HasPublicComponents +{ + fn d(&self) -> &[u8]; + fn p(&self) -> &[u8]; + fn q(&self) -> &[u8]; + fn dmp1(&self) -> &[u8]; + fn dmq1(&self) -> &[u8]; + fn iqmp(&self) -> &[u8]; + + #[inline] fn num_d(&self) -> BigNum + { + BigNum::from_slice(self.d()).unwrap() + } + #[inline] fn num_p(&self) -> BigNum + { + BigNum::from_slice(self.p()).unwrap() + } + #[inline] fn num_q(&self) -> BigNum + { + BigNum::from_slice(self.q()).unwrap() + } + #[inline] fn num_dmp1(&self) -> BigNum + { + BigNum::from_slice(self.dmp1()).unwrap() + } + #[inline] fn num_dmq1(&self) -> BigNum + { + BigNum::from_slice(self.dmq1()).unwrap() + } + #[inline] fn num_iqmp(&self) -> BigNum + { + BigNum::from_slice(self.iqmp()).unwrap() + } +} diff --git a/src/rsa/containers.rs b/src/rsa/containers.rs new file mode 100644 index 0000000..1f65c75 --- /dev/null +++ b/src/rsa/containers.rs @@ -0,0 +1,100 @@ +//! Traits for the key containers +use std::{ + borrow::Cow, + error, + convert::Infallible, +}; +use openssl::{ + pkey::{ + HasPublic, + HasPrivate, + PKey, + }, + rsa::{ + Rsa, + }, +}; + +/// A trait for containers that contain public keys +pub trait PublicKey +{ + /// The type of the key + type KeyType: HasPublic; + /// Error that can happen from the conversion + type Error: error::Error; + /// Get or create a `PKey` that contains the public key + fn get_pkey_pub(&self) -> Result>, Self::Error>; + + /// Get or create an `Rsa` from this public key if possible + fn get_rsa_pub(&self) -> Result>>, Self::Error> + { + Ok(self.get_pkey_pub()?.rsa().ok().map(|x| Cow::Owned(x))) + } +} + +/// A trait for containers that contain private and public keys +pub trait PrivateKey: PublicKey +where ::KeyType: HasPrivate +{ + /// Get or create a `PKey` that contains the private key + #[inline] fn get_pkey_priv(&self) -> Result::KeyType>>, ::Error> + { + self.get_pkey_pub() + } + /// Get or create an `Rsa` from this private key if possible + #[inline] fn get_rsa_priv(&self) -> Result>>, Self::Error> + { + self.get_rsa_pub() + } +} + +impl PublicKey for PKey +where T: HasPublic +{ + type KeyType = T; + type Error = Infallible; + fn get_pkey_pub(&self) -> Result>, Self::Error> + { + Ok(Cow::Borrowed(self)) + } +} + +impl PrivateKey for PKey +where T: HasPrivate +{ + fn get_pkey_priv(&self) -> Result::KeyType>>, ::Error> + { + Ok(Cow::Borrowed(self)) + } +} + +impl PublicKey for Rsa +where T: HasPublic +{ + type KeyType = T; + type Error = openssl::error::ErrorStack; + + fn get_pkey_pub(&self) -> Result>, Self::Error> + { + Ok(Cow::Owned(PKey::from_rsa(self.clone())?)) + } + + #[inline] fn get_rsa_pub(&self) -> Result>>, Self::Error> + { + Ok(Some(Cow::Borrowed(self))) + } +} + +impl PrivateKey for Rsa +where T: HasPrivate +{ + fn get_pkey_priv(&self) -> Result::KeyType>>, ::Error> + { + Ok(Cow::Owned(PKey::from_rsa(self.clone())?)) + } + + #[inline] fn get_rsa_priv(&self) -> Result>>, Self::Error> + { + Ok(Some(Cow::Borrowed(self))) + } +} diff --git a/src/rsa/crypt.rs b/src/rsa/crypt.rs new file mode 100644 index 0000000..87cb1d0 --- /dev/null +++ b/src/rsa/crypt.rs @@ -0,0 +1,226 @@ +//! Crypto transforms +use super::*; +#[allow(unused_imports)] +use std::{ + convert::TryFrom, + marker::Unpin, + io::{ + Write, + Read, + }, +}; +use openssl::{ + pkey::HasPrivate, +}; +#[cfg(feature="async")] +use tokio::{ + io::{ + AsyncWrite, + AsyncRead, + }, + prelude::*, +}; + +use consts::RSA_PADDING_NEEDS as PADDING_NEEDS; + +/// Encrypt a slice `data` to a new output vector with key `key` +pub fn encrypt_slice_to_vec(data: T, key: &K) -> Result, Error> +where T: AsRef<[u8]>, + K: PublicKey + ?Sized, +{ + let data = data.as_ref(); + let mut output = Vec::with_capacity(data.len()); + encrypt_slice_sync(data, key, &mut output)?; + Ok(output) +} + +/// Decrypt a slice `data` to a new output vector with key `key` +pub fn decrypt_slice_to_vec(data: T, key: &K) -> Result, Error> +where T: AsRef<[u8]>, + K: PrivateKey + ?Sized, +::KeyType: HasPrivate, +{ + let data = data.as_ref(); + let mut output = Vec::with_capacity(data.len()); + decrypt_slice_sync(data, key, &mut output)?; + Ok(output) +} + +/// Encrypt a stream `data` into `output` with `key`. Return the number of bytes *read*. +#[cfg(feature="async")] +pub async fn encrypt(data: &mut T, key: &K, output: &mut U) -> Result +where T: AsyncRead + Unpin + ?Sized, + K: PublicKey + ?Sized, + U: AsyncWrite + Unpin + ?Sized +{ + let key = key.get_rsa_pub().map_err(|_| Error::Key)?.ok_or(Error::Key)?; + let key_size = usize::try_from(key.size())?; + + let max_size = key_size - PADDING_NEEDS; + + let mut read_buffer = vec![0u8; max_size]; + let mut crypt_buffer = vec![0u8; key_size]; + + let mut read; + let mut done=0; + while {read = data.read(&mut read_buffer[..]).await?; read!=0} { + done+=read; + read = key.public_encrypt(&read_buffer[..read], &mut crypt_buffer[..], PADDING).map_err(|_| Error::Encrypt)?; + output.write_all(&crypt_buffer[..read]).await?; + } + + Ok(done) +} + +/// Encrypt a slice `data` into `output` with `key`. Return the number of bytes *written*. +#[cfg(feature="async")] +pub async fn encrypt_slice(data: T, key: &K, output: &mut U) -> Result +where T: AsRef<[u8]>, + K: PublicKey + ?Sized, + U: AsyncWrite + Unpin + ?Sized +{ + let key = key.get_rsa_pub().map_err(|_| Error::Key)?.ok_or(Error::Key)?; + let key_size = usize::try_from(key.size())?; + + let mut crypt_buffer = vec![0u8; key_size]; + + let read = key.public_encrypt(data.as_ref(), &mut crypt_buffer[..], PADDING).map_err(|_| Error::Encrypt)?; + output.write_all(&crypt_buffer[..read]).await?; + + Ok(read) +} +/// Encrypt a stream `data` into `output` with `key`. Return the number of bytes *read*. +pub fn encrypt_sync(data: &mut T, key: &K, output: &mut U) -> Result +where T: Read + ?Sized, + K: PublicKey + ?Sized, + U: Write + ?Sized +{ + let key = key.get_rsa_pub().map_err(|_| Error::Key)?.ok_or(Error::Key)?; + let key_size = usize::try_from(key.size())?; + + let max_size = key_size - PADDING_NEEDS; + + let mut read_buffer = vec![0u8; max_size]; + let mut crypt_buffer = vec![0u8; key_size]; + + let mut read; + let mut done=0; + while {read = data.read(&mut read_buffer[..])?; read!=0} { + done+=read; + read = key.public_encrypt(&read_buffer[..read], &mut crypt_buffer[..], PADDING).map_err(|_| Error::Encrypt)?; + output.write_all(&crypt_buffer[..read])?; + } + + Ok(done) +} + +/// Encrypt a slice `data` into `output` with `key`. Return the number of bytes *written*. +pub fn encrypt_slice_sync(data: T, key: &K, output: &mut U) -> Result +where T: AsRef<[u8]>, + K: PublicKey + ?Sized, + U: Write + ?Sized +{ + let key = key.get_rsa_pub().map_err(|_| Error::Key)?.ok_or(Error::Key)?; + let key_size = usize::try_from(key.size())?; + + let mut crypt_buffer = vec![0u8; key_size]; + + let read = key.public_encrypt(data.as_ref(), &mut crypt_buffer[..], PADDING).map_err(|_| Error::Encrypt)?; + output.write_all(&crypt_buffer[..read])?; + + Ok(read) +} + +/// Decrypt slice `data` into `output` with `key`. Return the number of bytes *written*. +#[cfg(feature="async")] +pub async fn decrypt_slice(data: T, key: &K, output: &mut U) -> Result +where T: AsRef<[u8]>, + K: PrivateKey + ?Sized, + U: AsyncWrite + Unpin + ?Sized, +::KeyType: HasPrivate, +{ + + let key = key.get_rsa_priv().map_err(|_| Error::Key)?.ok_or(Error::Key)?; + let key_size = usize::try_from(key.size())?; + + let mut crypt_buffer = vec![0u8; key_size]; + + let read = key.private_decrypt(data.as_ref(), &mut crypt_buffer[..], PADDING).map_err(|_| Error::Decrypt)?; + output.write_all(&crypt_buffer[..read]).await?; + + Ok(read) +} + +/// Decrypt a stream `data` into `output` with `key`. Return the number of bytes *read*. +#[cfg(feature="async")] +pub async fn decrypt(data: &mut T, key: &K, output: &mut U) -> Result +where T: AsyncRead + Unpin + ?Sized, + K: PrivateKey + ?Sized, + U: AsyncWrite + Unpin + ?Sized, +::KeyType: HasPrivate, +{ + let key = key.get_rsa_priv().map_err(|_| Error::Key)?.ok_or(Error::Key)?; + let key_size = usize::try_from(key.size())?; + + let max_size = key_size - PADDING_NEEDS; + + let mut read_buffer = vec![0u8; max_size]; + let mut crypt_buffer = vec![0u8; key_size]; + + let mut read; + let mut done=0; + while {read = data.read(&mut read_buffer[..]).await?; read!=0} { + done+=read; + read = key.private_decrypt(&read_buffer[..read], &mut crypt_buffer[..], PADDING).map_err(|_| Error::Decrypt)?; + output.write_all(&crypt_buffer[..read]).await?; + } + + Ok(done) + +} + +/// Decrypt slice `data` into `output` with `key`. Return the number of bytes *written*. +pub fn decrypt_slice_sync(data: T, key: &K, output: &mut U) -> Result +where T: AsRef<[u8]>, + K: PrivateKey + ?Sized, + U: Write + ?Sized, +::KeyType: HasPrivate, +{ + + let key = key.get_rsa_priv().map_err(|_| Error::Key)?.ok_or(Error::Key)?; + let key_size = usize::try_from(key.size())?; + + let mut crypt_buffer = vec![0u8; key_size]; + + let read = key.private_decrypt(data.as_ref(), &mut crypt_buffer[..], PADDING).map_err(|_| Error::Decrypt)?; + output.write_all(&crypt_buffer[..read])?; + + Ok(read) +} + +/// Decrypt a stream `data` into `output` with `key`. Return the number of bytes *read*. +pub fn decrypt_sync(data: &mut T, key: &K, output: &mut U) -> Result +where T: Read + ?Sized, + K: PrivateKey + ?Sized, + U: Write + ?Sized, +::KeyType: HasPrivate, +{ + let key = key.get_rsa_priv().map_err(|_| Error::Key)?.ok_or(Error::Key)?; + let key_size = usize::try_from(key.size())?; + + let max_size = key_size - PADDING_NEEDS; + + let mut read_buffer = vec![0u8; max_size]; + let mut crypt_buffer = vec![0u8; key_size]; + + let mut read; + let mut done=0; + while {read = data.read(&mut read_buffer[..])?; read!=0} { + done+=read; + read = key.private_decrypt(&read_buffer[..read], &mut crypt_buffer[..], PADDING).map_err(|_| Error::Decrypt)?; + output.write_all(&crypt_buffer[..read])?; + } + + Ok(done) + +} diff --git a/src/rsa/mod.rs b/src/rsa/mod.rs new file mode 100644 index 0000000..6061d8b --- /dev/null +++ b/src/rsa/mod.rs @@ -0,0 +1,37 @@ +//! RSA related thingies +use super::*; + +use consts::RSA_PADDING as PADDING; + +mod containers; +pub use containers::*; + +mod offsets; +mod public_offsets; +mod private_offsets; + +mod components; +pub use components::*; + +macro_rules! component { + ($self:tt -> $t:tt) => (&$self.data[$self.offset_starts.$t()..($self.offset_starts.$t()+$self.offset.$t())]) +} + +macro_rules! number { + (? $self:tt -> $c:tt) => (openssl::bn::BigNum::from_slice($self.$c())?); + ($self:tt -> $c:tt) => (openssl::bn::BigNum::from_slice($self.$c()).unwrap()); +} + +mod public; +pub use public::*; + +mod private; +pub use private::*; + +mod sign; +pub use sign::*; + +mod crypt; +pub use crypt::*; + +pub use crate::error::rsa::*; diff --git a/src/rsa/offsets.rs b/src/rsa/offsets.rs new file mode 100644 index 0000000..0471e50 --- /dev/null +++ b/src/rsa/offsets.rs @@ -0,0 +1,109 @@ +//! Traits for offsets of components + +pub struct Starts(T); + +pub trait HasOffsets: Sized +{ + fn starts(&self) -> Starts; + fn body_len(&self) -> usize; +} +pub trait HasPublicOffsets: HasOffsets +{ + fn n(&self) -> usize; + fn e(&self) -> usize; +} +pub trait HasPrivateOffsets: HasPublicOffsets { + fn d(&self) -> usize; + fn p(&self) -> usize; + fn q(&self) -> usize; + fn dmp1(&self) -> usize; + fn dmq1(&self) -> usize; + fn iqmp(&self) -> usize; +} + +pub use super::public_offsets::PublicOffsetGroup; +pub use super::private_offsets::PrivateOffsetGroup; + +impl Starts +where T: HasPublicOffsets +{ + pub fn n(&self) -> usize + { + self.0.n() + } + pub fn e(&self) -> usize + { + self.0.e() + } +} + +impl From for Starts +where T: HasPublicOffsets +{ + fn from(from: T) -> Self + { + Self(from) + } +} + +impl Starts +where T: HasPrivateOffsets +{ + pub fn d(&self) -> usize + { + self.0.d() + } + pub fn p(&self) -> usize + { + self.0.p() + } + pub fn q(&self) -> usize + { + self.0.q() + } + pub fn dmp1(&self) -> usize + { + self.0.dmp1() + } + pub fn dmq1(&self) -> usize + { + self.0.dmq1() + } + pub fn iqmp(&self) -> usize + { + self.0.iqmp() + } +} + +// Bullshit +use std::{ + cmp::{ + PartialEq,Eq, + }, + hash::{ + Hash,Hasher, + }, + fmt::{ + self, + Debug, + }, +}; +impl Copy for Starts where T: Copy + HasOffsets{} +impl Clone for Starts where T: Clone + HasOffsets{#[inline] fn clone(&self) -> Self {Self(self.0.clone())}} +impl Eq for Starts where T: Eq + HasOffsets{} +impl PartialEq for Starts where T: PartialEq + HasOffsets{#[inline] fn eq(&self, other: &Self) -> bool {self.0 == other.0}} +impl Hash for Starts +where T: Hash + HasOffsets +{ + #[inline] fn hash(&self, state: &mut H) { + self.0.hash(state) + } +} +impl Debug for Starts + where T: HasOffsets + Debug +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "Starts ({:?})", self.0) + } +} diff --git a/src/rsa/private.rs b/src/rsa/private.rs new file mode 100644 index 0000000..9c7f0e3 --- /dev/null +++ b/src/rsa/private.rs @@ -0,0 +1,402 @@ +//! Private key components +use super::*; +use offsets::*; +use crate::password::{ + Password, +}; +#[allow(unused_imports)] +use std::{ + borrow::{ + Borrow, + Cow, + }, + mem::{ + size_of, + }, + marker::Unpin, + io::{ + self, + Write, + Read, + }, + convert::{ + TryFrom, + }, +}; +use openssl::{ + bn::BigNumRef, + rsa::{ + Rsa, + }, + pkey::{ + Public, + Private, + HasPrivate, + PKey, + }, + symm::Cipher, +}; +#[cfg(feature="async")] +use tokio::{ + io::{ + AsyncWrite, + AsyncRead, + }, + prelude::*, +}; + +/// Container for the private & public parts of an RSA key +/// +/// # Notes +/// It is always assumed that the internal consistancy and state of the components binary representations is correct. +/// Incorrect internal state can cause panics on all operations. +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct RsaPrivateKey +{ + data: Vec, + offset_starts: Starts, + offset: PrivateOffsetGroup, +} + +impl RsaPrivateKey +{ + /// Create a new private key from its components + pub fn new( + n: impl Borrow, + e: impl Borrow, + d: impl Borrow, + p: impl Borrow, + q: impl Borrow, + dmp1: impl Borrow, + dmq1: impl Borrow, + iqmp: impl Borrow + ) -> Self + { + fn vectorise(b: impl Borrow, data: &mut Vec) -> usize + { + let bytes = b.borrow().to_vec(); + let len = bytes.len(); + data.extend(bytes); + len + } + + let mut data = Vec::new(); + let offset = PrivateOffsetGroup { + n: vectorise(n, &mut data), + e: vectorise(e, &mut data), + d: vectorise(d, &mut data), + p: vectorise(p, &mut data), + q: vectorise(q, &mut data), + dmp1: vectorise(dmp1, &mut data), + dmq1: vectorise(dmq1, &mut data), + iqmp: vectorise(iqmp, &mut data), + }; + + Self { + offset_starts: offset.starts(), + offset, + data, + } + } +} + +impl RsaPrivateKey +{ + /// Try to get the RSA private key from this instance + pub fn get_rsa_priv(&self) -> Result, Error> + { + Ok(Rsa::from_private_components( + number!(self -> n), + number!(self -> e), + number!(self -> d), + number!(self -> p), + number!(self -> q), + number!(self -> dmp1), + number!(self -> dmq1), + number!(self -> iqmp) + )?) + } + + /// Try to get the RSA public key from this instance of private key + pub fn get_rsa_pub(&self) -> Result, Error> + { + Ok(Rsa::from_public_components( + number!(self -> n), + number!(self -> e) + )?) + } + + + /// Get the public parts of this private key + pub fn get_public_parts(&self) -> RsaPublicKey + { + RsaPublicKey::new( + self.num_n(), + self.num_e() + ) + } + + /// Create a PEM string from this instance + pub fn to_pem(&self, pw: Option<&Password>) -> Result + { + let rsa = self.get_rsa_priv()?; + Ok(std::str::from_utf8(&match pw { + Some(password) => { + rsa.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), password.as_ref())? + }, + None => { + rsa.private_key_to_pem()? + }, + })?.to_owned()) + } + + /// Try to create an instance from PEM, requesting password if needed + pub fn from_pem(&self, pem: impl AsRef, pw: F) -> Result + where F: FnOnce() -> Option + { + let pem = pem.as_ref().as_bytes(); + Ok(Rsa::private_key_from_pem_callback(pem, |buf| { + if let Some(pw) = pw() { + Ok(bytes::copy_slice(buf, pw.as_ref())) + } else { + Ok(0) + } + })?.into()) + } + + /// Validates the RSA key parameters for correctness + pub fn check_key(&self) -> bool + { + self.get_rsa_priv() + .map(|rsa| rsa.check_key().unwrap_or(false)) + .unwrap_or(false) + } + + /// Try to construct an instance from bytes + pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result + { + const OFF_SIZE: usize = size_of::(); + let bytes = bytes.as_ref(); + + if bytes.len() < OFF_SIZE { + return Err(Error::Binary(BinaryErrorKind::Length{expected: Some(OFF_SIZE), got: Some(bytes.len())})); + } + + let offset: &PrivateOffsetGroup = bytes::derefer(&bytes[..OFF_SIZE]); + let bytes = &bytes[OFF_SIZE..]; + let sz = offset.body_len(); + + if bytes.len() < sz { + return Err(Error::Binary(BinaryErrorKind::Length{expected: Some(sz), got: Some(bytes.len())})); + } + + Ok(Self{ + data: Vec::from(&bytes[..]), + offset_starts: offset.starts(), + offset: *offset, + }) + } + + /// Write the binary representation of this instance to a new `Vec` + pub fn to_bytes(&self) -> Vec + { + let mut output = Vec::new(); + self.write_to_sync(&mut output).unwrap(); + output + } + + /// Return the length of the data body only (not including header). + #[inline] pub fn len(&self) -> usize + { + self.data.len() + } + + /// Write this private key as bytes to a stream + #[cfg(feature="async")] + pub async fn write_to(&self, to: &mut T) -> io::Result + where T: AsyncWrite + Unpin + ?Sized + { + to.write_all(bytes::refer(&self.offset)).await?; + to.write_all(&self.data[..]).await?; + + Ok(size_of::() + self.data.len()) + } + /// Write this private key as bytes to a stream + pub fn write_to_sync(&self, to: &mut T) -> io::Result + where T: Write + ?Sized + { + to.write_all(bytes::refer(&self.offset))?; + to.write_all(&self.data[..])?; + + Ok(size_of::() + self.data.len()) + } + + /// Read a private key from a stream + #[cfg(feature="async")] + pub async fn read_from(&self, from: &mut T) -> io::Result + where T: AsyncRead + Unpin + ?Sized + { + const OFF_SIZE: usize = size_of::(); + + let offset: PrivateOffsetGroup = { + let mut buffer = [0u8; OFF_SIZE]; + + if buffer.len() != from.read_exact(&mut buffer[..]).await? { + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "couldn't read offsets")); + } else { + *bytes::derefer(&buffer[..]) + } + }; + + let mut data = vec![0u8; offset.body_len()]; + + if from.read_exact(&mut data[..]).await? != data.len() { + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "couldn't read data body")); + } + + Ok(Self { + data, + offset_starts: offset.starts(), + offset + }) + } + + /// Read a private key from a stream + pub fn read_from_sync(&self, from: &mut T) -> io::Result + where T: Read + ?Sized + { + let offset: PrivateOffsetGroup = { + let mut buffer = [0u8; size_of::()]; + + from.read_exact(&mut buffer[..])?; + *bytes::derefer(&buffer[..]) + }; + + let mut data = vec![0u8; offset.body_len()]; + + from.read_exact(&mut data[..])?; + + Ok(Self { + data, + offset_starts: offset.starts(), + offset + }) + } + +} + +impl HasComponents for RsaPrivateKey +{ + fn raw(&self) -> &[u8] + { + return &self.data[..] + } +} + +impl HasPublicComponents for RsaPrivateKey +{ + fn n(&self) -> &[u8] + { + component!(self -> n) + } + fn e(&self) -> &[u8] + { + component!(self -> e) + } +} +impl HasPrivateComponents for RsaPrivateKey +{ + fn d(&self) -> &[u8] + { + component!(self -> d) + } + fn p(&self) -> &[u8] + { + component!(self -> p) + } + fn q(&self) -> &[u8] + { + component!(self -> q) + } + fn dmp1(&self) -> &[u8] + { + component!(self -> dmp1) + } + fn dmq1(&self) -> &[u8] + { + component!(self -> dmq1) + } + fn iqmp(&self) -> &[u8] + { + component!(self -> iqmp) + } +} + +impl From> for RsaPrivateKey +where T: HasPrivate +{ + fn from(key: Rsa) -> Self + { + Self::new( + key.n(), + key.e(), + key.d(), + key.p().unwrap(), + key.q().unwrap(), + key.dmp1().unwrap(), + key.dmq1().unwrap(), + key.iqmp().unwrap() + ) + } +} + +impl From for Rsa +{ + fn from(from: RsaPrivateKey) -> Self + { + from.get_rsa_priv().unwrap() + } +} + +impl From for RsaPublicKey +{ + fn from(from: RsaPrivateKey) -> Self + { + from.get_public_parts() + } +} + +impl PublicKey for RsaPrivateKey +{ + type KeyType = Private; + type Error = Error; + + fn get_pkey_pub(&self) -> Result>, Self::Error> + { + Ok(Cow::Owned(PKey::from_rsa(self.get_rsa_priv()?)?)) + } + + fn get_rsa_pub(&self) -> Result>>, Self::Error> + { + Ok(Some(Cow::Owned(self.get_pkey_pub()?.rsa()?))) + } +} +impl PrivateKey for RsaPrivateKey{} + +impl From for Vec +{ + #[inline] fn from(from: RsaPrivateKey) -> Self + { + from.to_bytes() + } +} + +impl TryFrom> for RsaPrivateKey +{ + type Error = Error; + + #[inline] fn try_from(from: Vec) -> Result + { + Self::from_bytes(from) + } +} diff --git a/src/rsa/private_offsets.rs b/src/rsa/private_offsets.rs new file mode 100644 index 0000000..1c9534d --- /dev/null +++ b/src/rsa/private_offsets.rs @@ -0,0 +1,78 @@ +//! Private offsets +use super::offsets::*; + +#[repr(C, packed)] +#[derive(Clone,Copy,Debug,Eq,PartialEq,Hash,Default)] +pub struct PrivateOffsetGroup +{ + pub n: usize, + pub e: usize, + pub d: usize, + pub p: usize, + pub q: usize, + pub dmp1: usize, + pub dmq1: usize, + pub iqmp: usize, +} + +impl HasOffsets for PrivateOffsetGroup +{ + fn starts(&self) -> Starts + { + Self { + n: 0, + e: self.n, + d: self.n+self.e, + p: self.n+self.e+self.d, + q: self.n+self.e+self.d+self.p, + dmp1: self.n+self.e+self.d+self.p+self.q, + dmq1: self.n+self.e+self.d+self.p+self.q+self.dmp1, + iqmp: self.n+self.e+self.d+self.p+self.q+self.dmp1+self.dmq1, + }.into() + } + + fn body_len(&self) -> usize + { + self.n+self.e+self.d+self.p+self.q+self.dmp1+self.dmq1+self.iqmp + } +} + +impl HasPublicOffsets for PrivateOffsetGroup +{ + fn n(&self) -> usize + { + self.n + } + fn e(&self) -> usize + { + self.e + } +} + +impl HasPrivateOffsets for PrivateOffsetGroup +{ + fn d(&self) -> usize + { + self.d + } + fn p(&self) -> usize + { + self.p + } + fn q(&self) -> usize + { + self.q + } + fn dmp1(&self) -> usize + { + self.dmp1 + } + fn dmq1(&self) -> usize + { + self.dmq1 + } + fn iqmp(&self) -> usize + { + self.iqmp + } +} diff --git a/src/rsa/public.rs b/src/rsa/public.rs new file mode 100644 index 0000000..da2073a --- /dev/null +++ b/src/rsa/public.rs @@ -0,0 +1,320 @@ +//! Public RSA key components +use super::*; +use offsets::*; + +#[allow(unused_imports)] +use std::{ + borrow::{ + Borrow, + Cow, + }, + io::{ + self, + Write, + Read, + }, + mem::size_of, + marker::Unpin, + convert::{ + TryFrom, + }, +}; +use openssl::{ + bn::{ + BigNumRef, + }, + rsa::{ + Rsa, + }, + pkey::{ + Public, + HasPublic, + PKey, + }, +}; +#[cfg(feature="async")] +use tokio::{ + io::{ + AsyncWrite, + AsyncRead, + }, + prelude::*, +}; + +/// Container for RSA public key components +/// +/// # Notes +/// It is always assumed that the internal consistancy and state of the components binary representations is correct. +/// Incorrect internal state can cause panics on all operations. +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct RsaPublicKey +{ + data: Vec, + offset_starts: Starts, + offset: PublicOffsetGroup, +} + +impl RsaPublicKey +{ + /// Create a new RSAPublicKey from components + pub fn new( + n: impl Borrow, + e: impl Borrow + ) -> Self + { + fn vectorise>(b: U, data: &mut T) -> usize + { + let bytes = b.borrow().to_vec(); + data.write(bytes.as_slice()).unwrap() + } + let mut data = Vec::new(); + let offset = offsets::PublicOffsetGroup { + n: vectorise(n, &mut data), + e: vectorise(e, &mut data), + }; + + Self { + offset_starts: offset.starts(), + offset, + data, + } + } + + /// Create a PEM string from this instance + pub fn to_pem(&self) -> Result + { + let pkey = self.get_pkey_pub()?; + let pem = pkey.public_key_to_pem()?; + + Ok(std::str::from_utf8(&pem[..])?.to_string()) + } + + /// Try to create a new instance from a PEM string + pub fn from_pem(pem: impl AsRef) -> Result + { + let pem = pem.as_ref(); + let pem = pem.as_bytes(); + + Ok(Rsa::public_key_from_pem(pem)?.into()) + } + + /// Validates the RSA key parameters for correctness + pub fn check_key(&self) -> bool + { + self.get_rsa_pub() + .map(|_| true) + .unwrap_or(false) + } + + /// Try to get the RSA public key from this instance + pub fn get_rsa_pub(&self) -> Result, Error> + { + Ok(Rsa::from_public_components( + number!(self -> n), + number!(self -> e) + )?) + } + + /// Try to construct an instance from bytes + pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result + { + let bytes = bytes.as_ref(); + + if bytes.len() < size_of::() { + return Err(Error::Binary(BinaryErrorKind::Length{expected: Some(size_of::()), got: Some(bytes.len())})); + } + + let offset: &PublicOffsetGroup = bytes::derefer(&bytes[..size_of::()]); + let bytes = &bytes[size_of::()..]; + + let sz = offset.body_len(); + if bytes.len() < sz { + return Err(Error::Binary(BinaryErrorKind::Length{expected:Some(sz), got: Some(bytes.len())})); + } + + Ok(Self { + data: Vec::from(&bytes[..]), + offset_starts: offset.starts(), + offset: *offset, + }) + } + + /// Write the binary representation of this instance to a new `Vec` + pub fn to_bytes(&self) -> Vec + { + let mut output = Vec::new(); + self.write_to_sync(&mut output).unwrap(); + output + } + + /// Return the length of the data body only (not including header). + #[inline] pub fn len(&self) -> usize + { + self.data.len() + } + + /// Write this public key as bytes to a stream + #[cfg(feature="async")] + pub async fn write_to(&self, to: &mut T) -> io::Result + where T: AsyncWrite + Unpin + ?Sized + { + to.write_all(bytes::refer(&self.offset)).await?; + to.write_all(&self.data[..]).await?; + + Ok(size_of::() + self.data.len()) + } + + /// Write this public key as bytes to a stream + pub fn write_to_sync(&self, to: &mut T) -> io::Result + where T: Write + ?Sized + { + to.write_all(bytes::refer(&self.offset))?; + to.write_all(&self.data[..])?; + + Ok(size_of::() + self.data.len()) + } + + /// Read a public key from a stream + #[cfg(feature="async")] + pub async fn read_from(&self, from: &mut T) -> io::Result + where T: AsyncRead + Unpin + ?Sized + { + let offset: PublicOffsetGroup = { + let mut buffer = [0u8; size_of::()]; + + if buffer.len() != from.read_exact(&mut buffer[..]).await? { + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "couldn't read offsets")); + } else { + *bytes::derefer(&buffer[..]) + } + }; + + let mut data = vec![0u8; offset.body_len()]; + + if from.read_exact(&mut data[..]).await? != data.len() { + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "couldn't read data body")); + } + + Ok(Self { + data, + offset_starts: offset.starts(), + offset + }) + } + + /// Read a public key from a stream + pub fn read_from_sync(&self, from: &mut T) -> io::Result + where T: Read + ?Sized + { + let offset: PublicOffsetGroup = { + let mut buffer = [0u8; size_of::()]; + + from.read_exact(&mut buffer[..])?; + *bytes::derefer(&buffer[..]) + }; + + let mut data = vec![0u8; offset.body_len()]; + + from.read_exact(&mut data[..])?; + + Ok(Self { + data, + offset_starts: offset.starts(), + offset + }) + } +} + +impl HasComponents for RsaPublicKey +{ + fn raw(&self) -> &[u8] + { + &self.data[..] + } +} + +impl From for Rsa +{ + #[inline] fn from(key: RsaPublicKey) -> Rsa + { + key.get_rsa_pub().unwrap() + } +} + +impl From for PKey +{ + fn from(from: RsaPublicKey) -> Self + { + PKey::from_rsa(from.into()).unwrap() + } +} + +impl From> for RsaPublicKey +where T: HasPublic +{ + fn from(from: PKey) -> Self + { + from.rsa().unwrap().into() + } +} + +impl PublicKey for RsaPublicKey +{ + type KeyType = Public; + type Error = Error; + + fn get_pkey_pub(&self) -> Result>, Self::Error> + { + Ok(Cow::Owned(PKey::from_rsa(Rsa::from_public_components(number!(self -> n), number!(self -> e))?)?)) + } + + fn get_rsa_pub(&self) -> Result>>, Self::Error> + { + Ok(Some(Cow::Owned(self.get_pkey_pub()?.rsa()?))) + } +} + + +impl From> for RsaPublicKey +where T: HasPublic +{ + fn from(key: Rsa) -> Self + { + Self::new(key.n(), + key.e()) + } +} + +impl HasPublicComponents for RsaPublicKey +{ + fn n(&self) -> &[u8] + { + component!(self -> n) + } + fn e(&self) -> &[u8] + { + component!(self -> e) + } +} + +impl From for Vec +{ + fn from(key: RsaPublicKey) -> Self + { + let mut vec = Self::with_capacity(key.data.len()+size_of::()); + vec.extend_from_slice(bytes::refer(&key.offset)); + vec.extend(key.data); + vec + } +} + +impl TryFrom> for RsaPublicKey +{ + type Error = Error; + + #[inline] fn try_from(from: Vec) -> Result + { + Self::from_bytes(from) + } +} + diff --git a/src/rsa/public_offsets.rs b/src/rsa/public_offsets.rs new file mode 100644 index 0000000..1f3f9f0 --- /dev/null +++ b/src/rsa/public_offsets.rs @@ -0,0 +1,37 @@ +//! Offsets for a public key container +use super::offsets::*; + +#[repr(C, packed)] +#[derive(Clone,Copy,Debug,Eq,PartialEq,Hash,Default)] +pub struct PublicOffsetGroup +{ + pub n: usize, + pub e: usize, +} + +impl HasOffsets for PublicOffsetGroup +{ + fn starts(&self) -> Starts + { + Self { + n: 0, + e: self.n, + }.into() + } + fn body_len(&self) -> usize + { + self.n+self.e + } +} + +impl HasPublicOffsets for PublicOffsetGroup +{ + fn n(&self) -> usize + { + self.n + } + fn e(&self) -> usize + { + self.e + } +} diff --git a/src/rsa/sign.rs b/src/rsa/sign.rs new file mode 100644 index 0000000..e23b280 --- /dev/null +++ b/src/rsa/sign.rs @@ -0,0 +1,255 @@ +//! RSA signing +use super::*; +#[allow(unused_imports)] +use std::{ + cmp::{PartialEq,Eq,}, + hash::{Hash,Hasher,}, + fmt::{ + self, + Display, + Debug, + }, + marker::Unpin, + io::{ + Read, + }, +}; +use openssl::{ + hash::{ + MessageDigest, + }, + sign::{ + Signer, + Verifier, + }, + pkey::{ + HasPrivate, + }, +}; +#[cfg(feature="async")] +use tokio::{ + io::{ + AsyncRead, + }, + prelude::*, +}; +use consts::RSA_SIG_SIZE as SIZE; +use consts::BUFFER_SIZE; + +/// Represents an RSA signature +#[derive(Copy, Clone)] +pub struct Signature([u8; SIZE]); + +impl Signature +{ + /// Create from an exact array + pub const fn from_exact(from: [u8; SIZE]) -> Self + { + Self(from) + } + + /// Create from a silce. + /// + /// # Panics + /// If `from` is not at least `RSA_SIG_SIZE` bytes long + pub fn from_slice(from: impl AsRef<[u8]>) -> Self + { + let mut output = [0u8; SIZE]; + assert_eq!(bytes::copy_slice(&mut output[..], from.as_ref()), SIZE); + Self(output) + } + + /// Verify this signature for a slice of data + pub fn verify_slice(&self, slice: T, key: &K) -> Result + where K: PublicKey + ?Sized, + T: AsRef<[u8]> + { + let pkey = key.get_pkey_pub().map_err(|_| Error::Key)?; + + let mut veri = Verifier::new(MessageDigest::sha256(), &pkey)?; + veri.update(slice.as_ref())?; + + Ok(veri.verify(&self.0[..])?) + } + + /// Verify this signature for a stream of data. Returns the success and number of bytes read. + #[cfg(feature="async")] + pub async fn verify(&self, from: &mut T, key: &K) -> Result<(bool, usize), Error> + where T: AsyncRead + Unpin + ?Sized, + K: PublicKey + ?Sized + { + let pkey = key.get_pkey_pub().map_err(|_| Error::Key)?; + + let mut veri = Verifier::new(MessageDigest::sha256(), &pkey)?; + let done = { + let mut read; + let mut done = 0; + let mut buffer = [0u8; BUFFER_SIZE]; + while {read = from.read(&mut buffer[..]).await?; read!=0} { + veri.update(&buffer[..read])?; + done+=read; + } + done + }; + + Ok((veri.verify(&self.0[..])?, done)) + } + /// Verify this signature for a stream of data. Returns the success and number of bytes read. + pub fn verify_sync(&self, from: &mut T, key: &K) -> Result<(bool, usize), Error> + where T: Read + ?Sized, + K: PublicKey + ?Sized + { + let pkey = key.get_pkey_pub().map_err(|_| Error::Key)?; + + let mut veri = Verifier::new(MessageDigest::sha256(), &pkey)?; + let done = { + let mut read; + let mut done = 0; + let mut buffer = [0u8; BUFFER_SIZE]; + while {read = from.read(&mut buffer[..])?; read!=0} { + veri.update(&buffer[..read])?; + done+=read; + } + done + }; + + Ok((veri.verify(&self.0[..])?, done)) + } +} + +/// Compute the signature for a slice of bytes +pub fn sign_slice(data: T, key: &K) -> Result +where T: AsRef<[u8]>, + K: PrivateKey + ?Sized, +::KeyType: HasPrivate //ugh +{ + let pkey = key.get_pkey_priv().map_err(|_| Error::Key)?; + + let mut signer = Signer::new(MessageDigest::sha256(), &pkey)?; + signer.update(data.as_ref())?; + + let mut output = [0u8; SIZE]; + assert_eq!(signer.sign(&mut output[..])?, SIZE); + + Ok(Signature(output)) +} + +/// Compute the signature for this stream, returning it and the number of bytes read +#[cfg(feature="async")] +pub async fn sign(data: &mut T, key: &K) -> Result<(Signature, usize), Error> +where T: AsyncRead + Unpin + ?Sized, + K: PrivateKey + ?Sized, +::KeyType: HasPrivate //ugh +{ + + let pkey = key.get_pkey_priv().map_err(|_| Error::Key)?; + + let mut signer = Signer::new(MessageDigest::sha256(), &pkey)?; + let done = { + let mut read; + let mut done=0; + let mut buffer = [0u8; SIZE]; + + while {read = data.read(&mut buffer[..]).await?; read!=0} { + signer.update(&buffer[..read])?; + done+=read; + } + done + }; + + let mut output = [0u8; SIZE]; + assert_eq!(signer.sign(&mut output[..])?, SIZE); + + Ok((Signature(output), done)) +} +/// Compute the signature for this stream, returning it and the number of bytes read +pub fn sign_sync(data: &mut T, key: &K) -> Result<(Signature, usize), Error> +where T: Read + ?Sized, + K: PrivateKey + ?Sized, +::KeyType: HasPrivate //ugh +{ + + let pkey = key.get_pkey_priv().map_err(|_| Error::Key)?; + + let mut signer = Signer::new(MessageDigest::sha256(), &pkey)?; + let done = { + let mut read; + let mut done=0; + let mut buffer = [0u8; SIZE]; + + while {read = data.read(&mut buffer[..])?; read!=0} { + signer.update(&buffer[..read])?; + done+=read; + } + done + }; + + let mut output = [0u8; SIZE]; + assert_eq!(signer.sign(&mut output[..])?, SIZE); + + Ok((Signature(output), done)) +} + +// Boilerplate + +impl AsRef<[u8]> for Signature +{ + fn as_ref(&self) -> &[u8] + { + &self.0[..] + } +} + +impl AsMut<[u8]> for Signature +{ + fn as_mut(&mut self) -> &mut [u8] + { + &mut self.0[..] + } +} + +impl Default for Signature +{ + #[inline] + fn default() -> Self + { + Self([0u8; SIZE]) + } +} + +impl Eq for Signature{} +impl PartialEq for Signature +{ + #[inline] fn eq(&self, other: &Self) -> bool + { + &self.0[..] == &other.0[..] + } +} + +impl Hash for Signature { + fn hash(&self, state: &mut H) { + self.0[..].hash(state) + } +} + +impl Debug for Signature +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "Signature ({:?})", &self.0[..]) + } +} + +impl Display for Signature +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "Signature (")?; + for byte in self.0.iter() + { + write!(f, "{:0x}", byte)?; + } + write!(f,")") + } +} +