Skip to content

Commit

Permalink
WIP: HMAC
Browse files Browse the repository at this point in the history
  • Loading branch information
Arshia001 committed Nov 14, 2023
1 parent af8fe47 commit 2b27b3a
Show file tree
Hide file tree
Showing 13 changed files with 616 additions and 127 deletions.
29 changes: 29 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ rand = "0.8.5"
sha1 = "0.10.6"
sha2 = "0.10.8"
md5 = "0.7.0"
strum = { version = "0.25.0", features = ["derive"] }

[patch.crates-io]
tokio = { git = "https://github.com/wasix-org/tokio.git", branch = "epoll" }
Expand Down
7 changes: 5 additions & 2 deletions src/ion_runner/crypto/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
mod algorithm;
mod subtle;

use ion::{conversions::ToValue, function_spec, Object};
use ion::{conversions::ToValue, function_spec, ClassDefinition, Context, Object};
use mozjs::typedarray::ArrayBufferView;
use mozjs_sys::jsapi::{JSFunctionSpec, JSObject};
use rand::RngCore;
Expand Down Expand Up @@ -51,3 +50,7 @@ impl NativeModule for CryptoModule {
}
}
}

pub fn define<'cx: 'o, 'o>(cx: &'cx Context, global: &mut ion::Object<'o>) -> bool {
subtle::crypto_key::CryptoKey::init_class(cx, global).0
}
114 changes: 0 additions & 114 deletions src/ion_runner/crypto/subtle.rs

This file was deleted.

121 changes: 121 additions & 0 deletions src/ion_runner/crypto/subtle/algorithm/hmac.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use ion::{
conversions::{ConversionBehavior, FromValue, ToValue},
Context,
};

use crate::{
ion_runner::crypto::subtle::{
crypto_key::{CryptoKey, KeyFormat, KeyUsage},
AlgorithmIdentifier, KeyData,
},
ionerr,
};

use super::CryptoAlgorithm;

macro_rules! validate_jwk_alg {
($hash_alg:ident, $jwk:ident, $name:expr, $jwk_name:expr) => {
if let Some(jwk_alg) = $jwk.alg {
if $hash_alg.name() == $name && jwk_alg != $jwk_name {
ionerr!(
format!("alg field of JWK must be {}", $jwk_name).as_str(),
Normal
);
}
}
};
}

#[derive(FromValue)]
pub struct HmacImportParams {
name: String,
hash: String,
#[ion(convert = ConversionBehavior::EnforceRange, strict)]
length: u32,
}

#[derive(FromValue)]
pub struct HmacKeyAlgorithm {
name: String,
hash: String,
#[ion(convert = ConversionBehavior::EnforceRange, strict)]
length: u32,
}

#[derive(FromValue)]
pub struct HmacKeyGenParams {
name: String,
hash: String,
#[ion(convert = ConversionBehavior::EnforceRange, strict)]
length: u32,
}

pub struct Hmac;

impl CryptoAlgorithm for Hmac {
fn name(&self) -> &'static str {
"HMAC"
}

fn import_key(
&self,
cx: &Context,
params: ion::Object,
format: KeyFormat,
key_data: KeyData,
extractable: bool,
usages: Vec<KeyUsage>,
) -> ion::Result<CryptoKey> {
if usages
.iter()
.any(|u| !matches!(u, KeyUsage::Sign | KeyUsage::Verify))
{
return Err(ion::Error::new("Invalid key usage", ion::ErrorKind::Syntax));
}

let params = HmacImportParams::from_value(cx, &params.as_value(cx), false, ())?;
let hash_alg = AlgorithmIdentifier::String(params.hash).get_algorithm(cx)?;

let key_bytes = match format {
KeyFormat::Raw => {
let KeyData::BufferSource(buffer) = key_data else {
panic!("Invalid key format/key data combination, should be validated before passing in");
};
buffer.as_slice()
}
KeyFormat::Jwk => {
let KeyData::Jwk(jwk) = key_data else {
panic!("Invalid key format/key data combination, should be validated before passing in");
};
if jwk.kty != "oct" {
ionerr!("kty member of JWK key must be 'oct'", Normal);
}
let Some(k) = jwk.k else {
ionerr!("Mandatory member k of JWK not specified", Normal);
};

validate_jwk_alg!(hash_alg, jwk, "SHA-1", "HS1");
validate_jwk_alg!(hash_alg, jwk, "SHA-256", "HS256");
validate_jwk_alg!(hash_alg, jwk, "SHA-384", "HS384");
validate_jwk_alg!(hash_alg, jwk, "SHA-512", "HS512");

/*
If usages is non-empty and the use field of jwk is present and is not "sign", then throw a DataError.
If the key_ops field of jwk is present, and is invalid according to the requirements of JSON Web Key [JWK] or does not contain all of the specified usages values, then throw a DataError.
If the ext field of jwk is present and has the value false and extractable is true, then throw a DataError. */

k.as_bytes()
}
_ => {
return Err(ion::Error::new(
"Unsupported key type",
ion::ErrorKind::Normal,
))
}
};

()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ use super::CryptoAlgorithm;
pub struct Md5;

impl CryptoAlgorithm for Md5 {
fn name(&self) -> &'static str {
"MD5"
}

fn digest(&self, _params: ion::Object, data: super::BufferSource) -> ion::Result<ArrayBuffer> {
let data = md5::compute(data.as_slice()).0;
Ok(ArrayBuffer::from(&data[..]))
Expand Down
Loading

0 comments on commit 2b27b3a

Please sign in to comment.