wasi-crypto 0.1.10

Experimental implementation of the WASI cryptography APIs
Documentation
mod dh;
mod kem;
mod keypair;
mod publickey;
mod secretkey;

use std::any::Any;
use std::convert::TryFrom;
use std::sync::{Arc, Mutex};

pub use keypair::*;
pub use publickey::*;
pub use secretkey::*;

use self::dh::*;
use self::kem::*;
use crate::array_output::*;
use crate::error::*;
use crate::handles::*;
use crate::options::*;

#[derive(Debug, Default)]
pub struct KxOptionsInner {
    context: Option<Vec<u8>>,
}

#[derive(Clone, Debug, Default)]
pub struct KxOptions {
    inner: Arc<Mutex<KxOptionsInner>>,
}

impl OptionsLike for KxOptions {
    fn as_any(&self) -> &dyn Any {
        self
    }

    fn set(&mut self, _name: &str, _value: &[u8]) -> Result<(), CryptoError> {
        bail!(CryptoError::UnsupportedOption)
    }

    fn set_u64(&mut self, _name: &str, _value: u64) -> Result<(), CryptoError> {
        bail!(CryptoError::UnsupportedOption)
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum KxAlgorithm {
    X25519,
    Kyber768,
    Kyber1024,
}

impl TryFrom<&str> for KxAlgorithm {
    type Error = CryptoError;

    fn try_from(alg_str: &str) -> Result<Self, CryptoError> {
        match alg_str.to_uppercase().as_str() {
            "X25519" => Ok(KxAlgorithm::X25519),
            "KYBER-768" => Ok(KxAlgorithm::Kyber768),
            "KYBER-1024" => Ok(KxAlgorithm::Kyber1024),
            _ => bail!(CryptoError::UnsupportedAlgorithm),
        }
    }
}

#[test]
fn test_key_exchange() {
    use crate::{AlgorithmType, CryptoCtx, KeyPairEncoding};

    let ctx = CryptoCtx::new();

    let kx_kp_handle1 = ctx
        .keypair_generate(AlgorithmType::KeyExchange, "X25519", None)
        .unwrap();
    let kx_kp_raw_bytes_handle = ctx
        .keypair_export(kx_kp_handle1, KeyPairEncoding::Raw)
        .unwrap();
    let mut kx_kp_raw_bytes = vec![0u8; ctx.array_output_len(kx_kp_raw_bytes_handle).unwrap()];
    ctx.array_output_pull(kx_kp_raw_bytes_handle, &mut kx_kp_raw_bytes)
        .unwrap();

    let pk1 = ctx.keypair_publickey(kx_kp_handle1).unwrap();
    let sk1 = ctx.keypair_secretkey(kx_kp_handle1).unwrap();

    let kx_kp_handle2 = ctx
        .keypair_generate(AlgorithmType::KeyExchange, "X25519", None)
        .unwrap();
    let pk2 = ctx.keypair_publickey(kx_kp_handle2).unwrap();
    let sk2 = ctx.keypair_secretkey(kx_kp_handle2).unwrap();

    let shared_key1_handle = ctx.kx_dh(pk1, sk2).unwrap();
    let mut shared_key1_raw_bytes = vec![0u8; ctx.array_output_len(shared_key1_handle).unwrap()];
    ctx.array_output_pull(shared_key1_handle, &mut shared_key1_raw_bytes)
        .unwrap();

    let shared_key2_handle = ctx.kx_dh(pk2, sk1).unwrap();
    let mut shared_key2_raw_bytes = vec![0u8; ctx.array_output_len(shared_key2_handle).unwrap()];
    ctx.array_output_pull(shared_key2_handle, &mut shared_key2_raw_bytes)
        .unwrap();

    assert_eq!(shared_key1_raw_bytes, shared_key2_raw_bytes);

    ctx.keypair_close(kx_kp_handle1).unwrap();
    ctx.keypair_close(kx_kp_handle2).unwrap();
}

#[cfg(feature = "pqcrypto")]
#[test]
fn test_key_encapsulation() {
    use crate::{AlgorithmType, CryptoCtx, KeyPairEncoding};

    let ctx = CryptoCtx::new();

    let kx_kp_handle = ctx
        .keypair_generate(AlgorithmType::KeyExchange, "Kyber-1024", None)
        .unwrap();
    let pk = ctx.keypair_publickey(kx_kp_handle).unwrap();
    let sk = ctx.keypair_secretkey(kx_kp_handle).unwrap();

    let (secret_handle, encapsulated_secret_handle) = ctx.kx_encapsulate(pk).unwrap();
    let mut secret_raw_bytes = vec![0u8; ctx.array_output_len(secret_handle).unwrap()];
    ctx.array_output_pull(secret_handle, &mut secret_raw_bytes)
        .unwrap();
    let mut encapsulated_secret_raw_bytes =
        vec![0u8; ctx.array_output_len(encapsulated_secret_handle).unwrap()];
    ctx.array_output_pull(
        encapsulated_secret_handle,
        &mut encapsulated_secret_raw_bytes,
    )
    .unwrap();

    let decapsulated_secret_handle = ctx
        .kx_decapsulate(sk, &encapsulated_secret_raw_bytes)
        .unwrap();
    let mut decapsulated_secret_raw_bytes =
        vec![0u8; ctx.array_output_len(decapsulated_secret_handle).unwrap()];
    ctx.array_output_pull(
        decapsulated_secret_handle,
        &mut decapsulated_secret_raw_bytes,
    )
    .unwrap();

    assert_eq!(secret_raw_bytes, decapsulated_secret_raw_bytes);
}