parent
5a2c84cb68
commit
f6be53890f
@ -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<usize>, got: Option<usize>},
|
||||||
|
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<ErrorStack> for Error
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: ErrorStack) -> Self
|
||||||
|
{
|
||||||
|
Self::OpenSSLInternal(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error
|
||||||
|
{
|
||||||
|
fn from(from: io::Error) -> Self
|
||||||
|
{
|
||||||
|
Self::IO(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::str::Utf8Error> for Error
|
||||||
|
{
|
||||||
|
fn from(_: std::str::Utf8Error) -> Self
|
||||||
|
{
|
||||||
|
Self::Utf8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TryFromIntError> for Error
|
||||||
|
{
|
||||||
|
fn from(_: TryFromIntError) -> Self
|
||||||
|
{
|
||||||
|
Self::Integer
|
||||||
|
}
|
||||||
|
}
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
@ -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<Cow<'_, PKey<Self::KeyType>>, Self::Error>;
|
||||||
|
|
||||||
|
/// Get or create an `Rsa` from this public key if possible
|
||||||
|
fn get_rsa_pub(&self) -> Result<Option<Cow<'_, Rsa<Self::KeyType>>>, 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 <Self as PublicKey>::KeyType: HasPrivate
|
||||||
|
{
|
||||||
|
/// Get or create a `PKey` that contains the private key
|
||||||
|
#[inline] fn get_pkey_priv(&self) -> Result<Cow<'_, PKey<<Self as PublicKey>::KeyType>>, <Self as PublicKey>::Error>
|
||||||
|
{
|
||||||
|
self.get_pkey_pub()
|
||||||
|
}
|
||||||
|
/// Get or create an `Rsa` from this private key if possible
|
||||||
|
#[inline] fn get_rsa_priv(&self) -> Result<Option<Cow<'_, Rsa<Self::KeyType>>>, Self::Error>
|
||||||
|
{
|
||||||
|
self.get_rsa_pub()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PublicKey for PKey<T>
|
||||||
|
where T: HasPublic
|
||||||
|
{
|
||||||
|
type KeyType = T;
|
||||||
|
type Error = Infallible;
|
||||||
|
fn get_pkey_pub(&self) -> Result<Cow<'_, PKey<Self::KeyType>>, Self::Error>
|
||||||
|
{
|
||||||
|
Ok(Cow::Borrowed(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PrivateKey for PKey<T>
|
||||||
|
where T: HasPrivate
|
||||||
|
{
|
||||||
|
fn get_pkey_priv(&self) -> Result<Cow<'_, PKey<<Self as PublicKey>::KeyType>>, <Self as PublicKey>::Error>
|
||||||
|
{
|
||||||
|
Ok(Cow::Borrowed(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PublicKey for Rsa<T>
|
||||||
|
where T: HasPublic
|
||||||
|
{
|
||||||
|
type KeyType = T;
|
||||||
|
type Error = openssl::error::ErrorStack;
|
||||||
|
|
||||||
|
fn get_pkey_pub(&self) -> Result<Cow<'_, PKey<Self::KeyType>>, Self::Error>
|
||||||
|
{
|
||||||
|
Ok(Cow::Owned(PKey::from_rsa(self.clone())?))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] fn get_rsa_pub(&self) -> Result<Option<Cow<'_, Rsa<Self::KeyType>>>, Self::Error>
|
||||||
|
{
|
||||||
|
Ok(Some(Cow::Borrowed(self)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PrivateKey for Rsa<T>
|
||||||
|
where T: HasPrivate
|
||||||
|
{
|
||||||
|
fn get_pkey_priv(&self) -> Result<Cow<'_, PKey<<Self as PublicKey>::KeyType>>, <Self as PublicKey>::Error>
|
||||||
|
{
|
||||||
|
Ok(Cow::Owned(PKey::from_rsa(self.clone())?))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] fn get_rsa_priv(&self) -> Result<Option<Cow<'_, Rsa<Self::KeyType>>>, Self::Error>
|
||||||
|
{
|
||||||
|
Ok(Some(Cow::Borrowed(self)))
|
||||||
|
}
|
||||||
|
}
|
@ -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<T,K>(data: T, key: &K) -> Result<Vec<u8>, 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<T,K>(data: T, key: &K) -> Result<Vec<u8>, Error>
|
||||||
|
where T: AsRef<[u8]>,
|
||||||
|
K: PrivateKey + ?Sized,
|
||||||
|
<K as PublicKey>::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<T,K,U>(data: &mut T, key: &K, output: &mut U) -> Result<usize, Error>
|
||||||
|
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<T,K,U>(data: T, key: &K, output: &mut U) -> Result<usize, Error>
|
||||||
|
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<T,K,U>(data: &mut T, key: &K, output: &mut U) -> Result<usize, Error>
|
||||||
|
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<T,K,U>(data: T, key: &K, output: &mut U) -> Result<usize, Error>
|
||||||
|
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<T,K,U>(data: T, key: &K, output: &mut U) -> Result<usize, Error>
|
||||||
|
where T: AsRef<[u8]>,
|
||||||
|
K: PrivateKey + ?Sized,
|
||||||
|
U: AsyncWrite + Unpin + ?Sized,
|
||||||
|
<K as PublicKey>::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<T,K,U>(data: &mut T, key: &K, output: &mut U) -> Result<usize, Error>
|
||||||
|
where T: AsyncRead + Unpin + ?Sized,
|
||||||
|
K: PrivateKey + ?Sized,
|
||||||
|
U: AsyncWrite + Unpin + ?Sized,
|
||||||
|
<K as PublicKey>::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<T,K,U>(data: T, key: &K, output: &mut U) -> Result<usize, Error>
|
||||||
|
where T: AsRef<[u8]>,
|
||||||
|
K: PrivateKey + ?Sized,
|
||||||
|
U: Write + ?Sized,
|
||||||
|
<K as PublicKey>::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<T,K,U>(data: &mut T, key: &K, output: &mut U) -> Result<usize, Error>
|
||||||
|
where T: Read + ?Sized,
|
||||||
|
K: PrivateKey + ?Sized,
|
||||||
|
U: Write + ?Sized,
|
||||||
|
<K as PublicKey>::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)
|
||||||
|
|
||||||
|
}
|
@ -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::*;
|
@ -0,0 +1,109 @@
|
|||||||
|
//! Traits for offsets of components
|
||||||
|
|
||||||
|
pub struct Starts<T: HasOffsets>(T);
|
||||||
|
|
||||||
|
pub trait HasOffsets: Sized
|
||||||
|
{
|
||||||
|
fn starts(&self) -> Starts<Self>;
|
||||||
|
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<T> Starts<T>
|
||||||
|
where T: HasPublicOffsets
|
||||||
|
{
|
||||||
|
pub fn n(&self) -> usize
|
||||||
|
{
|
||||||
|
self.0.n()
|
||||||
|
}
|
||||||
|
pub fn e(&self) -> usize
|
||||||
|
{
|
||||||
|
self.0.e()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for Starts<T>
|
||||||
|
where T: HasPublicOffsets
|
||||||
|
{
|
||||||
|
fn from(from: T) -> Self
|
||||||
|
{
|
||||||
|
Self(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Starts<T>
|
||||||
|
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<T> Copy for Starts<T> where T: Copy + HasOffsets{}
|
||||||
|
impl<T> Clone for Starts<T> where T: Clone + HasOffsets{#[inline] fn clone(&self) -> Self {Self(self.0.clone())}}
|
||||||
|
impl<T> Eq for Starts<T> where T: Eq + HasOffsets{}
|
||||||
|
impl<T> PartialEq for Starts<T> where T: PartialEq + HasOffsets{#[inline] fn eq(&self, other: &Self) -> bool {self.0 == other.0}}
|
||||||
|
impl<T> Hash for Starts<T>
|
||||||
|
where T: Hash + HasOffsets
|
||||||
|
{
|
||||||
|
#[inline] fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.0.hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> Debug for Starts<T>
|
||||||
|
where T: HasOffsets + Debug
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "Starts ({:?})", self.0)
|
||||||
|
}
|
||||||
|
}
|
@ -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<u8>,
|
||||||
|
offset_starts: Starts<PrivateOffsetGroup>,
|
||||||
|
offset: PrivateOffsetGroup,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RsaPrivateKey
|
||||||
|
{
|
||||||
|
/// Create a new private key from its components
|
||||||
|
pub fn new(
|
||||||
|
n: impl Borrow<BigNumRef>,
|
||||||
|
e: impl Borrow<BigNumRef>,
|
||||||
|
d: impl Borrow<BigNumRef>,
|
||||||
|
p: impl Borrow<BigNumRef>,
|
||||||
|
q: impl Borrow<BigNumRef>,
|
||||||
|
dmp1: impl Borrow<BigNumRef>,
|
||||||
|
dmq1: impl Borrow<BigNumRef>,
|
||||||
|
iqmp: impl Borrow<BigNumRef>
|
||||||
|
) -> Self
|
||||||
|
{
|
||||||
|
fn vectorise(b: impl Borrow<BigNumRef>, data: &mut Vec<u8>) -> 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<Rsa<Private>, 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<Rsa<Public>, 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<String, Error>
|
||||||
|
{
|
||||||
|
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<F>(&self, pem: impl AsRef<str>, pw: F) -> Result<Self, Error>
|
||||||
|
where F: FnOnce() -> Option<Password>
|
||||||
|
{
|
||||||
|
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<Self, Error>
|
||||||
|
{
|
||||||
|
const OFF_SIZE: usize = size_of::<PrivateOffsetGroup>();
|
||||||
|
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<u8>`
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
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<T>(&self, to: &mut T) -> io::Result<usize>
|
||||||
|
where T: AsyncWrite + Unpin + ?Sized
|
||||||
|
{
|
||||||
|
to.write_all(bytes::refer(&self.offset)).await?;
|
||||||
|
to.write_all(&self.data[..]).await?;
|
||||||
|
|
||||||
|
Ok(size_of::<PrivateOffsetGroup>() + self.data.len())
|
||||||
|
}
|
||||||
|
/// Write this private key as bytes to a stream
|
||||||
|
pub fn write_to_sync<T>(&self, to: &mut T) -> io::Result<usize>
|
||||||
|
where T: Write + ?Sized
|
||||||
|
{
|
||||||
|
to.write_all(bytes::refer(&self.offset))?;
|
||||||
|
to.write_all(&self.data[..])?;
|
||||||
|
|
||||||
|
Ok(size_of::<PrivateOffsetGroup>() + self.data.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a private key from a stream
|
||||||
|
#[cfg(feature="async")]
|
||||||
|
pub async fn read_from<T>(&self, from: &mut T) -> io::Result<Self>
|
||||||
|
where T: AsyncRead + Unpin + ?Sized
|
||||||
|
{
|
||||||
|
const OFF_SIZE: usize = size_of::<PrivateOffsetGroup>();
|
||||||
|
|
||||||
|
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<T>(&self, from: &mut T) -> io::Result<Self>
|
||||||
|
where T: Read + ?Sized
|
||||||
|
{
|
||||||
|
let offset: PrivateOffsetGroup = {
|
||||||
|
let mut buffer = [0u8; size_of::<PrivateOffsetGroup>()];
|
||||||
|
|
||||||
|
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<T> From<Rsa<T>> for RsaPrivateKey
|
||||||
|
where T: HasPrivate
|
||||||
|
{
|
||||||
|
fn from(key: Rsa<T>) -> 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<RsaPrivateKey> for Rsa<Private>
|
||||||
|
{
|
||||||
|
fn from(from: RsaPrivateKey) -> Self
|
||||||
|
{
|
||||||
|
from.get_rsa_priv().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RsaPrivateKey> 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<Cow<'_, PKey<Self::KeyType>>, Self::Error>
|
||||||
|
{
|
||||||
|
Ok(Cow::Owned(PKey::from_rsa(self.get_rsa_priv()?)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_rsa_pub(&self) -> Result<Option<Cow<'_, Rsa<Self::KeyType>>>, Self::Error>
|
||||||
|
{
|
||||||
|
Ok(Some(Cow::Owned(self.get_pkey_pub()?.rsa()?)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PrivateKey for RsaPrivateKey{}
|
||||||
|
|
||||||
|
impl From<RsaPrivateKey> for Vec<u8>
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: RsaPrivateKey) -> Self
|
||||||
|
{
|
||||||
|
from.to_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for RsaPrivateKey
|
||||||
|
{
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
#[inline] fn try_from(from: Vec<u8>) -> Result<Self, Self::Error>
|
||||||
|
{
|
||||||
|
Self::from_bytes(from)
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
||||||
|
{
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -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<u8>,
|
||||||
|
offset_starts: Starts<PublicOffsetGroup>,
|
||||||
|
offset: PublicOffsetGroup,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RsaPublicKey
|
||||||
|
{
|
||||||
|
/// Create a new RSAPublicKey from components
|
||||||
|
pub fn new(
|
||||||
|
n: impl Borrow<BigNumRef>,
|
||||||
|
e: impl Borrow<BigNumRef>
|
||||||
|
) -> Self
|
||||||
|
{
|
||||||
|
fn vectorise<T: Write,U: Borrow<BigNumRef>>(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<String, Error>
|
||||||
|
{
|
||||||
|
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<str>) -> Result<Self, Error>
|
||||||
|
{
|
||||||
|
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<Rsa<Public>, 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<Self, Error>
|
||||||
|
{
|
||||||
|
let bytes = bytes.as_ref();
|
||||||
|
|
||||||
|
if bytes.len() < size_of::<PublicOffsetGroup>() {
|
||||||
|
return Err(Error::Binary(BinaryErrorKind::Length{expected: Some(size_of::<PublicOffsetGroup>()), got: Some(bytes.len())}));
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset: &PublicOffsetGroup = bytes::derefer(&bytes[..size_of::<PublicOffsetGroup>()]);
|
||||||
|
let bytes = &bytes[size_of::<PublicOffsetGroup>()..];
|
||||||
|
|
||||||
|
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<u8>`
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
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<T>(&self, to: &mut T) -> io::Result<usize>
|
||||||
|
where T: AsyncWrite + Unpin + ?Sized
|
||||||
|
{
|
||||||
|
to.write_all(bytes::refer(&self.offset)).await?;
|
||||||
|
to.write_all(&self.data[..]).await?;
|
||||||
|
|
||||||
|
Ok(size_of::<PublicOffsetGroup>() + self.data.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write this public key as bytes to a stream
|
||||||
|
pub fn write_to_sync<T>(&self, to: &mut T) -> io::Result<usize>
|
||||||
|
where T: Write + ?Sized
|
||||||
|
{
|
||||||
|
to.write_all(bytes::refer(&self.offset))?;
|
||||||
|
to.write_all(&self.data[..])?;
|
||||||
|
|
||||||
|
Ok(size_of::<PublicOffsetGroup>() + self.data.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a public key from a stream
|
||||||
|
#[cfg(feature="async")]
|
||||||
|
pub async fn read_from<T>(&self, from: &mut T) -> io::Result<Self>
|
||||||
|
where T: AsyncRead + Unpin + ?Sized
|
||||||
|
{
|
||||||
|
let offset: PublicOffsetGroup = {
|
||||||
|
let mut buffer = [0u8; size_of::<PublicOffsetGroup>()];
|
||||||
|
|
||||||
|
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<T>(&self, from: &mut T) -> io::Result<Self>
|
||||||
|
where T: Read + ?Sized
|
||||||
|
{
|
||||||
|
let offset: PublicOffsetGroup = {
|
||||||
|
let mut buffer = [0u8; size_of::<PublicOffsetGroup>()];
|
||||||
|
|
||||||
|
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<RsaPublicKey> for Rsa<Public>
|
||||||
|
{
|
||||||
|
#[inline] fn from(key: RsaPublicKey) -> Rsa<Public>
|
||||||
|
{
|
||||||
|
key.get_rsa_pub().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RsaPublicKey> for PKey<Public>
|
||||||
|
{
|
||||||
|
fn from(from: RsaPublicKey) -> Self
|
||||||
|
{
|
||||||
|
PKey::from_rsa(from.into()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<PKey<T>> for RsaPublicKey
|
||||||
|
where T: HasPublic
|
||||||
|
{
|
||||||
|
fn from(from: PKey<T>) -> Self
|
||||||
|
{
|
||||||
|
from.rsa().unwrap().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PublicKey for RsaPublicKey
|
||||||
|
{
|
||||||
|
type KeyType = Public;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn get_pkey_pub(&self) -> Result<Cow<'_, PKey<Self::KeyType>>, Self::Error>
|
||||||
|
{
|
||||||
|
Ok(Cow::Owned(PKey::from_rsa(Rsa::from_public_components(number!(self -> n), number!(self -> e))?)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_rsa_pub(&self) -> Result<Option<Cow<'_, Rsa<Self::KeyType>>>, Self::Error>
|
||||||
|
{
|
||||||
|
Ok(Some(Cow::Owned(self.get_pkey_pub()?.rsa()?)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<T> From<Rsa<T>> for RsaPublicKey
|
||||||
|
where T: HasPublic
|
||||||
|
{
|
||||||
|
fn from(key: Rsa<T>) -> 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<RsaPublicKey> for Vec<u8>
|
||||||
|
{
|
||||||
|
fn from(key: RsaPublicKey) -> Self
|
||||||
|
{
|
||||||
|
let mut vec = Self::with_capacity(key.data.len()+size_of::<PublicOffsetGroup>());
|
||||||
|
vec.extend_from_slice(bytes::refer(&key.offset));
|
||||||
|
vec.extend(key.data);
|
||||||
|
vec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for RsaPublicKey
|
||||||
|
{
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
#[inline] fn try_from(from: Vec<u8>) -> Result<Self, Self::Error>
|
||||||
|
{
|
||||||
|
Self::from_bytes(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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>
|
||||||
|
{
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
@ -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<T,K>(&self, slice: T, key: &K) -> Result<bool, Error>
|
||||||
|
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<T,K>(&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<T,K>(&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<T,K>(data: T, key: &K) -> Result<Signature, Error>
|
||||||
|
where T: AsRef<[u8]>,
|
||||||
|
K: PrivateKey + ?Sized,
|
||||||
|
<K as PublicKey>::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<T,K>(data: &mut T, key: &K) -> Result<(Signature, usize), Error>
|
||||||
|
where T: AsyncRead + Unpin + ?Sized,
|
||||||
|
K: PrivateKey + ?Sized,
|
||||||
|
<K as PublicKey>::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<T,K>(data: &mut T, key: &K) -> Result<(Signature, usize), Error>
|
||||||
|
where T: Read + ?Sized,
|
||||||
|
K: PrivateKey + ?Sized,
|
||||||
|
<K as PublicKey>::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<H: Hasher>(&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,")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in new issue