#[cfg(feature = "rust-crypto")]
pub use rust_crypto::*;
use wasefire_applet_api::crypto::hash as api;
use wasefire_error::Code;
pub use self::api::Algorithm;
use crate::{Error, convert, convert_bool, convert_unit};
#[cfg(feature = "api-crypto-hash")]
pub struct Digest {
id: usize,
len: usize,
}
#[cfg(feature = "api-crypto-hash")]
impl Digest {
pub fn new(algorithm: Algorithm) -> Result<Self, Error> {
if !is_supported(algorithm) {
return Err(Error::world(Code::NotImplemented));
}
let params = api::initialize::Params { algorithm: algorithm as usize };
let id = convert(unsafe { api::initialize(params) })?;
let len = algorithm.digest_len();
Ok(Self { id, len })
}
pub fn update(&mut self, data: &[u8]) {
let params = api::update::Params { id: self.id, data: data.as_ptr(), length: data.len() };
convert_unit(unsafe { api::update(params) }).unwrap();
}
pub fn finalize(mut self, digest: &mut [u8]) -> Result<(), Error> {
if digest.len() != self.len {
return Err(Error::user(0));
}
let params = api::finalize::Params { id: self.id, digest: digest.as_mut_ptr() };
self.id = usize::MAX;
convert_unit(unsafe { api::finalize(params) })
}
pub fn digest(algorithm: Algorithm, data: &[u8], digest: &mut [u8]) -> Result<(), Error> {
let mut context = Self::new(algorithm)?;
context.update(data);
context.finalize(digest)
}
}
#[cfg(feature = "api-crypto-hash")]
impl Drop for Digest {
fn drop(&mut self) {
if self.id == usize::MAX {
return;
}
let params = api::finalize::Params { id: self.id, digest: core::ptr::null_mut() };
convert_unit(unsafe { api::finalize(params) }).unwrap();
}
}
#[cfg(feature = "api-crypto-hmac")]
pub struct Hmac {
id: usize,
len: usize,
}
#[cfg(feature = "api-crypto-hmac")]
impl Hmac {
pub fn new(algorithm: Algorithm, key: &[u8]) -> Result<Self, Error> {
if !is_hmac_supported(algorithm) {
return Err(Error::world(Code::NotImplemented));
}
let params = api::hmac_initialize::Params {
algorithm: algorithm as usize,
key: key.as_ptr(),
key_len: key.len(),
};
let id = convert(unsafe { api::hmac_initialize(params) })?;
let len = algorithm.digest_len();
Ok(Self { id, len })
}
pub fn update(&mut self, data: &[u8]) {
let params =
api::hmac_update::Params { id: self.id, data: data.as_ptr(), length: data.len() };
convert_unit(unsafe { api::hmac_update(params) }).unwrap();
}
pub fn finalize(mut self, hmac: &mut [u8]) -> Result<(), Error> {
if hmac.len() != self.len {
return Err(Error::user(0));
}
let params = api::hmac_finalize::Params { id: self.id, hmac: hmac.as_mut_ptr() };
self.id = usize::MAX;
convert_unit(unsafe { api::hmac_finalize(params) })
}
pub fn hmac(
algorithm: Algorithm, key: &[u8], data: &[u8], hmac: &mut [u8],
) -> Result<(), Error> {
let mut context = Self::new(algorithm, key)?;
context.update(data);
context.finalize(hmac)
}
}
#[cfg(feature = "api-crypto-hmac")]
impl Drop for Hmac {
fn drop(&mut self) {
if self.id == usize::MAX {
return;
}
let params = api::hmac_finalize::Params { id: self.id, hmac: core::ptr::null_mut() };
convert_unit(unsafe { api::hmac_finalize(params) }).unwrap();
}
}
#[cfg(feature = "api-crypto-hash")]
pub fn sha256(data: &[u8]) -> Result<[u8; 32], Error> {
let mut digest = [0; 32];
Digest::digest(Algorithm::Sha256, data, &mut digest)?;
Ok(digest)
}
#[cfg(feature = "api-crypto-hmac")]
pub fn hmac_sha256(key: &[u8], data: &[u8]) -> Result<[u8; 32], Error> {
let mut hmac = [0; 32];
Hmac::hmac(Algorithm::Sha256, key, data, &mut hmac)?;
Ok(hmac)
}
#[cfg(feature = "api-crypto-hkdf")]
pub fn hkdf(
algorithm: Algorithm, salt: Option<&[u8]>, ikm: &[u8], info: &[u8], okm: &mut [u8],
) -> Result<(), Error> {
let mut prk = alloc::vec![0; algorithm.digest_len()];
hkdf_extract(algorithm, salt, ikm, &mut prk)?;
hkdf_expand(algorithm, &prk, info, okm)
}
#[cfg(feature = "api-crypto-hkdf")]
pub fn hkdf_extract(
algorithm: Algorithm, salt: Option<&[u8]>, ikm: &[u8], prk: &mut [u8],
) -> Result<(), Error> {
use alloc::borrow::Cow;
let salt = match salt {
Some(x) => Cow::Borrowed(x),
None => Cow::Owned(alloc::vec![0; algorithm.digest_len()]),
};
Hmac::hmac(algorithm, &salt, ikm, prk)
}
#[cfg(feature = "api-crypto-hkdf")]
pub fn hkdf_expand(
algorithm: Algorithm, prk: &[u8], info: &[u8], okm: &mut [u8],
) -> Result<(), Error> {
let params = api::hkdf_expand::Params {
algorithm: algorithm as usize,
prk: prk.as_ptr(),
prk_len: prk.len(),
info: info.as_ptr(),
info_len: info.len(),
okm: okm.as_mut_ptr(),
okm_len: okm.len(),
};
convert_unit(unsafe { api::hkdf_expand(params) })
}
#[cfg(feature = "api-crypto-hash")]
pub fn is_supported(algorithm: Algorithm) -> bool {
let params = api::is_supported::Params { algorithm: algorithm as usize };
convert_bool(unsafe { api::is_supported(params) }).unwrap_or(false)
}
#[cfg(feature = "api-crypto-hmac")]
pub fn is_hmac_supported(algorithm: Algorithm) -> bool {
let params = api::is_hmac_supported::Params { algorithm: algorithm as usize };
convert_bool(unsafe { api::is_hmac_supported(params) }).unwrap_or(false)
}
#[cfg(feature = "api-crypto-hkdf")]
pub fn is_hkdf_supported(algorithm: Algorithm) -> bool {
let params = api::is_hkdf_supported::Params { algorithm: algorithm as usize };
convert_bool(unsafe { api::is_hkdf_supported(params) }).unwrap_or(false)
}
#[cfg(feature = "rust-crypto")]
mod rust_crypto {
#[cfg(feature = "api-crypto-hmac")]
use crypto_common::{KeyInit, KeySizeUser};
#[cfg(feature = "api-crypto-hash")]
use digest::HashMarker;
#[cfg(feature = "api-crypto-hmac")]
use digest::MacMarker;
use digest::{FixedOutput, OutputSizeUser, Update};
use super::*;
#[cfg(feature = "api-crypto-hash")]
pub struct Sha256(Digest);
#[cfg(feature = "api-crypto-hash")]
pub struct Sha384(Digest);
#[cfg(feature = "api-crypto-hmac")]
pub struct HmacSha256(Hmac);
#[cfg(feature = "api-crypto-hmac")]
pub struct HmacSha384(Hmac);
#[cfg(feature = "api-crypto-hash")]
impl HashMarker for Sha256 {}
#[cfg(feature = "api-crypto-hash")]
impl HashMarker for Sha384 {}
#[cfg(feature = "api-crypto-hash")]
impl Default for Sha256 {
fn default() -> Self {
Self(Digest::new(Algorithm::Sha256).unwrap())
}
}
#[cfg(feature = "api-crypto-hash")]
impl Default for Sha384 {
fn default() -> Self {
Self(Digest::new(Algorithm::Sha384).unwrap())
}
}
#[cfg(feature = "api-crypto-hash")]
impl Update for Sha256 {
fn update(&mut self, data: &[u8]) {
self.0.update(data);
}
}
#[cfg(feature = "api-crypto-hash")]
impl Update for Sha384 {
fn update(&mut self, data: &[u8]) {
self.0.update(data);
}
}
#[cfg(feature = "api-crypto-hash")]
impl OutputSizeUser for Sha256 {
type OutputSize = digest::consts::U32;
}
#[cfg(feature = "api-crypto-hash")]
impl OutputSizeUser for Sha384 {
type OutputSize = digest::consts::U48;
}
#[cfg(feature = "api-crypto-hash")]
impl FixedOutput for Sha256 {
fn finalize_into(self, out: &mut digest::Output<Self>) {
self.0.finalize(out).unwrap();
}
}
#[cfg(feature = "api-crypto-hash")]
impl FixedOutput for Sha384 {
fn finalize_into(self, out: &mut digest::Output<Self>) {
self.0.finalize(out).unwrap();
}
}
#[cfg(feature = "api-crypto-hmac")]
impl MacMarker for HmacSha256 {}
#[cfg(feature = "api-crypto-hmac")]
impl MacMarker for HmacSha384 {}
#[cfg(feature = "api-crypto-hmac")]
impl KeySizeUser for HmacSha256 {
type KeySize = digest::consts::U64;
}
#[cfg(feature = "api-crypto-hmac")]
impl KeySizeUser for HmacSha384 {
type KeySize = digest::consts::U128;
}
#[cfg(feature = "api-crypto-hmac")]
impl KeyInit for HmacSha256 {
fn new(key: &digest::Key<Self>) -> Self {
Self::new_from_slice(key).unwrap()
}
fn new_from_slice(key: &[u8]) -> Result<Self, crypto_common::InvalidLength> {
match Hmac::new(Algorithm::Sha256, key) {
Err(e) if e == Error::user(Code::InvalidLength) => {
Err(crypto_common::InvalidLength)
}
x => Ok(Self(x.unwrap())),
}
}
}
#[cfg(feature = "api-crypto-hmac")]
impl KeyInit for HmacSha384 {
fn new(key: &digest::Key<Self>) -> Self {
Self::new_from_slice(key).unwrap()
}
fn new_from_slice(key: &[u8]) -> Result<Self, crypto_common::InvalidLength> {
Ok(Self(Hmac::new(Algorithm::Sha384, key).unwrap()))
}
}
#[cfg(feature = "api-crypto-hmac")]
impl Update for HmacSha256 {
fn update(&mut self, data: &[u8]) {
self.0.update(data);
}
}
#[cfg(feature = "api-crypto-hmac")]
impl Update for HmacSha384 {
fn update(&mut self, data: &[u8]) {
self.0.update(data);
}
}
#[cfg(feature = "api-crypto-hmac")]
impl OutputSizeUser for HmacSha256 {
type OutputSize = digest::consts::U32;
}
#[cfg(feature = "api-crypto-hmac")]
impl OutputSizeUser for HmacSha384 {
type OutputSize = digest::consts::U48;
}
#[cfg(feature = "api-crypto-hmac")]
impl FixedOutput for HmacSha256 {
fn finalize_into(self, out: &mut digest::Output<Self>) {
self.0.finalize(out).unwrap()
}
}
#[cfg(feature = "api-crypto-hmac")]
impl FixedOutput for HmacSha384 {
fn finalize_into(self, out: &mut digest::Output<Self>) {
self.0.finalize(out).unwrap()
}
}
}