pub type Hash = [u8; 32];
pub trait SgxHashOps {
fn new() -> Self;
fn update(&mut self, data: &[u8]);
fn finish(self) -> Hash;
}
pub trait SgxRsaOps {
type Error: ::std::error::Error;
fn len(&self) -> usize;
fn sign_sha256_pkcs1v1_5_with_q1_q2<H: AsRef<[u8]>>(
&self,
hash: H,
) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), Self::Error>;
fn verify_sha256_pkcs1v1_5<S: AsRef<[u8]>, H: AsRef<[u8]>>(
&self,
sig: S,
hash: H,
) -> Result<(), Self::Error>;
fn e(&self) -> Vec<u8>;
fn n(&self) -> Vec<u8>;
}
pub trait SgxRsaPubOps {
type Error: ::std::error::Error;
fn calculate_q1_q2(&self, s: &[u8]) -> Result<(Vec<u8>, Vec<u8>), Self::Error>;
}
#[cfg(feature = "crypto-openssl")]
mod openssl {
use super::*;
use foreign_types::ForeignTypeRef;
use openssl::bn::{BigNum, BigNumRef, BigNumContext};
use openssl::error::ErrorStack as SslError;
use openssl::hash::{Hasher, MessageDigest};
use openssl::nid::Nid;
use openssl::pkey::{HasPublic, Private, Public};
use openssl::rsa::RsaRef;
use openssl_sys as ffi;
pub fn calculate_q1_q2(n: &BigNumRef, s_slice: &[u8]) -> Result<(Vec<u8>, Vec<u8>), SslError> {
let mut s_2 = BigNum::new()?;
let mut s_3 = BigNum::new()?;
let mut q1 = BigNum::new()?;
let mut tmp1 = BigNum::new()?;
let mut tmp2 = BigNum::new()?;
let mut tmp3 = BigNum::new()?;
let mut q2 = BigNum::new()?;
let mut ctx = BigNumContext::new()?;
let s = BigNum::from_slice(s_slice)?;
s_2.sqr(&s, &mut ctx)?;
q1.checked_div(&s_2, &n, &mut ctx)?;
s_3.checked_mul(&s_2, &s, &mut ctx)?;
tmp1.checked_mul(&q1, &s, &mut ctx)?;
tmp2.checked_mul(&tmp1, &n, &mut ctx)?;
tmp3.checked_sub(&s_3, &tmp2)?;
q2.checked_div(&tmp3, &n, &mut ctx)?;
let mut q1 = q1.to_vec();
let mut q2 = q2.to_vec();
q1.reverse();
q2.reverse();
Ok((q1, q2))
}
impl SgxHashOps for Hasher {
fn new() -> Self {
Hasher::new(MessageDigest::sha256()).expect("failed to create openssl hasher")
}
fn update(&mut self, data: &[u8]) {
self.update(data).expect("failed to update openssl hasher");
}
fn finish(mut self) -> Hash {
let mut hash = [0u8; 32];
hash.copy_from_slice(
&Hasher::finish(&mut self).expect("failed to finish openssl hasher"),
);
hash
}
}
pub trait MaybePrivate: Sized {
fn as_private(rsa: &RsaRef<Self>) -> &RsaRef<Private>;
}
impl MaybePrivate for Private {
fn as_private(rsa: &RsaRef<Self>) -> &RsaRef<Private> {
rsa
}
}
impl MaybePrivate for Public {
fn as_private(_rsa: &RsaRef<Self>) -> &RsaRef<Private> {
panic!("Requires private key!")
}
}
impl<T: HasPublic + MaybePrivate> SgxRsaOps for RsaRef<T> {
type Error = SslError;
fn len(&self) -> usize {
self.n().num_bits() as _
}
fn sign_sha256_pkcs1v1_5_with_q1_q2<H: AsRef<[u8]>>(
&self,
hash: H,
) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>), Self::Error> {
let mut s_vec = unsafe {
let mut r = vec![0; self.size() as _];
let mut len = 0;
let rv = ffi::RSA_sign(
Nid::SHA256.as_raw(),
hash.as_ref().as_ptr(),
hash.as_ref().len() as _,
r.as_mut_ptr(),
&mut len,
self.as_ptr(),
);
if rv < 0 {
return Err(SslError::get());
} else {
r.truncate(len as _);
r
}
};
let (q1, q2) = calculate_q1_q2(self.n(), &s_vec)?;
s_vec.reverse();
Ok((s_vec, q1, q2))
}
fn verify_sha256_pkcs1v1_5<S: AsRef<[u8]>, H: AsRef<[u8]>>(
&self,
sig: S,
hash: H,
) -> Result<(), Self::Error> {
let mut sig = sig.as_ref().to_owned();
sig.reverse();
let ret = unsafe {
ffi::RSA_verify(
Nid::SHA256.as_raw(),
hash.as_ref().as_ptr(),
hash.as_ref().len() as _,
sig.as_mut_ptr(),
sig.len() as _,
self.as_ptr(),
)
};
if ret == 1 {
Ok(())
} else {
Err(SslError::get())
}
}
fn e(&self) -> Vec<u8> {
let mut v = self.e().to_vec();
v.reverse();
v
}
fn n(&self) -> Vec<u8> {
let mut v = self.n().to_vec();
v.reverse();
v
}
}
impl<T: HasPublic> SgxRsaPubOps for RsaRef<T> {
type Error = SslError;
fn calculate_q1_q2(&self, s: &[u8]) -> Result<(Vec<u8>, Vec<u8>), Self::Error> {
calculate_q1_q2(self.n(), s)
}
}
}
#[cfg(feature = "sha2")]
mod sha2 {
use super::*;
use sha2::{Digest, Sha256};
impl SgxHashOps for Sha256 {
fn new() -> Self {
<Sha256 as Digest>::new()
}
fn update(&mut self, data: &[u8]) {
self.input(data)
}
fn finish(self) -> Hash {
let mut hash = [0u8; 32];
hash.copy_from_slice(self.result().as_slice());
hash
}
}
}
#[cfg(all(test))]
mod tests;