wasi-crypto 0.1.9

Experimental implementation of the WASI cryptography APIs
Documentation
use ::sha2::{Digest, Sha256, Sha384, Sha512, Sha512_256};

use super::state::*;
use super::*;

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone)]
enum HashVariant {
    Sha256(Sha256),
    Sha384(Sha384),
    Sha512(Sha512),
    Sha512_256(Sha512_256),
}

#[derive(Derivative, Clone)]
#[derivative(Debug)]
pub struct Sha2SymmetricState {
    pub alg: SymmetricAlgorithm,
    options: Option<SymmetricOptions>,
    size_limit: Option<usize>,
    ctx: HashVariant,
}

impl Sha2SymmetricState {
    pub fn new(
        alg: SymmetricAlgorithm,
        key: Option<&SymmetricKey>,
        options: Option<SymmetricOptions>,
        size_limit: Option<usize>,
    ) -> Result<Self, CryptoError> {
        if key.is_some() {
            return Err(CryptoError::KeyNotSupported);
        }
        let ctx = match alg {
            SymmetricAlgorithm::Sha256 => HashVariant::Sha256(Sha256::new()),
            SymmetricAlgorithm::Sha384 => HashVariant::Sha384(Sha384::new()),
            SymmetricAlgorithm::Sha512 => HashVariant::Sha512(Sha512::new()),
            SymmetricAlgorithm::Sha512_256 => HashVariant::Sha512_256(Sha512_256::new()),
            _ => bail!(CryptoError::UnsupportedAlgorithm),
        };
        Ok(Sha2SymmetricState {
            alg,
            options,
            size_limit,
            ctx,
        })
    }
}

impl SymmetricStateLike for Sha2SymmetricState {
    fn alg(&self) -> SymmetricAlgorithm {
        self.alg
    }

    fn options_get(&self, name: &str) -> Result<Vec<u8>, CryptoError> {
        self.options
            .as_ref()
            .ok_or(CryptoError::OptionNotSet)?
            .get(name)
    }

    fn options_get_u64(&self, name: &str) -> Result<u64, CryptoError> {
        self.options
            .as_ref()
            .ok_or(CryptoError::OptionNotSet)?
            .get_u64(name)
    }

    fn size_limit(&self) -> Option<usize> {
        self.size_limit
    }

    fn absorb_unchecked(&mut self, data: &[u8]) -> Result<(), CryptoError> {
        match &mut self.ctx {
            HashVariant::Sha256(x) => x.update(data),
            HashVariant::Sha384(x) => x.update(data),
            HashVariant::Sha512(x) => x.update(data),
            HashVariant::Sha512_256(x) => x.update(data),
        };
        Ok(())
    }

    fn squeeze_unchecked(&mut self, out: &mut [u8]) -> Result<(), CryptoError> {
        let raw = match &self.ctx {
            HashVariant::Sha256(x) => x.clone().finalize().to_vec(),
            HashVariant::Sha384(x) => x.clone().finalize().to_vec(),
            HashVariant::Sha512(x) => x.clone().finalize().to_vec(),
            HashVariant::Sha512_256(x) => x.clone().finalize().to_vec(),
        };
        ensure!(raw.len() >= out.len(), CryptoError::InvalidLength);
        out.copy_from_slice(&raw[..out.len()]);
        Ok(())
    }
}