wasi-crypto 0.1.15

Experimental implementation of the WASI cryptography APIs
Documentation
use std::sync::{Arc, Mutex, MutexGuard};

use super::*;
use crate::array_output::*;
use crate::version::*;
use crate::CryptoCtx;

#[derive(Clone)]
pub struct SymmetricKey {
    inner: Arc<Mutex<Box<dyn SymmetricKeyLike>>>,
}

pub trait SymmetricKeyBuilder {
    fn generate(&self, options: Option<SymmetricOptions>) -> Result<SymmetricKey, CryptoError>;

    fn import(&self, raw: &[u8]) -> Result<SymmetricKey, CryptoError>;

    fn key_len(&self) -> Result<usize, CryptoError>;
}

impl SymmetricKey {
    pub fn new(symmetric_key_like: Box<dyn SymmetricKeyLike>) -> Self {
        SymmetricKey {
            inner: Arc::new(Mutex::new(symmetric_key_like)),
        }
    }

    pub fn inner(&self) -> MutexGuard<'_, Box<dyn SymmetricKeyLike>> {
        self.inner.lock().unwrap()
    }

    pub fn locked<T, U>(&self, mut f: T) -> U
    where
        T: FnMut(MutexGuard<'_, Box<dyn SymmetricKeyLike>>) -> U,
    {
        f(self.inner())
    }

    pub fn alg(&self) -> SymmetricAlgorithm {
        self.inner().alg()
    }

    pub fn builder(alg_str: &str) -> Result<Box<dyn SymmetricKeyBuilder>, CryptoError> {
        let alg = SymmetricAlgorithm::try_from(alg_str)?;
        let builder = match alg {
            SymmetricAlgorithm::HmacSha256 | SymmetricAlgorithm::HmacSha512 => {
                HmacSha2SymmetricKeyBuilder::new(alg)
            }
            SymmetricAlgorithm::HkdfSha256Expand
            | SymmetricAlgorithm::HkdfSha256Extract
            | SymmetricAlgorithm::HkdfSha512Expand
            | SymmetricAlgorithm::HkdfSha512Extract => HkdfSymmetricKeyBuilder::new(alg),
            SymmetricAlgorithm::Aes128Gcm | SymmetricAlgorithm::Aes256Gcm => {
                AesGcmSymmetricKeyBuilder::new(alg)
            }
            SymmetricAlgorithm::Xoodyak128 | SymmetricAlgorithm::Xoodyak160 => {
                XoodyakSymmetricKeyBuilder::new(alg)
            }
            SymmetricAlgorithm::ChaCha20Poly1305 | SymmetricAlgorithm::XChaCha20Poly1305 => {
                ChaChaPolySymmetricKeyBuilder::new(alg)
            }
            _ => bail!(CryptoError::InvalidOperation),
        };
        Ok(builder)
    }

    fn generate(
        alg_str: &str,
        options: Option<SymmetricOptions>,
    ) -> Result<SymmetricKey, CryptoError> {
        let builder = Self::builder(alg_str)?;
        builder.generate(options)
    }

    fn import(alg_str: &str, raw: &[u8]) -> Result<SymmetricKey, CryptoError> {
        let builder = Self::builder(alg_str)?;
        builder.import(raw)
    }
}

pub trait SymmetricKeyLike: Sync + Send {
    fn as_any(&self) -> &dyn Any;
    fn alg(&self) -> SymmetricAlgorithm;
    fn as_raw(&self) -> Result<&[u8], CryptoError>;
}

impl CryptoCtx {
    pub fn symmetric_key_generate(
        &self,
        alg_str: &str,
        options_handle: Option<Handle>,
    ) -> Result<Handle, CryptoError> {
        let options = match options_handle {
            None => None,
            Some(options_handle) => {
                Some(self.handles.options.get(options_handle)?.into_symmetric()?)
            }
        };
        let symmetric_key = SymmetricKey::generate(alg_str, options)?;
        let handle = self.handles.symmetric_key.register(symmetric_key)?;
        Ok(handle)
    }

    pub fn symmetric_key_import(&self, alg_str: &str, raw: &[u8]) -> Result<Handle, CryptoError> {
        let symmetric_key = SymmetricKey::import(alg_str, raw)?;
        let handle = self.handles.symmetric_key.register(symmetric_key)?;
        Ok(handle)
    }

    pub fn symmetric_key_export(
        &self,
        symmetric_key_handle: Handle,
    ) -> Result<Handle, CryptoError> {
        let symmetric_key = self.handles.symmetric_key.get(symmetric_key_handle)?;
        let array_output_handle =
            ArrayOutput::register(&self.handles, symmetric_key.inner().as_raw()?.to_vec())?;
        Ok(array_output_handle)
    }

    pub fn symmetric_key_id(
        &self,
        symmetric_key_handle: Handle,
    ) -> Result<(Vec<u8>, Version), CryptoError> {
        let _symmetric_key = self.handles.symmetric_key.get(symmetric_key_handle)?;
        bail!(CryptoError::UnsupportedFeature)
    }

    pub fn symmetric_key_close(&self, symmetric_key_handle: Handle) -> Result<(), CryptoError> {
        self.handles.symmetric_key.close(symmetric_key_handle)
    }
}