Klave logo

Subtle Crypto

The Subtle Crypto Interface provides an advanced way to manage cryptographic operations such as encryption, decryption, signing, signature verifications, key wrapping/unwrapping, key import/export, etc. The Key lifecycle management should be done by the developers. The Subtle Crypto interface offers more algoritm and cryptographic mode as well as configuration.

Generating Keys

ClassOperationParameters: typeReturnsBehavior
Crypto.SubtlegenerateKeyalgorithm: T, extractable: boolean, usages: string[]Result<CryptoKey, Error>Generate a CryptoKey based on the algorithm object and usages provided. Return a ResultSet Result<CryptoKey, Error> containing either the generated CryptoKey or an Error.

A CryptoKey contains the key type and usages and is an handle on the key.

class CryptoKey extends Key
{
    algorithm!: string;
    extractable!: boolean;
    usages!: string[];
}
ClassOperationParameters: typeReturnsBehavior
crypto::subtlegenerate_keyalgorithm: GenAlgorithm, extractable: bool, usages: &[&str]Result<CryptoKey, Error>Generate a CryptoKey based on the algorithm object and usages provided. Return a ResultSet Result<CryptoKey, Error> containing either the generated CryptoKey or an Error.

A CryptoKey contains the key type, usages and is an handle on the key.

pub struct CryptoKey {
    id: String,
    alias: Option<String>,
    key_type: String,
    extractable: bool,
    family: String,
    usages: Vec<String>,
    algorithm: String
}

Depending on the type of key that needs to be generated a GenAlgorithm Enum variants is passed as parameters.

pub enum KeyGenAlgorithm {
    Rsa(RsaHashedKeyGenParams),
    Ecc(EcKeyGenParams),
    Aes(AesKeyGenParams),
    Hmac(HmacKeyGenParams),
}

RSA Key

For generating RSA key, the algorithm object to use is Crypto.RsaHashedKeyGenParams.

When generating an RSA Key, only the private key is generated and not a key pair. Usages needs to be align with that, for instance an RSA private key can only be used for signing, decrypting or unwraping.

class RsaHashedKeyGenParams {
    modulusLength: u32 = 2048; // 2048, 3072, 4096
    publicExponent: u32 = 65537;
    hash: string = 'SHA2-256'; // "SHA2-256", "SHA2-384", "SHA2-512"
}
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoRSA(): void
{
    // Generate RSA key
    let rsaKey = Crypto.Subtle.generateKey({modulusLength: 2048, publicExponent: 65537, hash: "SHA2-256"} as Crypto.RsaHashedKeyGenParams, true, ["decrypt", "sign"]);
}

Public key derivation can be done directly from the private key and will automatically get the usages aligned with the private one.

ClassOperationParameters: typeReturnsBehavior
Crypto.SubtlegetPublicKeykey: CryptoKeyResult<CryptoKey, Error>Derive the public CryptoKey corresponding to the private key provided. Return a ResultSet Result<CryptoKey, Error> containing either the generated CryptoKey or an Error.
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoRSA(): void
{
    // Generate RSA key
    let rsaKeyResult = Crypto.Subtle.generateKey({modulusLength: 2048, publicExponent: 65537, hash: "SHA2-256"} as Crypto.RsaHashedKeyGenParams, true, ["decrypt", "sign"]);
    let rsaKey = rsaKeyResult.data as Crypto.CryptoKey;
    // Derive RSA public key
    let publicRsaKeyResult = Crypto.Subtle.getPublicKey(rsaKey);
}

For generating RSA key, the algorithm object to use is RsaHashedKeyGenParams.

When generating an RSA Key, only the private key is generated and not a key pair. Usages needs to be align with that, for instance an RSA private key can only be used for signing, decrypting or unwraping.

pub struct RsaHashedKeyGenParams {
    pub modulus_length: u32, // 2048, 3072, 4096
    pub public_exponent: u32, // 65537
    pub hash: String // "SHA2-256", "SHA2-384", "SHA2-512"
}
use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_rsa(input: String) {
    let rsa_params = subtle::RsaHashedKeyGenParams {
        modulus_length: 2048,
        public_exponent: 65537,
        hash: "SHA2-256"
    };
    let key_usages_slice: Vec<&str> = vec!["decrypt", "sign"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Rsa(rsa_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}

Public key derivation can be done directly from the private key and will automatically get the usages aligned with the private one.

ClassOperationParameters: typeReturnsBehavior
crypto::subtleget_public_keykey: CryptoKeyResult<CryptoKey, Error>Derive the public CryptoKey corresponding to the private key provided. Return a ResultSet Result<CryptoKey, Error> containing either the generated CryptoKey or an Error.
use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_rsa(input: String) {
    let rsa_params = subtle::RsaHashedKeyGenParams {
        modulus_length: 2048,
        public_exponent: 65537,
        hash: "SHA2-256"
    };
    let key_usages_slice: Vec<&str> = vec!["decrypt", "sign"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Rsa(rsa_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    let public_crypto_key: CryptoKey = match subtle::get_public_key(&crypto_key) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}

EC Key

For generating EC key, the algorithm object to use is Crypto.EcKeyGenParams.

When generating an EC Key, only the private key is generated and not a key pair. Usages needs to be align with that, for instance an EC private key can only be used for signing or for derivation.

export class EcKeyGenParams {
    namedCurve: string = 'P-256'; // "P-256", "P-384", "P-521"
}
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoEC(): void
{
    // Generate EC key
    let eccKey = Crypto.Subtle.generateKey({namedCurve: "P-256"} as Crypto.EcKeyGenParams, true, ["sign"]);
}

Public key derivation can be done directly from the private key and will automatically get the usages aligned with the private one.

ClassOperationParameters: typeReturnsBehavior
Crypto.SubtlegetPublicKeykey: CryptoKeyResult<CryptoKey, Error>Derive the public CryptoKey corresponding to the private key provided. Return a ResultSet Result<CryptoKey, Error> containing either the generated CryptoKey or an Error.
/**
* @query
*/
export function subtleCryptoEC(): void
{
    // Generate EC key
    let eccKey = Crypto.Subtle.generateKey({namedCurve: "P-256"} as Crypto.EcKeyGenParams, true, ["sign"]);
    // Derive Public key
    let public_eccKey = Crypto.Subtle.getPublicKey(eccKey);
}

For generating EC key, the algorithm object to use is EcKeyGenParams.

When generating an EC Key, only the private key is generated and not a key pair. Usages needs to be align with that, for instance an EC private key can only be used for signing or for derivation.

pub struct EcKeyGenParams {
    pub named_curve: String // "P-256", "P-384", "P-521"
}
use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_ec(input: String) {
    let ec_params = subtle::EcKeyGenParams { named_curve: "P-256" };
    let key_usages_slice: Vec<&str> = vec!["sign"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Ecc(ec_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}

Public key derivation can be done directly from the private key and will automatically get the usages aligned with the private one.

ClassOperationParameters: typeReturnsBehavior
crypto::subtleget_public_keykey: CryptoKeyResult<CryptoKey, Error>Derive the public CryptoKey corresponding to the private key provided. Return a ResultSet Result<CryptoKey, Error> containing either the generated CryptoKey or an Error.
use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_ec(input: String) {
    let ec_params = subtle::EcKeyGenParams { named_curve: "P-256" };
    let key_usages_slice: Vec<&str> = vec!["sign"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Ecc(ec_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
    let public_key: CryptoKey = match subtle::get_public_key(&crypto_key) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}

AES Key

For generating AES key, the algorithm object to use is Crypto.AesKeyGenParams.

class AesKeyGenParams {
    length: u32 = 256; // 128, 192, 256
}
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoAES(): void
{
    // Generate AES key
    let aesKey = Crypto.Subtle.generateKey({length: 256} as Crypto.AesKeyGenParams, true, ["encrypt", "decrypt"]);
}

For generating AES key, the algorithm object to use is AesKeyGenParams.

pub struct AesKeyGenParams {
    pub length: u32 // 128, 192, 256
}
use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_aes(input: String) {
    let aes_params = subtle::AesKeyGenParams { length: 256 };
    let key_usages_slice: Vec<&str> = vec!["encrypt", "decrypt"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Aes(aes_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}

HMAC Key

For generating HMAC key, the algorithm object to use is Crypto.HmacKeyGenParams.

export class HmacKeyGenParams {
    hash: string = 'SHA2-256'; //SHA2-384, SHA2-512
}
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoHMAC(): void
{
    // Generate HMAC key
    let hmacKey = Crypto.Subtle.generateKey({hash: 'SHA2-256'} as Crypto.HmacKeyGenParams, true, ["sign", "verify"]);
}

For generating HMAC key, the algorithm object to use is HmacKeyGenParams.

pub struct HmacKeyGenParams {
    pub hash: String, //"SHA2-256", "SHA2-384", "SHA2-512"
}
use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_hmac(input: String) {
    let hmac_params = subtle::HmacKeyGenParams { hash: "SHA2-256".to_string() };
    let key_usages_slice: Vec<&str> = vec!["sign", "verify"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Hmac(hmac_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}

Data encryption and decryption

ClassOperationParameters: typeReturnsBehavior
Crypto.Subtleencryptalgorithm: T, key: CryptoKey, clearText: ArrayBufferResult<ArrayBuffer, Error>Encrypt the clearText with the algorithm object and keyprovided. Return an ArrayBuffer containing the cipherText or an Error.
Crypto.Subtledecryptalgorithm: T, key: CryptoKey, cipherText: ArrayBufferResult<ArrayBuffer, Error>Decrypt the cipherText with the algorithm object and keyprovided. Return an ArrayBuffer containing the clearText or an Error.
ClassOperationParameters: typeReturnsBehavior
crypto::subtleencryptalgorithm: EncryptAlgorithm, key: CryptoKey, clearText: [u8]Result<Vec<u8>, Error>Encrypt the clearText with the algorithm object and keyprovided. Return an ArrayBuffer containing the cipherText or an Error.
crypto::subtledecryptalgorithm: EncryptAlgorithm, key: CryptoKey, cipherText: [u8]Result<Vec<u8>, Error>Decrypt the cipherText with the algorithm object and keyprovided. Return an ArrayBuffer containing the clearText or an Error.

Depending on the type of encryption that needs to be done an EncryptAlgorithm Enum variants is passed as parameters.

pub enum EncryptAlgorithm {
    RsaOaep(RsaOaepParams),
    AesGcm(AesGcmParams),
}

AES-GCM

For encrypting with AES-GCM you need an AES key and to use the Crypto.AesGcmParams algorithm object.

class AesGcmParams {
    iv!: ArrayBuffer; // iv cannot be empty
    additionalData: ArrayBuffer = new ArrayBuffer(0);
    tagLength: u32 = 128;
}
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoAESGCM(): void
{
    // Generate AES key
    let aesKeyResult = Crypto.Subtle.generateKey({length: 256} as Crypto.AesKeyGenParams, true, ["encrypt", "decrypt"]);
    let aesKey = aesKeyResult.data as Crypto.CryptoKey;
    // Generate iv
    let iv = Crypto.getRandomValues(12);
    let aesGcmParams = {iv : iv.buffer, additionalData : new ArrayBuffer(0),  tagLength : 128} as Crypto.AesGcmParams;
    let cipher = Crypto.Subtle.encrypt(aesGcmParams, aesKey, String.UTF8.encode("Hello World"));
    let clearText = Crypto.Subtle.decrypt(aesGcmParams, aesKey, cipher.data as ArrayBuffer);
}

For encrypting with AES-GCM you need an AES key and to use the Crypto.AesGcmParams algorithm object.

pub struct AesGcmParams {
    pub iv: Vec<u8>, // iv cannot be empty
    pub additional_data: Vec<u8>,
    pub tag_length: u32
}
use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_aes_gcm(input: String) {
    // Generate AES key
    let aes_params = subtle::AesKeyGenParams { length: 256 };
    let key_usages_slice: Vec<&str> = vec!["encrypt", "decrypt"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Aes(aes_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Generate IV
    let random_bytes = match klave::crypto::random::get_random_bytes(12) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    //Generate GCM parameters
    let aes_params = subtle::AesGcmParams {
        iv: &random_bytes,
        additionalData: vec![],
        tagLength: 128
    };
    let crypt_algorithm = subtle::EncryptAlgorithm::AesGcm(aes_params);

    // Encrypt
    let encrypted_text = match subtle::encrypt(&crypt_algorithm, &crypto_key, &String::from("Hello World").into_bytes()) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Decrypt
    let decrypted_text = match subtle::decrypt(&crypt_algorithm, &crypto_key, &encrypted_text) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}

RSA-OAEP

For encrypting with RSA-OAEP you need an RSA key and to use the Crypto.RsaOaepParams algorithm object.

export class RsaOaepParams {
    label: ArrayBuffer = new ArrayBuffer(0);
}
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoRSAOAEP(): void
{
    // Generate RSA key
    let rsakeyResult = Crypto.Subtle.generateKey({modulusLength: 2048, publicExponent: 65537, hash: "SHA2-256"} as Crypto.RsaHashedKeyGenParams, true, ["encrypt", "decrypt"]);
    let rsaKey = rsakeyResult.data as Crypto.CryptoKey;
    // Encrypt and Decrypt
    let rsaOaepParams = {label : new ArrayBuffer(0)} as Crypto.RsaOaepParams;
    let cipher = Crypto.Subtle.encrypt(rsaOaepParams, rsaKey, String.UTF8.encode("Hello World"));
    let clearText = Crypto.Subtle.decrypt(rsaOaepParams, rsaKey, cipher.data as ArrayBuffer);
}

For encrypting with RSA-OAEP you need an RSA key and to use the RsaOaepParams algorithm object.

pub struct RsaOaepParams {
    pub label: Vec<u8>
}
use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_rsa_oaep(input: String) {
    // Generate RSA key
    let rsa_params = subtle::RsaHashedKeyGenParams {
        modulus_length: 2048,
        public_exponent: 65537,
        hash: "SHA2-256"
    };
    let key_usages_slice: Vec<&str> = vec!["encrypt", "decrypt"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Rsa(rsa_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Encrypt
    let rsa_oaep_params = subtle::RsaOaepParams { label: vec![] };
    let crypt_algorithm = subtle::EncryptAlgorithm::RsaOaep(rsa_oaep_params);
    let encrypted_text = match subtle::encrypt(&crypt_algorithm, &crypto_key, &String::from("Hello World").into_bytes()) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Decrypt
    let decrypted_text = match subtle::decrypt(&crypt_algorithm, &crypto_key, &encrypted_text) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}

Signing and Verifying

ClassOperationParameters: typeReturnsBehavior
Crypto.Subtlesignalgorithm: T, key: CryptoKey, data: ArrayBufferResult<ArrayBuffer, Error>Sign the data with the algorithm object and key provided. Return an ArrayBuffer containing the signature or an Error.
Crypto.Subtleverifyalgorithm: T, key: CryptoKey, data: ArrayBuffer, signature: ArrayBufferResult<Crypto.SignatureVerification, Error>Verify the signature against the data with the algorithm object and key provided. Return an Crypto.SignatureVerification containing a boolean or an Error.
ClassOperationParameters: typeReturnsBehavior
crypto::subtlesignalgorithm: SignAlgorithm, key: CryptoKey, data: [u8]Result<Vec<u8>, Error>Sign the data with the algorithm object and key provided. Return an Vec<u8> containing the signature or an Error.
crypto::subtleverifyalgorithm: SignAlgorithm, key: CryptoKey, data: [u8], signature: [u8]Result<VerifySignResult, Error>Verify the signature against the data with the algorithm object and key provided. Return an VerifySignResult containing a bool or an Error.

Depending on the type of signature that needs to be done a SignAlgorithm Enum variants is passed as parameters.

pub enum SignAlgorithm {
    Ecdsa(EcdsaParams),
    RsaPss(RsaPssParams),
    Hmac(HmacParams),
}

ECDSA

For ECDSA signature you need an EC key pair and to use the Crypto.EcdsaParams algorithm object.

export class EcdsaParams {
    hash: string = 'SHA2-256'; // "SHA2-256", "SHA2-384", "SHA2-512"
}
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoECDSA(): void
{
    // Generate EC key
    let eccKeyResult = Crypto.Subtle.generateKey({namedCurve: "P-256"} as Crypto.EcKeyGenParams, true, ["sign", "verify"]);
    let eccKey = eccKeyResult.data as Crypto.CryptoKey;
    // Sign and Verify
    let ecdsaParams = {hash: "SHA2-256"} as Crypto.EcdsaParams;
    let signEcc = Crypto.Subtle.sign(ecdsaParams, eccKey, String.UTF8.encode("Hello World"));
    let verifyEcc = Crypto.Subtle.verify(ecdsaParams, eccKey, String.UTF8.encode("Hello World"), signEcc.data as ArrayBuffer);
    let verification = verifyEcc.data as SignatureVerification;
    // Validate signature : if(verification.isValid) ...
}

For ECDSA signature you need an EC key pair and to use the EcdsaParams algorithm object.

pub struct EcdsaParams {
    pub hash: String // "SHA2-256", "SHA2-384", "SHA2-512"
}
use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_ecdsa(input: String) {
    // Generate Key
    let ec_params = subtle::EcKeyGenParams { named_curve: "P-256" };
    let key_usages_slice: Vec<&str> = vec!["sign", "verify"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Ecc(ec_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
    // Sign
    let sign_ec_params = subtle::EcdsaParams { hash: "SHA2-256" };
    let sign_algorithm = subtle::SignAlgorithm::Ecdsa(sign_ec_params);
    let signature = match subtle::sign(&sign_algorithm, &crypto_key, &String::from("Hello World").into_bytes()) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
    // Verify
    let verify_result = match subtle::verify(&sign_algorithm, &crypto_key, &String::from("Hello World").into_bytes(), &signature) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
    if verify_result.is_valid() {
        klave::notifier::send_string("Verified");
    }
    else {
        klave::notifier::send_string("Not Verified");
    }
}

RSA-PSS

For RSA-PSS signature you need an RSA key pair and to use the Crypto.RsaPssParams algorithm object.

export class RsaPssParams {
    saltLength: u32 = 0;
}
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoRSAPSS(): void
{
    // Generate RSA key
    let rsaKeyResult = Crypto.Subtle.generateKey({modulusLength: 2048, publicExponent: 65537, hash: "SHA2-256"} as Crypto.RsaHashedKeyGenParams, true, ["sign", "verify"]);
    let rsaKey = rsaKeyResult.data as Crypto.CryptoKey;
    // Sign and Verify
    let rsaPssParams = {saltLength: 32} as Crypto.RsaPssParams;
    let signRsa = Crypto.Subtle.sign(rsaPssParams, rsaKey, String.UTF8.encode("Hello World"));
    let verifyRsa = Crypto.Subtle.verify(rsaPssParams, rsaKey, String.UTF8.encode("Hello World"), signRsa.data as ArrayBuffer);
    let verification = verifyRsa.data as SignatureVerification;
    // Validate signature : if(verification.isValid) ...
}

For RSA-PSS signature you need an RSA key pair and to use the RsaPssParams algorithm object.

pub struct RsaPssParams {
    pub salt_length: u32
}
use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_rsa_pss(input: String) {
    // Generate RSA key
    let rsa_params = subtle::RsaHashedKeyGenParams {
        modulus_length: 2048,
        public_exponent: 65537,
        hash: "SHA2-256"
    };
    let key_usages_slice: Vec<&str> = vec!["sign", "verify"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Rsa(rsa_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
    // Sign
    let sign_rsa_params = subtle::RsaPssParams { salt_length: 0 };
    let sign_algorithm = subtle::SignAlgorithm::RsaPss(sign_rsa_params);
    let signature = match subtle::sign(&sign_algorithm, &crypto_key, &String::from("Hello World").into_bytes()) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
    // Verify
    let verify_result = match subtle::verify(&sign_algorithm, &crypto_key, &String::from("Hello World").into_bytes(), &signature) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    if verify_result.is_valid() {
        klave::notifier::send_string("Verified");
    }
    else {
        klave::notifier::send_string("Not Verified");
    }
}

HMAC

For HMAC signature you need an HMAC key and to use the Crypto.HmacKeyGenParams algorithm object.

export class HmacKeyGenParams {
    hash: string = 'SHA2-256'; //SHA2-384, SHA2-512
}
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoHMAC(): void
{
    // Generate HMAC key
    let hmacKeyResult = Crypto.Subtle.generateKey({hash: 'SHA2-256'} as Crypto.HmacKeyGenParams, true, ["sign", "verify"]);
    let hmacKey = hmacKeyResult.data as Crypto.CryptoKey;
    // Sign and Verify
    let hmacParams = {hash: 'SHA2-256'} as Crypto.HmacKeyGenParams;
    let signHmac = Crypto.Subtle.sign(hmacParams, hmacKey, String.UTF8.encode("Hello World"));
    let verifyHmac = Crypto.Subtle.verify(hmacParams, hmacKey, String.UTF8.encode("Hello World"), signHmac.data as ArrayBuffer);
    let verification = verifyHmac.data as SignatureVerification;
    // Validate signature : if(verification.isValid) ...
}

For HMAC signature you need an HMAC key and to use the HmacParams algorithm object.

pub struct HmacParams {
    pub hash: String,
}
use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_hmac(input: String) {
    // Generate HMAC key
    let hmac_params = subtle::HmacKeyGenParams { hash: "SHA2-256".to_string() };
    let key_usages_slice: Vec<&str> = vec!["sign", "verify"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Hmac(hmac_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
    // Sign
    let sign_hmac_params = subtle::HmacParams { hash: "SHA2-256".to_string() };
    let sign_algorithm = subtle::SignAlgorithm::Hmac(sign_hmac_params);
    let signature = match subtle::sign(&sign_algorithm, &crypto_key, &String::from("Hello World").into_bytes()) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
    // Verify
    let verify_result = match subtle::verify(&sign_algorithm, &crypto_key, &String::from("Hello World").into_bytes(), &signature) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    if verify_result.is_valid() {
        klave::notifier::send_string("Verified");
    }
    else {
        klave::notifier::send_string("Not Verified");
    }
}

Key wrapping

ClassOperationParameters: typeReturnsBehavior
Crypto.SubtlewrapKeyformat: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgo: TResult<ArrayBuffer, Error>Wrap the keyin the format specified with the wrappingKey using the wrapping algorithm. Return an ArrayBuffer containing the wrapped key or an Error.
Crypto.SubtleunwrapKeyformat: string, wrappedKey: ArrayBuffer, unwrappingKey: CryptoKey, unwrapAlgo: T, unwrappedKeyAlgo: E, extractable: boolean, usages: string[]Result<CryptoKey, Error>Unwrap the wrappedKey wrapped in the format with the unwrappingKey and unwrapAlgo and create a Cryptokey with the specified unwrappedKeyAlgo and parameters. Return a result set containing a Crypto.CryptoKey or an Error.

Format that can be used depending on the key you want to wrap/unwrap are the following: raw, spki, pkcs8, pkcs1, sec1.

ClassOperationParameters: typeReturnsBehavior
crypto::subtlewrap_keyformat: string, key: CryptoKey, wrapping_key: CryptoKey, algorithm: WrapAlgorithmResult<Vec<u8>, Error>Wrap the keyin the format specified with the wrapping_key using the wrapping algorithm. Return an Vec<u8> containing the wrapped key or an Error.
crypto::subtleunwrap_keyformat: string, wrappedKey: [u8], unwrapping_key: CryptoKey, unwrap_algorithm: WrapAlgorithm, unwrapped_key_algorithm: GenAlgorithm, extractable: bool, usages: [&str]Result<CryptoKey, Error>Unwrap the wrapped_key wrapped in the format with the unwrapping_key and unwrap_algorithm and create a Cryptokey with the specified unwrapped_key_algorithm and parameters. Return a result set containing a CryptoKey or an Error.

Depending on the type of wrapping that needs to be done a WrapAlgorithm Enum variants is passed as parameters.

pub enum KeyWrapAlgorithm {
    RsaOaep(RsaOaepParams),
    AesGcm(AesGcmParams),
    AesKw,
}

Format that can be used depending on the key you want to wrap/unwrap are the following: raw, spki, pkcs8, pkcs1, sec1.

AES-KW

To wrap and unwrap key with AES-KW you will need an AES key, a key to wrap and to use NamedAlgorithm.

export class NamedAlgorithm {
    name!: string;
}
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoAESKW(): void
{
    // Generate wrapping AES key
    let aesKeyResult = Crypto.Subtle.generateKey({length: 256} as Crypto.AesKeyGenParams, true, ["wrap_key", "unwrap_key"]);
    let aesKey = aesKeyResult.data as Crypto.CryptoKey;

    // Generate AES key to wrap
    let aesKeyToWrapResult = Crypto.Subtle.generateKey({length: 256} as Crypto.AesKeyGenParams, true, ["encrypt", "decrypt"]);
    let aesKeyToWrap = aesKeyToWrapResult.data as Crypto.CryptoKey;

    // Wrap and Unwrap
    let aesKwParams = {name: "AES-KW"} as Crypto.NamedAlgorithm;
    let wrappedKeyResult = Crypto.Subtle.wrapKey("raw", aesKeyToWrap, aesKey, aesKwParams);
    let unwrappedKeyResult = Crypto.Subtle.unwrapKey("raw", wrappedKeyResult.data, aesKey, aesKwParams, {length: 256} as Crypto.AesKeyGenParams, true, ["encrypt", "decrypt"]);
}

To wrap and unwrap key with AES-KW you will need an AES key and a key to wrap .

use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_aes_kw(input: String) {
    // Generate wrapping AES key
    let aes_params_wrap_key = subtle::AesKeyGenParams { length: 256 };
    let key_usages_wrap_key: Vec<&str> = vec!["wrap_key", "unwrap_key"];
    let gen_algorithm_wrap_key = subtle::KeyGenAlgorithm::Aes(aes_params_wrap_key);
    let wrapping_key: CryptoKey = match subtle::generate_key(&gen_algorithm_wrap_key, true, &key_usages_wrap_key) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Generate AES key to wrap
    let aes_params = subtle::AesKeyGenParams { length: 256 };
    let key_usages_slice: Vec<&str> = vec!["encrypt", "decrypt"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Aes(aes_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Wrap
    let kw_wrap_algo = subtle::KeyWrapAlgorithm::AesKw;
    let wrapped_key = match subtle::wrap_key(&"raw", &crypto_key, &wrapping_key, &kw_wrap_algo) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Unwrap
    let unwrapped_key = match subtle::unwrap_key(&"raw", &wrapped_key, &wrapping_key,
        &kw_wrap_algo,
        &gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}

AES-GCM

To wrap and unwrap key with AES-GCM you will need an AES key, a key to wrap and to use Crypto.AesGcmParams algorithm object.

import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoAESGCM(): void
{
    // Generate wrapping AES key
    let aesKeyResult = Crypto.Subtle.generateKey({length: 256} as Crypto.AesKeyGenParams, true, ["wrap_key", "unwrap_key"]);
    let aesKey = aesKeyResult.data as Crypto.CryptoKey;

    // Generate AES key to wrap
    let aesKeyToWrapResult = Crypto.Subtle.generateKey({length: 256} as Crypto.AesKeyGenParams, true, ["encrypt", "decrypt"]);
    let aesKeyToWrap = aesKeyToWrapResult.data as Crypto.CryptoKey;

    // Wrap and Unwrap
    let iv = Crypto.getRandomValues(12);
    let aesGcmParams = {iv : iv.buffer, additionalData : new ArrayBuffer(0),  tagLength : 128} as Crypto.AesGcmParams;
    let wrappedKeyResult = Crypto.Subtle.wrapKey("raw", aesKeyToWrap, aesKey, aesGcmParams);
    let unwrappedKeyResult = Crypto.Subtle.unwrapKey("raw", wrappedKeyResult.data, aesKey, aesGcmParams, {length: 256} as Crypto.AesKeyGenParams, true, ["encrypt", "decrypt"]);
}

To wrap and unwrap key with AES-GCM you will need an AES key, a key to wrap and to use AesGcmParams algorithm object.

use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_aes_gcm_wrap(input: String) {
    // Generate wrapping AES key
    let aes_params_wrap_key = subtle::AesKeyGenParams { length: 256 };
    let key_usages_wrap_key: Vec<&str> = vec!["wrap_key", "unwrap_key"];
    let gen_algorithm_wrap_key = subtle::KeyGenAlgorithm::Aes(aes_params_wrap_key);
    let wrapping_key: CryptoKey = match subtle::generate_key(&gen_algorithm_wrap_key, true, &key_usages_wrap_key) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Generate AES key to wrap
    let aes_params = subtle::AesKeyGenParams { length: 256 };
    let key_usages_slice: Vec<&str> = vec!["encrypt", "decrypt"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Aes(aes_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Generate IV
    let random_bytes = match klave::crypto::random::get_random_bytes(12) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    //Generate GCM parameters
    let aes_gcm_params = subtle::AesGcmParams {
        iv: &random_bytes,
        additionalData: vec![],
        tagLength: 128
    };
    let wrapping_algorithm = subtle::KeyWrapAlgorithm::AesGcm(aes_params);

    // Wrap
    let wrapped_key = match subtle::wrap_key(&"raw", &crypto_key, &wrapping_key, &wrapping_algorithm) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Unwrap
    let unwrapped_key = match subtle::unwrap_key(&"raw", &wrapped_key, &wrapping_key,
        &wrapping_algorithm,
        &gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}

RSA-OAEP

To wrap and unwrap key with RSA-OAEP you will need an RSA key, a key to wrap and to use Crypto.RsaOaepParams algorithm object.

import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoRSAOAEP(): void
{
    // Generate wrapping RSA key
    let rsakeyResult = Crypto.Subtle.generateKey({modulusLength: 2048, publicExponent: 65537, hash: "SHA2-256"} as Crypto.RsaHashedKeyGenParams, true, ["wrap_key", "unwrap_key"]);
    let rsaKey = rsakeyResult.data as Crypto.CryptoKey;

    // Generate AES key to wrap
    let aesKeyToWrapResult = Crypto.Subtle.generateKey({length: 256} as Crypto.AesKeyGenParams, true, ["encrypt", "decrypt"]);
    let aesKeyToWrap = aesKeyToWrapResult.data as Crypto.CryptoKey;

    // Wrap and Unwrap
    let rsaOaepParams = {label : new ArrayBuffer(0)} as Crypto.RsaOaepParams;
    let wrappedKeyResult = Crypto.Subtle.wrapKey("raw", aesKeyToWrap, rsaKey, rsaOaepParams);
    let unwrappedKeyResult = Crypto.Subtle.unwrapKey("raw", wrappedKeyResult.data, rsaKey, rsaOaepParams, {length: 256} as Crypto.AesKeyGenParams, true, ["encrypt", "decrypt"]);
}

To wrap and unwrap key with RSA-OAEP you will need an RSA key, a key to wrap and to use RsaOaepParams algorithm object.

use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_rsa_oaep_wrap(input: String) {
    // Generate wrapping RSA key
    let rsa_params_wrap_key = subtle::RsaHashedKeyGenParams {
        modulus_length: 2048,
        public_exponent: 65537,
        hash: "SHA2-256"
    };
    let key_usages_wrap_key: Vec<&str> = vec!["wrap_key", "unwrap_key"];
    let gen_algorithm_wrap_key = subtle::KeyGenAlgorithm::Rsa(rsa_params_wrap_key);
    let wrapping_key: CryptoKey = match subtle::generate_key(&gen_algorithm_wrap_key, true, &key_usages_wrap_key) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Generate AES key to wrap
    let aes_params = subtle::AesKeyGenParams { length: 256 };
    let key_usages_slice: Vec<&str> = vec!["encrypt", "decrypt"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Aes(aes_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    //Generate RSA-OAEP parameters
    let rsa_oaep_params = subtle::RsaOaepParams { label: vec![] };
    let wrapping_algorithm = subtle::KeyWrapAlgorithm::RsaOaep(rsa_oaep_params);

    // Wrap
    let wrapped_key = match subtle::wrap_key(&"raw", &crypto_key, &wrapping_key, &wrapping_algorithm) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Unwrap
    let unwrapped_key = match subtle::unwrap_key(&"raw", &wrapped_key, &wrapping_key,
        &wrapping_algorithm,
        &gen_algorithm, true, &key_usages_slice) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}

Importing and Exporting key

ClassOperationParameters: typeReturnsBehavior
Crypto.SubtleimportKeyformat: string, keyData: ArrayBuffer, algorithm: T, extractable: boolean, usages: string[]Result<CryptoKey, Error>Import a key from the keyDatain the format specified. Return a result set containing the CryptoKey or an Error.
Crypto.SubtleexportKeyformat: string, key: CryptoKeyResult<ArrayBuffer, Error>Export the key in the specified format. Return a result set containing a ArrayBuffer of the exported key or an Error.

Depending on the type of Key to export or import the format to use are the following: raw, spki, pkcs8, pkcs1, sec1.

If the key is not extractable then export will fail.

import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function subtleCryptoExportImportKey(): void
{
    // Generate AES key to export
    let aesKeyResult = Crypto.Subtle.generateKey({length: 256} as Crypto.AesKeyGenParams, true, ["encrypt", "decrypt"]);
    let aesKey = aesKeyResult.data as Crypto.CryptoKey;

    // Export and Import
    let aesKeyExport = Crypto.Subtle.exportKey("raw", aesKey);
    let importedAesKey = Crypto.Subtle.importKey("raw", aesKeyExport.data, {length: 256} as Crypto.AesKeyGenParams, true, ["encrypt", "decrypt"]);
}
ClassOperationParameters: typeReturnsBehavior
crypto::subtleimport_keyformat: string, keyData: [u8], algorithm: GenAlgorithm, extractable: bool, usages: [&str]Result<CryptoKey, Error>Import a key from the keyDatain the format specified. Return a result set containing the CryptoKey or an Error.
crypto::subtleexport_keyformat: string, key: CryptoKeyResult<Vec<u8>, Error>Export the key in the specified format. Return a result set containing a Vec<u8> of the exported key or an Error.

Depending on the type of Key to export or import the format to use are the following: raw, spki, pkcs8, pkcs1, sec1.

If the key is not extractable then export will fail.

use klave::{self, crypto::subtle, crypto::subtle::CryptoKey};

fn subtle_crypto_export_import_key(input: String) {
    // Generate AES key
    let aes_params = subtle::AesKeyGenParams { length: 256 };
    let key_usages: Vec<&str> = vec!["encrypt", "decrypt"];
    let gen_algorithm = subtle::KeyGenAlgorithm::Aes(aes_params);
    let crypto_key: CryptoKey = match subtle::generate_key(&gen_algorithm, true, &key_usages) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Export the Key
    let exported_key = match subtle::export_key("raw", &crypto_key) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };

    // Import the Key
    let imported_key = match subtle::import_key("raw", &exported_key, &gen_algorithm, true, &key_usages) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    }
}

Making data digest

The interface can be accessed through the Crypto.SHA keyword and is compatible with SHA2 and SHA3 digest.

ClassOperationParameters: typeReturnsBehavior
Crypto.Subtledigestalgorithm: string, data: ArrayBufferResult<ArrayBuffer, Error>Generate a digest of the data based on the algorithm specified. Return a ResultSet Result<ArrayBuffer, Error> containing either the digest in an ArrayBuffer or an Error.
import { Crypto } from '@klave/sdk';

/**
* @query
*/
export function CryptoSHA_Test(): void
{
    let data = String.UTF8.encode("Hello World");
    let sha256 = Crypto.Subtle.digest("SHA2-256", data);
    let sha384 = Crypto.Subtle.digest("SHA2-384", data);
    let sha512 = Crypto.Subtle.digest("SHA2-512", data);
    let sha3_256 = Crypto.Subtle.digest("SHA3-256", data);
    let sha3_384 = Crypto.Subtle.digest("SHA3-384", data);
    let sha3_512 = Crypto.Subtle.digest("SHA3-512", data);
}
ClassOperationParameters: typeReturnsBehavior
crypto::subtledigestalgorithm: string, data: [u8]Result<Vec<u8>, Error>Generate a digest of the data based on the algorithm specified. Return a ResultSet Result<Vec<u8>, Error> containing either the digest in an Vec<u8> or an Error.
use klave::{self, crypto::subtle}

fn digest(input: String) {
    // Digest : SHA2-256, SHA2-384, SHA2-512, SHA3-256, SHA3-384, SHA3-512
    let digest = match sha::digest("SHA2-256", &String::from("Hello World").into_bytes()) {
        Ok(result) => result,
        Err(err) => {
            klave::notifier::send_string(&err.to_string());
            return;
        }
    };
}
Edit on GitHub

Last updated on