wasi-crypto 0.1.10

Experimental implementation of the WASI cryptography APIs
Documentation
use std::convert::TryFrom;

use super::*;
use crate::options::Options;
use crate::AlgorithmType;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum KeyPairEncoding {
    Raw,
    Pkcs8,
    Pem,
    Local,
}

#[derive(Clone)]
pub enum KeyPair {
    Signature(SignatureKeyPair),
    KeyExchange(KxKeyPair),
}

impl KeyPair {
    pub(crate) fn into_signature_keypair(self) -> Result<SignatureKeyPair, CryptoError> {
        match self {
            KeyPair::Signature(kp) => Ok(kp),
            _ => bail!(CryptoError::InvalidHandle),
        }
    }

    pub(crate) fn into_kx_keypair(self) -> Result<KxKeyPair, CryptoError> {
        match self {
            KeyPair::KeyExchange(kp) => Ok(kp),
            _ => bail!(CryptoError::InvalidHandle),
        }
    }

    pub fn export(&self, encoding: KeyPairEncoding) -> Result<Vec<u8>, CryptoError> {
        match self {
            KeyPair::Signature(key_pair) => key_pair.export(encoding),
            KeyPair::KeyExchange(key_pair) => key_pair.export(encoding),
        }
    }

    pub fn generate(
        alg_type: AlgorithmType,
        alg_str: &str,
        options: Option<Options>,
    ) -> Result<KeyPair, CryptoError> {
        match alg_type {
            AlgorithmType::Signatures => {
                let options = match options {
                    None => None,
                    Some(options) => Some(options.into_signatures()?),
                };
                Ok(KeyPair::Signature(SignatureKeyPair::generate(
                    SignatureAlgorithm::try_from(alg_str)?,
                    options,
                )?))
            }
            AlgorithmType::KeyExchange => {
                let options = match options {
                    None => None,
                    Some(options) => Some(options.into_key_exchange()?),
                };
                Ok(KeyPair::KeyExchange(KxKeyPair::generate(
                    KxAlgorithm::try_from(alg_str)?,
                    options,
                )?))
            }
            _ => bail!(CryptoError::InvalidOperation),
        }
    }

    pub fn import(
        alg_type: AlgorithmType,
        alg_str: &str,
        encoded: &[u8],
        encoding: KeyPairEncoding,
    ) -> Result<KeyPair, CryptoError> {
        match alg_type {
            AlgorithmType::Signatures => Ok(KeyPair::Signature(SignatureKeyPair::import(
                SignatureAlgorithm::try_from(alg_str)?,
                encoded,
                encoding,
            )?)),
            _ => bail!(CryptoError::InvalidOperation),
        }
    }

    pub fn from_pk_and_sk(_pk: PublicKey, _sk: SecretKey) -> Result<KeyPair, CryptoError> {
        match (_pk, _sk) {
            (PublicKey::Signature(pk), SecretKey::Signature(sk)) => {
                ensure!(pk.alg() == sk.alg(), CryptoError::IncompatibleKeys);
            }
            (PublicKey::KeyExchange(pk), SecretKey::KeyExchange(sk)) => {
                ensure!(pk.alg() == sk.alg(), CryptoError::IncompatibleKeys);
            }
            _ => bail!(CryptoError::IncompatibleKeys),
        }
        bail!(CryptoError::NotImplemented);
    }

    pub fn public_key(&self) -> Result<PublicKey, CryptoError> {
        match self {
            KeyPair::Signature(key_pair) => Ok(PublicKey::Signature(key_pair.public_key()?)),
            KeyPair::KeyExchange(key_pair) => Ok(PublicKey::KeyExchange(key_pair.public_key()?)),
        }
    }

    pub fn secret_key(&self) -> Result<SecretKey, CryptoError> {
        match self {
            KeyPair::Signature(key_pair) => Ok(SecretKey::Signature(key_pair.secret_key()?)),
            KeyPair::KeyExchange(key_pair) => Ok(SecretKey::KeyExchange(key_pair.secret_key()?)),
        }
    }
}

impl CryptoCtx {
    pub fn keypair_generate(
        &self,
        alg_type: AlgorithmType,
        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)?),
        };
        let kp = KeyPair::generate(alg_type, alg_str, options)?;
        let handle = self.handles.keypair.register(kp)?;
        Ok(handle)
    }

    pub fn keypair_import(
        &self,
        alg_type: AlgorithmType,
        alg_str: &str,
        encoded: &[u8],
        encoding: KeyPairEncoding,
    ) -> Result<Handle, CryptoError> {
        let kp = KeyPair::import(alg_type, alg_str, encoded, encoding)?;
        let handle = self.handles.keypair.register(kp)?;
        Ok(handle)
    }

    pub fn keypair_id(&self, kp_handle: Handle) -> Result<(Vec<u8>, Version), CryptoError> {
        let _kp = self.handles.keypair.get(kp_handle)?;
        bail!(CryptoError::UnsupportedFeature)
    }

    pub fn keypair_from_pk_and_sk(
        &self,
        pk_handle: Handle,
        sk_handle: Handle,
    ) -> Result<Handle, CryptoError> {
        let pk = self.handles.publickey.get(pk_handle)?;
        let sk = self.handles.secretkey.get(sk_handle)?;
        let kp = KeyPair::from_pk_and_sk(pk, sk)?;
        let handle = self.handles.keypair.register(kp)?;
        Ok(handle)
    }

    pub fn keypair_export(
        &self,
        kp_handle: Handle,
        encoding: KeyPairEncoding,
    ) -> Result<Handle, CryptoError> {
        let kp = self.handles.keypair.get(kp_handle)?;
        let encoded = kp.export(encoding)?;
        let array_output_handle = ArrayOutput::register(&self.handles, encoded)?;
        Ok(array_output_handle)
    }

    pub fn keypair_publickey(&self, kp_handle: Handle) -> Result<Handle, CryptoError> {
        let kp = self.handles.keypair.get(kp_handle)?;
        let pk = kp.public_key()?;
        let handle = self.handles.publickey.register(pk)?;
        Ok(handle)
    }

    pub fn keypair_secretkey(&self, kp_handle: Handle) -> Result<Handle, CryptoError> {
        let kp = self.handles.keypair.get(kp_handle)?;
        let sk = kp.secret_key()?;
        let handle = self.handles.secretkey.register(sk)?;
        Ok(handle)
    }

    pub fn keypair_close(&self, kp_handle: Handle) -> Result<(), CryptoError> {
        self.handles.keypair.close(kp_handle)
    }
}