From 7de75c90deb91afe01718a33148efadfdd9a47cf Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Sat, 23 Nov 2024 21:17:10 +0900 Subject: [PATCH 01/22] feat(crypto): Initial support for SubtleCrypto --- Cargo.lock | 225 ++++++++++ modules/llrt_crypto/Cargo.toml | 14 +- modules/llrt_crypto/src/lib.rs | 15 + modules/llrt_crypto/src/subtle/decrypt.rs | 77 ++++ modules/llrt_crypto/src/subtle/derive_bits.rs | 122 ++++++ modules/llrt_crypto/src/subtle/digest.rs | 34 ++ modules/llrt_crypto/src/subtle/encrypt.rs | 78 ++++ .../llrt_crypto/src/subtle/generate_key.rs | 103 +++++ modules/llrt_crypto/src/subtle/mod.rs | 385 ++++++++++++++++++ modules/llrt_crypto/src/subtle/sign.rs | 83 ++++ modules/llrt_crypto/src/subtle/verify.rs | 106 +++++ 11 files changed, 1241 insertions(+), 1 deletion(-) create mode 100644 modules/llrt_crypto/src/subtle/decrypt.rs create mode 100644 modules/llrt_crypto/src/subtle/derive_bits.rs create mode 100644 modules/llrt_crypto/src/subtle/digest.rs create mode 100644 modules/llrt_crypto/src/subtle/encrypt.rs create mode 100644 modules/llrt_crypto/src/subtle/generate_key.rs create mode 100644 modules/llrt_crypto/src/subtle/mod.rs create mode 100644 modules/llrt_crypto/src/subtle/sign.rs create mode 100644 modules/llrt_crypto/src/subtle/verify.rs diff --git a/Cargo.lock b/Cargo.lock index 645b53c53..6ac3b5fdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,41 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.8.11" @@ -303,6 +338,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + [[package]] name = "brotli" version = "7.0.0" @@ -518,6 +562,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + [[package]] name = "cc" version = "1.1.31" @@ -585,6 +638,16 @@ dependencies = [ "half", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -843,6 +906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core", "typenum", ] @@ -852,6 +916,15 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "026ac6ceace6298d2c557ef5ed798894962296469ec7842288ea64674201a2d1" +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "curl" version = "0.4.47" @@ -1281,6 +1354,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.31.1" @@ -2402,6 +2485,16 @@ dependencies = [ "hashbrown 0.15.0", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "block-padding", + "generic-array", +] + [[package]] name = "io-close" version = "0.3.7" @@ -2495,6 +2588,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "lazycell" @@ -2532,6 +2628,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "libnghttp2-sys" version = "0.1.10+1.61.0" @@ -2740,8 +2842,13 @@ dependencies = [ name = "llrt_crypto" version = "0.3.0-beta" dependencies = [ + "aes", + "aes-gcm", + "cbc", "crc32c", "crc32fast", + "ctr", + "hmac", "llrt_buffer", "llrt_context", "llrt_encoding", @@ -2749,10 +2856,16 @@ dependencies = [ "llrt_utils", "md-5", "memchr", + "num-traits", "once_cell", + "p256", + "p384", "rand", "ring", "rquickjs", + "rsa", + "sha1", + "sha2", "tokio", "uuid", "uuid-simd", @@ -3165,12 +3278,49 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -3178,6 +3328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3220,6 +3371,12 @@ version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "opener" version = "0.5.2" @@ -3285,6 +3442,18 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "p384" version = "0.13.0" @@ -3443,6 +3612,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + [[package]] name = "pkcs8" version = "0.10.2" @@ -3487,6 +3667,18 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -3786,6 +3978,29 @@ dependencies = [ "cc", ] +[[package]] +name = "rsa" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +dependencies = [ + "byteorder", + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "sha2", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -4540,6 +4755,16 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "untrusted" version = "0.9.0" diff --git a/modules/llrt_crypto/Cargo.toml b/modules/llrt_crypto/Cargo.toml index 3cce71245..1745a112f 100644 --- a/modules/llrt_crypto/Cargo.toml +++ b/modules/llrt_crypto/Cargo.toml @@ -20,7 +20,7 @@ llrt_encoding = { version = "0.3.0-beta", path = "../../libs/llrt_encoding" } llrt_utils = { version = "0.3.0-beta", path = "../../libs/llrt_utils", default-features = false } once_cell = "1" rand = "0.8" -ring = "0.17" +ring = { version = "0.17", features = ["std"] } rquickjs = { git = "https://github.com/DelSkayn/rquickjs.git", version = "0.8.1", features = [ "macro", ], default-features = false } @@ -30,6 +30,18 @@ uuid = { version = "1", default-features = false, features = [ ] } uuid-simd = "0.8" +hmac = "0.12" +sha1 = "0.10" +sha2 = "0.10" +aes = "0.8" +aes-gcm = "0.10" +cbc = { version = "0.1", features = ["std"] } +num-traits = "0.2" +rsa = { version = "0.9", features = ["std", "sha2"], default-features = false } +p256 = { version = "0.13", features = ["ecdh"] } +p384 = "0.13" +ctr = "0.9" + [target.'cfg(target_os = "windows")'.dependencies] memchr = "2" md-5 = "0.10" diff --git a/modules/llrt_crypto/src/lib.rs b/modules/llrt_crypto/src/lib.rs index 0f9cf6f9b..5de524138 100644 --- a/modules/llrt_crypto/src/lib.rs +++ b/modules/llrt_crypto/src/lib.rs @@ -4,6 +4,7 @@ mod crc32; mod md5_hash; mod sha_hash; use std::slice; +mod subtle; use llrt_buffer::Buffer; use llrt_context::CtxExtension; @@ -25,6 +26,10 @@ use rquickjs::{ prelude::{Func, Rest}, Class, Ctx, Error, Exception, Function, IntoJs, Null, Object, Result, Value, }; +use subtle::{ + subtle_decrypt, subtle_derive_bits, subtle_digest, subtle_encrypt, subtle_generate_key, + subtle_sign, subtle_verify, +}; use uuid::Uuid; use uuid_simd::UuidExt; @@ -185,6 +190,16 @@ pub fn init(ctx: &Ctx<'_>) -> Result<()> { crypto.set("randomFill", Func::from(random_fill))?; crypto.set("getRandomValues", Func::from(get_random_values))?; + let subtle = Object::new(ctx.clone())?; + subtle.set("decrypt", Func::from(subtle_decrypt))?; + subtle.set("deriveBits", Func::from(subtle_derive_bits))?; + subtle.set("digest", Func::from(subtle_digest))?; + subtle.set("encrypt", Func::from(subtle_encrypt))?; + subtle.set("generateKey", Func::from(subtle_generate_key))?; + subtle.set("verify", Func::from(subtle_verify))?; + subtle.set("sign", Func::from(subtle_sign))?; + crypto.set("subtle", subtle)?; + globals.set("crypto", crypto)?; Ok(()) diff --git a/modules/llrt_crypto/src/subtle/decrypt.rs b/modules/llrt_crypto/src/subtle/decrypt.rs new file mode 100644 index 000000000..ed99d7112 --- /dev/null +++ b/modules/llrt_crypto/src/subtle/decrypt.rs @@ -0,0 +1,77 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, KeyIvInit}; +use aes_gcm::{aead::Aead, KeyInit, Nonce}; +use ctr::{cipher::StreamCipher, Ctr128BE, Ctr32BE, Ctr64BE}; +use llrt_utils::result::ResultExt; +use rquickjs::{Ctx, Exception, Result}; +use rsa::{pkcs1::DecodeRsaPrivateKey, Oaep, RsaPrivateKey}; +use sha2::Sha256; + +use crate::subtle::{Aes256Gcm, Algorithm}; + +type Aes256CbcDec = cbc::Decryptor; + +pub fn decrypt( + ctx: &Ctx<'_>, + algorithm: &Algorithm, + key_value: Vec, + data: Vec, +) -> Result> { + match algorithm { + Algorithm::AesGcm(iv) => { + let cipher = Aes256Gcm::new_from_slice(&key_value).or_throw(ctx)?; + let nonce = Nonce::from_slice(iv); + + match cipher.decrypt(nonce, data.as_ref()) { + Ok(result) => Ok(result), + Err(_) => Err(Exception::throw_message(ctx, "Decryption failed"))?, + } + }, + Algorithm::AesCbc(iv) => { + match Aes256CbcDec::new(key_value.as_slice().into(), iv.as_slice().into()) + .decrypt_padded_vec_mut::(&data) + { + Ok(result) => Ok(result), + Err(_) => Err(Exception::throw_message(ctx, "Decryption failed")), + } + }, + Algorithm::AesCtr(counter, length) => match length { + 32 => decrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), + 64 => decrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), + 128 => decrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), + _ => Err(Exception::throw_message( + ctx, + "invalid counter length. Currently supported 32/64/128 bits", + )), + }, + Algorithm::RsaOaep(label) => { + let private_key = RsaPrivateKey::from_pkcs1_der(&key_value).or_throw(ctx)?; + let padding = match label { + Some(buf) => { + Oaep::new_with_label::(String::from_utf8(buf.to_vec())?) + }, + None => Oaep::new::(), + }; + + private_key + .decrypt(padding, &data) + .map_err(|e| Exception::throw_message(ctx, e.to_string().as_str())) + }, + _ => Err(Exception::throw_message(ctx, "Algorithm not supported")), + } +} + +fn decrypt_aes_ctr_gen(ctx: &Ctx<'_>, key: &[u8], counter: &[u8], data: &[u8]) -> Result> +where + B: KeyIvInit + StreamCipher, +{ + let mut cipher = B::new(key.into(), counter.into()); + + let mut plaintext = data.to_vec(); + cipher + .try_apply_keystream(&mut plaintext) + .map_err(|_| Exception::throw_message(ctx, "tried to decrypt too much data"))?; + + Ok(plaintext) +} diff --git a/modules/llrt_crypto/src/subtle/derive_bits.rs b/modules/llrt_crypto/src/subtle/derive_bits.rs new file mode 100644 index 000000000..62c536782 --- /dev/null +++ b/modules/llrt_crypto/src/subtle/derive_bits.rs @@ -0,0 +1,122 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use std::num::NonZeroU32; + +use llrt_utils::result::ResultExt; +use p256::pkcs8::DecodePrivateKey; +use ring::{hkdf, pbkdf2}; +use rquickjs::{Ctx, Exception, Result}; + +use crate::subtle::{CryptoNamedCurve, DeriveAlgorithm, Sha}; + +struct HkdfOutput(usize); + +impl hkdf::KeyType for HkdfOutput { + fn len(&self) -> usize { + self.0 + } +} + +pub fn derive_bits( + ctx: &Ctx<'_>, + algorithm: &DeriveAlgorithm, + key_value: Vec, + length: u32, +) -> Result> { + match algorithm { + DeriveAlgorithm::Edch { curve, public } => match curve { + CryptoNamedCurve::P256 => { + let secret_key = p256::SecretKey::from_pkcs8_der(&key_value).map_err(|_| { + Exception::throw_message(ctx, "Unexpected error decoding private key") + })?; + + let public_key = p256::SecretKey::from_pkcs8_der(public) + .map_err(|_| { + Exception::throw_message(ctx, "Unexpected error decoding public key") + })? + .public_key(); + + let shared_secret = p256::elliptic_curve::ecdh::diffie_hellman( + secret_key.to_nonzero_scalar(), + public_key.as_affine(), + ); + + Ok(shared_secret.raw_secret_bytes().to_vec()) + }, + CryptoNamedCurve::P384 => { + let secret_key = p384::SecretKey::from_pkcs8_der(&key_value).map_err(|_| { + Exception::throw_message(ctx, "Unexpected error decoding private key") + })?; + + let public_key = p384::SecretKey::from_pkcs8_der(public) + .map_err(|_| { + Exception::throw_message(ctx, "Unexpected error decoding public key") + })? + .public_key(); + + let shared_secret = p384::elliptic_curve::ecdh::diffie_hellman( + secret_key.to_nonzero_scalar(), + public_key.as_affine(), + ); + + Ok(shared_secret.raw_secret_bytes().to_vec()) + }, + }, + DeriveAlgorithm::Pbkdf2 { + hash, + ref salt, + iterations, + } => { + let hash_algorithm = match hash { + Sha::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1, + Sha::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256, + Sha::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384, + Sha::Sha512 => pbkdf2::PBKDF2_HMAC_SHA512, + }; + + let mut out = vec![0; (length / 8).try_into().or_throw(ctx)?]; + let not_zero_iterations = NonZeroU32::new(*iterations) + .ok_or_else(|| Exception::throw_message(ctx, "Iterations not zero"))?; + + pbkdf2::derive( + hash_algorithm, + not_zero_iterations, + salt, + &key_value, + &mut out, + ); + + Ok(out) + }, + DeriveAlgorithm::Hkdf { + hash, + ref salt, + info, + } => { + let hash_algorithm = match hash { + Sha::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY, + Sha::Sha256 => hkdf::HKDF_SHA256, + Sha::Sha384 => hkdf::HKDF_SHA384, + Sha::Sha512 => hkdf::HKDF_SHA512, + }; + + let salt = hkdf::Salt::new(hash_algorithm, salt); + let boxed_slice = info.clone().into_boxed_slice(); + let info: &[&[u8]] = &[&*boxed_slice]; + + let prk = salt.extract(&key_value); + let out_length = (length / 8).try_into().or_throw(ctx)?; + + let okm = prk + .expand(info, HkdfOutput((length / 8).try_into().or_throw(ctx)?)) + .map_err(|_e| { + Exception::throw_message(ctx, "The length provided for HKDF is too large") + })?; + + let mut out = vec![0u8; out_length]; + let _ = okm.fill(&mut out).or_throw(ctx); + + Ok(out) + }, + } +} diff --git a/modules/llrt_crypto/src/subtle/digest.rs b/modules/llrt_crypto/src/subtle/digest.rs new file mode 100644 index 000000000..c62033aa0 --- /dev/null +++ b/modules/llrt_crypto/src/subtle/digest.rs @@ -0,0 +1,34 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use rquickjs::{Ctx, Result}; +use sha1::Sha1; +use sha2::{Digest, Sha256, Sha384, Sha512}; + +use crate::subtle::{get_sha, Sha}; + +pub fn digest(ctx: Ctx<'_>, name: &str, data: Vec) -> Result> { + let sha = get_sha(&ctx, name)?; + + match sha { + Sha::Sha1 => { + let mut hasher = Sha1::new(); + hasher.update(data); + Ok(hasher.finalize().to_vec()) + }, + Sha::Sha256 => { + let mut hasher = Sha256::new(); + hasher.update(data); + Ok(hasher.finalize().to_vec()) + }, + Sha::Sha384 => { + let mut hasher = Sha384::new(); + hasher.update(data); + Ok(hasher.finalize().to_vec()) + }, + Sha::Sha512 => { + let mut hasher = Sha512::new(); + hasher.update(data); + Ok(hasher.finalize().to_vec()) + }, + } +} diff --git a/modules/llrt_crypto/src/subtle/encrypt.rs b/modules/llrt_crypto/src/subtle/encrypt.rs new file mode 100644 index 000000000..35a3098ef --- /dev/null +++ b/modules/llrt_crypto/src/subtle/encrypt.rs @@ -0,0 +1,78 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use aes::cipher::{block_padding::Pkcs7, BlockEncryptMut, KeyIvInit}; +use aes_gcm::{aead::Aead, KeyInit, Nonce}; +use ctr::{cipher::StreamCipher, Ctr128BE, Ctr32BE, Ctr64BE}; +use llrt_utils::result::ResultExt; +use rquickjs::{Ctx, Exception, Result}; +use rsa::{pkcs1::DecodeRsaPrivateKey, rand_core::OsRng, Oaep, RsaPrivateKey}; +use sha2::Sha256; + +use crate::subtle::{Aes256Gcm, Algorithm}; + +type Aes256CbcEnc = cbc::Encryptor; + +pub fn encrypt( + ctx: &Ctx<'_>, + algorithm: &Algorithm, + key_value: Vec, + data: Vec, +) -> Result> { + match algorithm { + Algorithm::AesGcm(iv) => { + let cipher = Aes256Gcm::new_from_slice(&key_value).or_throw(ctx)?; + let nonce = Nonce::from_slice(iv); + + match cipher.encrypt(nonce, data.as_ref()) { + Ok(result) => Ok(result), + Err(_) => Err(Exception::throw_message(ctx, "Encryption failed")), + } + }, + Algorithm::AesCbc(iv) => Ok(Aes256CbcEnc::new( + key_value.as_slice().into(), + iv.as_slice().into(), + ) + .encrypt_padded_vec_mut::(&data)), + Algorithm::AesCtr(counter, length) => match length { + 32 => encrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), + 64 => encrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), + 128 => encrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), + _ => Err(Exception::throw_message( + ctx, + "invalid counter length. Currently supported 32/64/128 bits", + )), + }, + Algorithm::RsaOaep(label) => { + let public_key = RsaPrivateKey::from_pkcs1_der(&key_value) + .or_throw(ctx)? + .to_public_key(); + let mut rng = OsRng; + let padding = match label { + Some(buf) => { + Oaep::new_with_label::(String::from_utf8(buf.to_vec())?) + }, + None => Oaep::new::(), + }; + let encrypted = public_key + .encrypt(&mut rng, padding, &data) + .map_err(|_| Exception::throw_message(ctx, "Encryption failed"))?; + + Ok(encrypted) + }, + _ => Err(Exception::throw_message(ctx, "Algorithm not supported")), + } +} + +fn encrypt_aes_ctr_gen(ctx: &Ctx<'_>, key: &[u8], counter: &[u8], data: &[u8]) -> Result> +where + B: KeyIvInit + StreamCipher, +{ + let mut cipher = B::new(key.into(), counter.into()); + + let mut ciphertext = data.to_vec(); + cipher + .try_apply_keystream(&mut ciphertext) + .map_err(|_| Exception::throw_message(ctx, "tried to encrypt too much data"))?; + + Ok(ciphertext) +} diff --git a/modules/llrt_crypto/src/subtle/generate_key.rs b/modules/llrt_crypto/src/subtle/generate_key.rs new file mode 100644 index 000000000..b5aedc4da --- /dev/null +++ b/modules/llrt_crypto/src/subtle/generate_key.rs @@ -0,0 +1,103 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use std::sync::OnceLock; + +use num_traits::FromPrimitive; +use ring::{ + rand::{SecureRandom, SystemRandom}, + signature::EcdsaKeyPair, +}; +use rquickjs::{Ctx, Exception, Result}; +use rsa::pkcs1::EncodeRsaPrivateKey; +use rsa::{rand_core::OsRng, BigUint, RsaPrivateKey}; + +use crate::subtle::{CryptoNamedCurve, KeyGenAlgorithm, Sha}; + +static PUB_EXPONENT_1: OnceLock = OnceLock::new(); +static PUB_EXPONENT_2: OnceLock = OnceLock::new(); + +pub fn generate_key(ctx: &Ctx<'_>, algorithm: &KeyGenAlgorithm) -> Result> { + match algorithm { + KeyGenAlgorithm::Rsa { + modulus_length, + ref public_exponent, + } => { + let exponent = BigUint::from_bytes_be(public_exponent); + + if exponent != *PUB_EXPONENT_1.get_or_init(|| BigUint::from_u64(3).unwrap()) + && exponent != *PUB_EXPONENT_2.get_or_init(|| BigUint::from_u64(65537).unwrap()) + { + return Err(Exception::throw_message(ctx, "Bad public exponent")); + } + + let mut rng = OsRng; + + let private_key = + RsaPrivateKey::new_with_exp(&mut rng, *modulus_length as usize, &exponent) + .map_err(|_| Exception::throw_message(ctx, "Failed to generate RSA key"))?; + + let private_key = private_key + .to_pkcs1_der() + .map_err(|_| Exception::throw_message(ctx, "Failed to serialize RSA key"))?; + + Ok(private_key.as_bytes().to_vec()) + }, + KeyGenAlgorithm::Ec { curve } => { + let curve = match curve { + CryptoNamedCurve::P256 => &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING, + CryptoNamedCurve::P384 => &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING, + }; + let rng = SystemRandom::new(); + let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng) + .map_err(|_| Exception::throw_message(ctx, "Failed to generate EC key"))?; + + Ok(pkcs8.as_ref().to_vec()) + }, + KeyGenAlgorithm::Aes { length } => { + let length = *length as usize; + + if length % 8 != 0 || length > 256 { + return Err(Exception::throw_message(ctx, "Invalid AES key length")); + } + + let mut key = vec![0u8; length / 8]; + let rng = SystemRandom::new(); + rng.fill(&mut key) + .map_err(|_| Exception::throw_message(ctx, "Failed to generate key"))?; + + Ok(key) + }, + KeyGenAlgorithm::Hmac { hash, length } => { + let _hash = match hash { + Sha::Sha1 => &ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, + Sha::Sha256 => &ring::hmac::HMAC_SHA256, + Sha::Sha384 => &ring::hmac::HMAC_SHA384, + Sha::Sha512 => &ring::hmac::HMAC_SHA512, + }; + + let length = if let Some(length) = length { + if length % 8 != 0 { + return Err(Exception::throw_message(ctx, "Invalid HMAC key length")); + } + + let length = length / 8; + + if length > ring::digest::MAX_BLOCK_LEN.try_into().unwrap() { + return Err(Exception::throw_message(ctx, "Invalid HMAC key length")); + } + + length as usize + } else { + //hash.digest_algorithm().block_len + ring::digest::MAX_BLOCK_LEN + }; + + let rng = ring::rand::SystemRandom::new(); + let mut key = vec![0u8; length]; + rng.fill(&mut key) + .map_err(|_| Exception::throw_message(ctx, "Failed to generate key"))?; + + Ok(key) + }, + } +} diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs new file mode 100644 index 000000000..8a4a876dd --- /dev/null +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -0,0 +1,385 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +mod decrypt; +mod derive_bits; +mod digest; +mod encrypt; +mod generate_key; +mod sign; +mod verify; + +use decrypt::decrypt; +use derive_bits::derive_bits; +use digest::digest; +use encrypt::encrypt; +use generate_key::generate_key; +use sign::sign; +use verify::verify; + +use aes::{cipher::typenum::U16, Aes256}; +use aes_gcm::AesGcm; +use hmac::Hmac; +use llrt_utils::object::ObjectExt; +use rquickjs::{Ctx, Exception, Result, Value}; +use sha2::Sha256; + +pub type HmacSha256 = Hmac; +pub type Aes256Gcm = AesGcm; + +#[derive(Debug)] +pub enum Sha { + Sha1, + Sha256, + Sha384, + Sha512, +} + +fn get_sha(ctx: &Ctx<'_>, hash: &str) -> Result { + match hash { + "SHA-1" => Ok(Sha::Sha1), + "SHA-256" => Ok(Sha::Sha256), + "SHA-384" => Ok(Sha::Sha384), + "SHA-512" => Ok(Sha::Sha512), + _ => Err(Exception::throw_message(ctx, "hash not found")), + } +} + +#[derive(Debug)] +pub enum Algorithm { + Hmac, + AesGcm(Vec), + AesCbc(Vec), + AesCtr(Vec, u32), + RsaPss(u32), + RsassaPkcs1v15, + Ecdsa(Sha), + RsaOaep(Option>), +} + +#[derive(Debug)] +pub enum CryptoNamedCurve { + P256, + P384, +} + +fn get_named_curve(ctx: &Ctx<'_>, curve: &str) -> Result { + match curve { + "P-256" => Ok(CryptoNamedCurve::P256), + "P-384" => Ok(CryptoNamedCurve::P384), + _ => Err(Exception::throw_message(ctx, "named_curve not found")), + } +} + +#[derive(Debug)] +pub enum DeriveAlgorithm { + Edch { + curve: CryptoNamedCurve, + public: Vec, + }, + Hkdf { + hash: Sha, + salt: Vec, + info: Vec, + }, + Pbkdf2 { + hash: Sha, + salt: Vec, + iterations: u32, + }, +} + +#[derive(Debug)] +pub enum KeyGenAlgorithm { + Rsa { + modulus_length: u32, + public_exponent: Vec, + }, + Ec { + curve: CryptoNamedCurve, + }, + Aes { + length: u32, + }, + Hmac { + hash: Sha, + length: Option, + }, +} + +pub fn subtle_decrypt( + ctx: Ctx<'_>, + algorithm: Value, + key_value: Vec, + data: Vec, +) -> Result> { + let algorithm = extract_algorithm_object(&ctx, &algorithm)?; + decrypt(&ctx, &algorithm, key_value, data) +} + +pub fn subtle_derive_bits( + ctx: Ctx<'_>, + algorithm: Value, + key_value: Vec, + length: u32, +) -> Result> { + let derive_algorithm = extract_derive_algorithm(&ctx, &algorithm)?; + derive_bits(&ctx, &derive_algorithm, key_value, length) +} + +pub fn subtle_digest(ctx: Ctx<'_>, name: String, data: Vec) -> Result> { + digest(ctx, &name, data) +} + +pub fn subtle_encrypt( + ctx: Ctx<'_>, + algorithm: Value, + key_value: Vec, + data: Vec, +) -> Result> { + let algorithm = extract_algorithm_object(&ctx, &algorithm)?; + encrypt(&ctx, &algorithm, key_value, data) +} + +pub fn subtle_generate_key(ctx: Ctx<'_>, algorithm: Value) -> Result> { + let key_gen_algorithm = extract_generate_key_algorithm(&ctx, &algorithm)?; + generate_key(&ctx, &key_gen_algorithm) +} + +pub fn subtle_sign( + ctx: Ctx<'_>, + algorithm: Value, + key_value: Vec, + data: Vec, +) -> Result> { + let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; + sign(&ctx, &algorithm, key_value, data) +} + +pub fn subtle_verify( + ctx: Ctx<'_>, + algorithm: Value, + key_value: Vec, + signature: Vec, + data: Vec, +) -> Result { + let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; + verify(&ctx, &algorithm, key_value, signature, data) +} + +fn extract_algorithm_object(ctx: &Ctx<'_>, algorithm: &Value) -> Result { + let name = algorithm + .get_optional::<_, String>("name")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; + + if name == "HMAC" { + return Ok(Algorithm::Hmac); + } + + if name == "AES-GCM" { + let iv = algorithm + .get_optional("iv")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm iv not found"))?; + + return Ok(Algorithm::AesGcm(iv)); + } + + if name == "AES-CBC" { + let iv = algorithm + .get_optional("iv")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm iv not found"))?; + + return Ok(Algorithm::AesCbc(iv)); + } + + if name == "AES-CTR" { + let counter = algorithm + .get_optional("counter")? + .ok_or_else(|| Exception::throw_message(ctx, "AES-CTR counter not found"))?; + + let length = algorithm + .get_optional("length")? + .ok_or_else(|| Exception::throw_message(ctx, "AES-CTR length not found"))?; + + return Ok(Algorithm::AesCtr(counter, length)); + } + + if name == "RSA-OAEP" { + let label = algorithm.get_optional("label")?; + + return Ok(Algorithm::RsaOaep(label)); + } + + Err(Exception::throw_message(ctx, "Algorithm not supported")) +} + +fn extract_sha_hash(ctx: &Ctx<'_>, algorithm: &Value) -> Result { + let hash = algorithm + .get_optional::<_, String>("hash")? + .ok_or_else(|| Exception::throw_message(ctx, "hash not found"))?; + + get_sha(ctx, &hash) +} + +fn extract_sign_verify_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { + if algorithm.is_string() { + let algorithm_name = algorithm.as_string().unwrap().to_string()?; + if algorithm_name == "RSASSA-PKCS1-v1_5" { + return Ok(Algorithm::RsassaPkcs1v15); + } + + if algorithm_name == "HMAC" { + return Ok(Algorithm::Hmac); + } + + return Err(Exception::throw_message(ctx, "Algorithm not supported")); + } + + let name = algorithm + .get_optional::<_, String>("name")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; + + if name == "RSASSA-PKCS1-v1_5" { + return Ok(Algorithm::RsassaPkcs1v15); + } + + if name == "HMAC" { + return Ok(Algorithm::Hmac); + } + + if name == "RSA-PSS" { + let salt_length = algorithm + .get_optional("saltLength")? + .ok_or_else(|| Exception::throw_message(ctx, "RSA-PSS saltLength not found"))?; + + return Ok(Algorithm::RsaPss(salt_length)); + } + + if name == "ECDSA" { + let sha = extract_sha_hash(ctx, algorithm)?; + + return Ok(Algorithm::Ecdsa(sha)); + } + + Err(Exception::throw_message(ctx, "Algorithm not supported")) +} + +fn extract_derive_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { + let name = algorithm + .get_optional::<_, String>("name")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; + + if name == "ECDH" { + let namedcurve = algorithm + .get_optional::<_, String>("namedcurve")? + .ok_or_else(|| { + Exception::throw_message(ctx, "ECDH namedCurve must be one of: P-256 or P-384") + })?; + + let curve = get_named_curve(ctx, &namedcurve)?; + + let public = algorithm + .get_optional("public")? + .ok_or_else(|| Exception::throw_message(ctx, "ECDH must have CryptoKey"))?; + + return Ok(DeriveAlgorithm::Edch { curve, public }); + } + + if name == "HKDF" { + let hash = algorithm + .get_optional::<_, String>("hash")? + .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have hash"))?; + + let hash = get_sha(ctx, &hash)?; + + let salt = algorithm + .get_optional("salt")? + .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have salt"))?; + + let info = algorithm + .get_optional("info")? + .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have info"))?; + + return Ok(DeriveAlgorithm::Hkdf { hash, salt, info }); + } + + if name == "PBKDF2" { + let hash = algorithm + .get_optional::<_, String>("hash")? + .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have hash"))?; + + let hash = get_sha(ctx, &hash)?; + + let salt = algorithm + .get_optional("salt")? + .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have salt"))?; + + let iterations = algorithm + .get_optional("iterations")? + .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have iterations"))?; + + return Ok(DeriveAlgorithm::Pbkdf2 { + hash, + salt, + iterations, + }); + } + + Err(Exception::throw_message(ctx, "Algorithm not supported")) +} + +fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { + let name = algorithm + .get_optional::<_, String>("name")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; + + if name == "RSASSA-PKCS1-v1_5" || name == "RSA-PSS" || name == "RSA-OAEP" { + let modulus_length = algorithm + .get_optional("modulusLength")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm modulusLength not found"))?; + + let public_exponent = algorithm + .get_optional("publicExponent")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm publicExponent not found"))?; + + return Ok(KeyGenAlgorithm::Rsa { + modulus_length, + public_exponent, + }); + } + + if name == "ECDSA" || name == "ECDH" { + let namedcurve = algorithm + .get_optional::<_, String>("namedCurve")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm namedCurve not found"))?; + let curve = get_named_curve(ctx, &namedcurve)?; + + return Ok(KeyGenAlgorithm::Ec { curve }); + } + + if name == "HMAC" { + let hash = extract_sha_hash(ctx, algorithm)?; + + let length = algorithm.get_optional::<_, u32>("length")?; + return Ok(KeyGenAlgorithm::Hmac { hash, length }); + } + + if name == "AES-CTR" || name == "AES-CBC" || name == "AES-GCM" || name == "AES-KW" { + let length = algorithm + .get_optional("length")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm length not found"))?; + + if length != 128 && length != 192 && length != 256 { + return Err(Exception::throw_message( + ctx, + "Algorithm length must be one of: 128, 192, or 256.", + )); + } + + return Ok(KeyGenAlgorithm::Aes { length }); + } + + Err(Exception::throw_message( + ctx, + "Algorithm must be RsaHashedKeyGenParams | EcKeyGenParams | HmacKeyGenParams | AesKeyGenParams" + )) +} diff --git a/modules/llrt_crypto/src/subtle/sign.rs b/modules/llrt_crypto/src/subtle/sign.rs new file mode 100644 index 000000000..0086c4547 --- /dev/null +++ b/modules/llrt_crypto/src/subtle/sign.rs @@ -0,0 +1,83 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use hmac::Mac; +use llrt_utils::result::ResultExt; +use rand::rngs::OsRng; +use ring::{rand::SystemRandom, signature::EcdsaKeyPair}; +use rquickjs::{Ctx, Exception, Result}; +use rsa::{ + pkcs1::DecodeRsaPrivateKey, + pss::Pss, + sha2::{Digest, Sha256}, +}; +use rsa::{Pkcs1v15Sign, RsaPrivateKey}; + +use crate::subtle::{Algorithm, HmacSha256, Sha}; + +pub fn sign( + ctx: &Ctx<'_>, + algorithm: &Algorithm, + key_value: Vec, + data: Vec, +) -> Result> { + match algorithm { + Algorithm::Hmac => { + let mut mac = HmacSha256::new_from_slice(&key_value).or_throw(ctx)?; + mac.update(&data); + + Ok(mac.finalize().into_bytes().to_vec()) + }, + Algorithm::RsassaPkcs1v15 => { + let private_key = RsaPrivateKey::from_pkcs1_der(&key_value).or_throw(ctx)?; + let mut hasher = Sha256::new(); + hasher.update(&data); + + let hashed = hasher.finalize()[..].to_vec(); + + Ok(private_key + .sign(Pkcs1v15Sign::new::(), &hashed) + .or_throw(ctx)?) + }, + Algorithm::RsaPss(salt_length) => { + let private_key = RsaPrivateKey::from_pkcs1_der(&key_value).or_throw(ctx)?; + let mut rng = OsRng; + let mut hasher = Sha256::new(); + hasher.update(&data); + + let hashed = hasher.finalize()[..].to_vec(); + + Ok(private_key + .sign_with_rng( + &mut rng, + Pss::new_with_salt::(*salt_length as usize), + &hashed, + ) + .or_throw(ctx)?) + }, + Algorithm::Ecdsa(sha) => match sha { + Sha::Sha256 => { + let curve = &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING; + let rng = SystemRandom::new(); + let key_pair = EcdsaKeyPair::from_pkcs8(curve, &key_value, &rng).or_throw(ctx)?; + + let signature = key_pair.sign(&rng, &data).or_throw(ctx)?; + + Ok(signature.as_ref().to_vec()) + }, + Sha::Sha384 => { + let curve = &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING; + let rng = SystemRandom::new(); + let key_pair = EcdsaKeyPair::from_pkcs8(curve, &key_value, &rng).or_throw(ctx)?; + + let signature = key_pair.sign(&rng, &data).or_throw(ctx)?; + + Ok(signature.as_ref().to_vec()) + }, + _ => Err(Exception::throw_message( + ctx, + "Ecdsa.hash only support Sha256 or Sha384", + )), + }, + _ => Err(Exception::throw_message(ctx, "Algorithm not supported")), + } +} diff --git a/modules/llrt_crypto/src/subtle/verify.rs b/modules/llrt_crypto/src/subtle/verify.rs new file mode 100644 index 000000000..865de6d4e --- /dev/null +++ b/modules/llrt_crypto/src/subtle/verify.rs @@ -0,0 +1,106 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use hmac::Mac; +use llrt_utils::result::ResultExt; +use ring::{ + rand::SystemRandom, + signature::{EcdsaKeyPair, KeyPair}, +}; +use rquickjs::{Ctx, Exception, Result}; +use rsa::{ + pkcs1::DecodeRsaPrivateKey, + pkcs1v15::Pkcs1v15Sign, + pss::Pss, + sha2::{Digest, Sha256}, + RsaPrivateKey, +}; + +use crate::subtle::{Algorithm, HmacSha256, Sha}; + +pub fn verify( + ctx: &Ctx<'_>, + algorithm: &Algorithm, + key_value: Vec, + signature: Vec, + data: Vec, +) -> Result { + match algorithm { + Algorithm::Hmac => { + let mut mac = HmacSha256::new_from_slice(&key_value).or_throw(ctx)?; + mac.update(&data); + + Ok(mac.verify_slice(&signature).is_ok()) + }, + Algorithm::RsassaPkcs1v15 => { + let public_key = RsaPrivateKey::from_pkcs1_der(&key_value) + .or_throw(ctx)? + .to_public_key(); + let mut hasher = Sha256::new(); + hasher.update(&data); + + let hashed = hasher.finalize()[..].to_vec(); + + Ok(public_key + .verify(Pkcs1v15Sign::new::(), &hashed, &signature) + .is_ok()) + }, + Algorithm::RsaPss(salt_length) => { + let public_key = RsaPrivateKey::from_pkcs1_der(&key_value) + .or_throw(ctx)? + .to_public_key(); + let mut hasher = Sha256::new(); + + hasher.update(&data); + let hashed = hasher.finalize()[..].to_vec(); + + Ok(public_key + .verify( + Pss::new_with_salt::(*salt_length as usize), + &hashed, + &signature, + ) + .is_ok()) + }, + Algorithm::Ecdsa(sha) => match sha { + Sha::Sha256 => { + let rng = SystemRandom::new(); + let private_key = EcdsaKeyPair::from_pkcs8( + &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING, + &key_value, + &rng, + ) + .or_throw(ctx)?; + + let public_key_bytes = private_key.public_key().as_ref(); + let public_key = ring::signature::UnparsedPublicKey::new( + &ring::signature::ECDSA_P256_SHA256_FIXED, + &public_key_bytes, + ); + + Ok(public_key.verify(&data, &signature).is_ok()) + }, + Sha::Sha384 => { + let rng = SystemRandom::new(); + let private_key = EcdsaKeyPair::from_pkcs8( + &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING, + &key_value, + &rng, + ) + .or_throw(ctx)?; + + let public_key_bytes = private_key.public_key().as_ref(); + let public_key = ring::signature::UnparsedPublicKey::new( + &ring::signature::ECDSA_P384_SHA384_FIXED, + &public_key_bytes, + ); + + Ok(public_key.verify(&data, &signature).is_ok()) + }, + _ => Err(Exception::throw_message( + ctx, + "Ecdsa.hash only support Sha256 or Sha384", + )), + }, + _ => Err(Exception::throw_message(ctx, "Algorithm not supported")), + } +} From a4d83217d3b7b6994917cccb230125e95ac45e65 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Sun, 24 Nov 2024 07:04:36 +0900 Subject: [PATCH 02/22] Refactor extract logic --- modules/llrt_crypto/src/subtle/mod.rs | 324 ++++++++++++-------------- 1 file changed, 153 insertions(+), 171 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index 8a4a876dd..6d3b3cf08 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -171,45 +171,40 @@ fn extract_algorithm_object(ctx: &Ctx<'_>, algorithm: &Value) -> Result("name")? .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; - if name == "HMAC" { - return Ok(Algorithm::Hmac); + match name.as_str() { + "HMAC" => Ok(Algorithm::Hmac), + "AES-GCM" => { + let iv = algorithm + .get_optional("iv")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm iv not found"))?; + + Ok(Algorithm::AesGcm(iv)) + }, + "AES-CBC" => { + let iv = algorithm + .get_optional("iv")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm iv not found"))?; + + Ok(Algorithm::AesCbc(iv)) + }, + "AES-CTR" => { + let counter = algorithm + .get_optional("counter")? + .ok_or_else(|| Exception::throw_message(ctx, "AES-CTR counter not found"))?; + + let length = algorithm + .get_optional("length")? + .ok_or_else(|| Exception::throw_message(ctx, "AES-CTR length not found"))?; + + Ok(Algorithm::AesCtr(counter, length)) + }, + "RSA-OAEP" => { + let label = algorithm.get_optional("label")?; + + Ok(Algorithm::RsaOaep(label)) + }, + _ => Err(Exception::throw_message(ctx, "Algorithm not supported")), } - - if name == "AES-GCM" { - let iv = algorithm - .get_optional("iv")? - .ok_or_else(|| Exception::throw_message(ctx, "Algorithm iv not found"))?; - - return Ok(Algorithm::AesGcm(iv)); - } - - if name == "AES-CBC" { - let iv = algorithm - .get_optional("iv")? - .ok_or_else(|| Exception::throw_message(ctx, "Algorithm iv not found"))?; - - return Ok(Algorithm::AesCbc(iv)); - } - - if name == "AES-CTR" { - let counter = algorithm - .get_optional("counter")? - .ok_or_else(|| Exception::throw_message(ctx, "AES-CTR counter not found"))?; - - let length = algorithm - .get_optional("length")? - .ok_or_else(|| Exception::throw_message(ctx, "AES-CTR length not found"))?; - - return Ok(Algorithm::AesCtr(counter, length)); - } - - if name == "RSA-OAEP" { - let label = algorithm.get_optional("label")?; - - return Ok(Algorithm::RsaOaep(label)); - } - - Err(Exception::throw_message(ctx, "Algorithm not supported")) } fn extract_sha_hash(ctx: &Ctx<'_>, algorithm: &Value) -> Result { @@ -223,44 +218,35 @@ fn extract_sha_hash(ctx: &Ctx<'_>, algorithm: &Value) -> Result { fn extract_sign_verify_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { if algorithm.is_string() { let algorithm_name = algorithm.as_string().unwrap().to_string()?; - if algorithm_name == "RSASSA-PKCS1-v1_5" { - return Ok(Algorithm::RsassaPkcs1v15); - } - if algorithm_name == "HMAC" { - return Ok(Algorithm::Hmac); - } - - return Err(Exception::throw_message(ctx, "Algorithm not supported")); + return match algorithm_name.as_str() { + "RSASSA-PKCS1-v1_5" => Ok(Algorithm::RsassaPkcs1v15), + "HMAC" => Ok(Algorithm::Hmac), + _ => Err(Exception::throw_message(ctx, "Algorithm not supported")), + }; } let name = algorithm .get_optional::<_, String>("name")? .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; - if name == "RSASSA-PKCS1-v1_5" { - return Ok(Algorithm::RsassaPkcs1v15); - } - - if name == "HMAC" { - return Ok(Algorithm::Hmac); + match name.as_str() { + "RSASSA-PKCS1-v1_5" => Ok(Algorithm::RsassaPkcs1v15), + "HMAC" => Ok(Algorithm::Hmac), + "RSA-PSS" => { + let salt_length = algorithm + .get_optional("saltLength")? + .ok_or_else(|| Exception::throw_message(ctx, "RSA-PSS saltLength not found"))?; + + Ok(Algorithm::RsaPss(salt_length)) + }, + "ECDSA" => { + let sha = extract_sha_hash(ctx, algorithm)?; + + Ok(Algorithm::Ecdsa(sha)) + }, + _ => Err(Exception::throw_message(ctx, "Algorithm not supported")), } - - if name == "RSA-PSS" { - let salt_length = algorithm - .get_optional("saltLength")? - .ok_or_else(|| Exception::throw_message(ctx, "RSA-PSS saltLength not found"))?; - - return Ok(Algorithm::RsaPss(salt_length)); - } - - if name == "ECDSA" { - let sha = extract_sha_hash(ctx, algorithm)?; - - return Ok(Algorithm::Ecdsa(sha)); - } - - Err(Exception::throw_message(ctx, "Algorithm not supported")) } fn extract_derive_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { @@ -268,63 +254,62 @@ fn extract_derive_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result("name")? .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; - if name == "ECDH" { - let namedcurve = algorithm - .get_optional::<_, String>("namedcurve")? - .ok_or_else(|| { - Exception::throw_message(ctx, "ECDH namedCurve must be one of: P-256 or P-384") - })?; - - let curve = get_named_curve(ctx, &namedcurve)?; - - let public = algorithm - .get_optional("public")? - .ok_or_else(|| Exception::throw_message(ctx, "ECDH must have CryptoKey"))?; - - return Ok(DeriveAlgorithm::Edch { curve, public }); - } - - if name == "HKDF" { - let hash = algorithm - .get_optional::<_, String>("hash")? - .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have hash"))?; - - let hash = get_sha(ctx, &hash)?; - - let salt = algorithm - .get_optional("salt")? - .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have salt"))?; - - let info = algorithm - .get_optional("info")? - .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have info"))?; - - return Ok(DeriveAlgorithm::Hkdf { hash, salt, info }); + match name.as_str() { + "ECDH" => { + let namedcurve = algorithm + .get_optional::<_, String>("namedcurve")? + .ok_or_else(|| { + Exception::throw_message(ctx, "ECDH namedCurve must be one of: P-256 or P-384") + })?; + + let curve = get_named_curve(ctx, &namedcurve)?; + + let public = algorithm + .get_optional("public")? + .ok_or_else(|| Exception::throw_message(ctx, "ECDH must have CryptoKey"))?; + + Ok(DeriveAlgorithm::Edch { curve, public }) + }, + "HKDF" => { + let hash = algorithm + .get_optional::<_, String>("hash")? + .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have hash"))?; + + let hash = get_sha(ctx, &hash)?; + + let salt = algorithm + .get_optional("salt")? + .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have salt"))?; + + let info = algorithm + .get_optional("info")? + .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have info"))?; + + Ok(DeriveAlgorithm::Hkdf { hash, salt, info }) + }, + "PBKDF2" => { + let hash = algorithm + .get_optional::<_, String>("hash")? + .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have hash"))?; + + let hash = get_sha(ctx, &hash)?; + + let salt = algorithm + .get_optional("salt")? + .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have salt"))?; + + let iterations = algorithm + .get_optional("iterations")? + .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have iterations"))?; + + Ok(DeriveAlgorithm::Pbkdf2 { + hash, + salt, + iterations, + }) + }, + _ => Err(Exception::throw_message(ctx, "Algorithm not supported")), } - - if name == "PBKDF2" { - let hash = algorithm - .get_optional::<_, String>("hash")? - .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have hash"))?; - - let hash = get_sha(ctx, &hash)?; - - let salt = algorithm - .get_optional("salt")? - .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have salt"))?; - - let iterations = algorithm - .get_optional("iterations")? - .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have iterations"))?; - - return Ok(DeriveAlgorithm::Pbkdf2 { - hash, - salt, - iterations, - }); - } - - Err(Exception::throw_message(ctx, "Algorithm not supported")) } fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { @@ -332,54 +317,51 @@ fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result("name")? .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; - if name == "RSASSA-PKCS1-v1_5" || name == "RSA-PSS" || name == "RSA-OAEP" { - let modulus_length = algorithm - .get_optional("modulusLength")? - .ok_or_else(|| Exception::throw_message(ctx, "Algorithm modulusLength not found"))?; - - let public_exponent = algorithm - .get_optional("publicExponent")? - .ok_or_else(|| Exception::throw_message(ctx, "Algorithm publicExponent not found"))?; - - return Ok(KeyGenAlgorithm::Rsa { - modulus_length, - public_exponent, - }); - } - - if name == "ECDSA" || name == "ECDH" { - let namedcurve = algorithm - .get_optional::<_, String>("namedCurve")? - .ok_or_else(|| Exception::throw_message(ctx, "Algorithm namedCurve not found"))?; - let curve = get_named_curve(ctx, &namedcurve)?; - - return Ok(KeyGenAlgorithm::Ec { curve }); - } - - if name == "HMAC" { - let hash = extract_sha_hash(ctx, algorithm)?; - - let length = algorithm.get_optional::<_, u32>("length")?; - return Ok(KeyGenAlgorithm::Hmac { hash, length }); - } - - if name == "AES-CTR" || name == "AES-CBC" || name == "AES-GCM" || name == "AES-KW" { - let length = algorithm - .get_optional("length")? - .ok_or_else(|| Exception::throw_message(ctx, "Algorithm length not found"))?; + match name.as_str() { + "RSASSA-PKCS1-v1_5" | "RSA-PSS" | "RSA-OAEP" => { + let modulus_length = algorithm.get_optional("modulusLength")?.ok_or_else(|| { + Exception::throw_message(ctx, "Algorithm modulusLength not found") + })?; - if length != 128 && length != 192 && length != 256 { - return Err(Exception::throw_message( - ctx, - "Algorithm length must be one of: 128, 192, or 256.", - )); - } + let public_exponent = algorithm.get_optional("publicExponent")?.ok_or_else(|| { + Exception::throw_message(ctx, "Algorithm publicExponent not found") + })?; - return Ok(KeyGenAlgorithm::Aes { length }); + Ok(KeyGenAlgorithm::Rsa { + modulus_length, + public_exponent, + }) + }, + "ECDSA" | "ECDH" => { + let namedcurve = algorithm + .get_optional::<_, String>("namedCurve")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm namedCurve not found"))?; + + let curve = get_named_curve(ctx, &namedcurve)?; + + Ok(KeyGenAlgorithm::Ec { curve }) + }, + "HMAC" => { + let hash = extract_sha_hash(ctx, algorithm)?; + + let length = algorithm.get_optional::<_, u32>("length")?; + + Ok(KeyGenAlgorithm::Hmac { hash, length }) + }, + "AES-CTR" | "AES-CBC" | "AES-GCM" | "AES-KW" => { + let length = algorithm + .get_optional("length")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm length not found"))?; + + if length != 128 && length != 192 && length != 256 { + return Err(Exception::throw_message( + ctx, + "Algorithm length must be one of: 128, 192, or 256.", + )); + } + + Ok(KeyGenAlgorithm::Aes { length }) + }, + _ => Err(Exception::throw_message(ctx,"Algorithm must be RsaHashedKeyGenParams | EcKeyGenParams | HmacKeyGenParams | AesKeyGenParams")) } - - Err(Exception::throw_message( - ctx, - "Algorithm must be RsaHashedKeyGenParams | EcKeyGenParams | HmacKeyGenParams | AesKeyGenParams" - )) } From 0f4050e119c5be00bec0c7a7d972f0ae777ed070 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Sun, 24 Nov 2024 14:38:18 +0900 Subject: [PATCH 03/22] Asynchronous support and tiny fix --- modules/llrt_crypto/src/lib.rs | 16 ++++++------- .../llrt_crypto/src/subtle/generate_key.rs | 5 ++-- modules/llrt_crypto/src/subtle/mod.rs | 24 +++++++++---------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/modules/llrt_crypto/src/lib.rs b/modules/llrt_crypto/src/lib.rs index 5de524138..ea9a124c0 100644 --- a/modules/llrt_crypto/src/lib.rs +++ b/modules/llrt_crypto/src/lib.rs @@ -23,7 +23,7 @@ use ring::rand::{SecureRandom, SystemRandom}; use rquickjs::{ function::{Constructor, Opt}, module::{Declarations, Exports, ModuleDef}, - prelude::{Func, Rest}, + prelude::{Async, Func, Rest}, Class, Ctx, Error, Exception, Function, IntoJs, Null, Object, Result, Value, }; use subtle::{ @@ -191,13 +191,13 @@ pub fn init(ctx: &Ctx<'_>) -> Result<()> { crypto.set("getRandomValues", Func::from(get_random_values))?; let subtle = Object::new(ctx.clone())?; - subtle.set("decrypt", Func::from(subtle_decrypt))?; - subtle.set("deriveBits", Func::from(subtle_derive_bits))?; - subtle.set("digest", Func::from(subtle_digest))?; - subtle.set("encrypt", Func::from(subtle_encrypt))?; - subtle.set("generateKey", Func::from(subtle_generate_key))?; - subtle.set("verify", Func::from(subtle_verify))?; - subtle.set("sign", Func::from(subtle_sign))?; + subtle.set("decrypt", Func::from(Async(subtle_decrypt)))?; + subtle.set("deriveBits", Func::from(Async(subtle_derive_bits)))?; + subtle.set("digest", Func::from(Async(subtle_digest)))?; + subtle.set("encrypt", Func::from(Async(subtle_encrypt)))?; + subtle.set("generateKey", Func::from(Async(subtle_generate_key)))?; + subtle.set("verify", Func::from(Async(subtle_verify)))?; + subtle.set("sign", Func::from(Async(subtle_sign)))?; crypto.set("subtle", subtle)?; globals.set("crypto", crypto)?; diff --git a/modules/llrt_crypto/src/subtle/generate_key.rs b/modules/llrt_crypto/src/subtle/generate_key.rs index b5aedc4da..00832b0f2 100644 --- a/modules/llrt_crypto/src/subtle/generate_key.rs +++ b/modules/llrt_crypto/src/subtle/generate_key.rs @@ -68,7 +68,7 @@ pub fn generate_key(ctx: &Ctx<'_>, algorithm: &KeyGenAlgorithm) -> Result { - let _hash = match hash { + let hash = match hash { Sha::Sha1 => &ring::hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, Sha::Sha256 => &ring::hmac::HMAC_SHA256, Sha::Sha384 => &ring::hmac::HMAC_SHA384, @@ -88,8 +88,7 @@ pub fn generate_key(ctx: &Ctx<'_>, algorithm: &KeyGenAlgorithm) -> Result, - algorithm: Value, + algorithm: Value<'_>, key_value: Vec, data: Vec, ) -> Result> { @@ -116,9 +116,9 @@ pub fn subtle_decrypt( decrypt(&ctx, &algorithm, key_value, data) } -pub fn subtle_derive_bits( +pub async fn subtle_derive_bits( ctx: Ctx<'_>, - algorithm: Value, + algorithm: Value<'_>, key_value: Vec, length: u32, ) -> Result> { @@ -126,13 +126,13 @@ pub fn subtle_derive_bits( derive_bits(&ctx, &derive_algorithm, key_value, length) } -pub fn subtle_digest(ctx: Ctx<'_>, name: String, data: Vec) -> Result> { +pub async fn subtle_digest(ctx: Ctx<'_>, name: String, data: Vec) -> Result> { digest(ctx, &name, data) } -pub fn subtle_encrypt( +pub async fn subtle_encrypt( ctx: Ctx<'_>, - algorithm: Value, + algorithm: Value<'_>, key_value: Vec, data: Vec, ) -> Result> { @@ -140,14 +140,14 @@ pub fn subtle_encrypt( encrypt(&ctx, &algorithm, key_value, data) } -pub fn subtle_generate_key(ctx: Ctx<'_>, algorithm: Value) -> Result> { +pub async fn subtle_generate_key(ctx: Ctx<'_>, algorithm: Value<'_>) -> Result> { let key_gen_algorithm = extract_generate_key_algorithm(&ctx, &algorithm)?; generate_key(&ctx, &key_gen_algorithm) } -pub fn subtle_sign( +pub async fn subtle_sign( ctx: Ctx<'_>, - algorithm: Value, + algorithm: Value<'_>, key_value: Vec, data: Vec, ) -> Result> { @@ -155,9 +155,9 @@ pub fn subtle_sign( sign(&ctx, &algorithm, key_value, data) } -pub fn subtle_verify( +pub async fn subtle_verify( ctx: Ctx<'_>, - algorithm: Value, + algorithm: Value<'_>, key_value: Vec, signature: Vec, data: Vec, From 5161cce815f288abea8952b8be8adf441e9a8339 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Sun, 24 Nov 2024 20:30:40 +0900 Subject: [PATCH 04/22] Refactor arguments and return values --- modules/llrt_crypto/src/subtle/digest.rs | 4 +- modules/llrt_crypto/src/subtle/mod.rs | 120 +++++++++++++++-------- 2 files changed, 81 insertions(+), 43 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/digest.rs b/modules/llrt_crypto/src/subtle/digest.rs index c62033aa0..dabdc339a 100644 --- a/modules/llrt_crypto/src/subtle/digest.rs +++ b/modules/llrt_crypto/src/subtle/digest.rs @@ -6,8 +6,8 @@ use sha2::{Digest, Sha256, Sha384, Sha512}; use crate::subtle::{get_sha, Sha}; -pub fn digest(ctx: Ctx<'_>, name: &str, data: Vec) -> Result> { - let sha = get_sha(&ctx, name)?; +pub fn digest(ctx: &Ctx<'_>, name: &str, data: Vec) -> Result> { + let sha = get_sha(ctx, name)?; match sha { Sha::Sha1 => { diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index 97f722ea0..9cdb7900a 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -19,8 +19,8 @@ use verify::verify; use aes::{cipher::typenum::U16, Aes256}; use aes_gcm::AesGcm; use hmac::Hmac; -use llrt_utils::object::ObjectExt; -use rquickjs::{Ctx, Exception, Result, Value}; +use llrt_utils::{bytes::get_array_bytes, object::ObjectExt}; +use rquickjs::{ArrayBuffer, Ctx, Exception, Result, Value}; use sha2::Sha256; pub type HmacSha256 = Hmac; @@ -35,7 +35,7 @@ pub enum Sha { } fn get_sha(ctx: &Ctx<'_>, hash: &str) -> Result { - match hash { + match hash.to_ascii_uppercase().as_str() { "SHA-1" => Ok(Sha::Sha1), "SHA-256" => Ok(Sha::Sha256), "SHA-384" => Ok(Sha::Sha384), @@ -63,7 +63,7 @@ pub enum CryptoNamedCurve { } fn get_named_curve(ctx: &Ctx<'_>, curve: &str) -> Result { - match curve { + match curve.to_ascii_uppercase().as_str() { "P-256" => Ok(CryptoNamedCurve::P256), "P-384" => Ok(CryptoNamedCurve::P384), _ => Err(Exception::throw_message(ctx, "named_curve not found")), @@ -106,63 +106,101 @@ pub enum KeyGenAlgorithm { }, } -pub async fn subtle_decrypt( - ctx: Ctx<'_>, - algorithm: Value<'_>, - key_value: Vec, - data: Vec, -) -> Result> { +pub async fn subtle_decrypt<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + key_value: Value<'js>, + data: Value<'js>, +) -> Result> { let algorithm = extract_algorithm_object(&ctx, &algorithm)?; - decrypt(&ctx, &algorithm, key_value, data) + let key_value = get_array_bytes(&key_value, 0, None)?.unwrap_or_else(Vec::new); + let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); + + let bytes = decrypt(&ctx, &algorithm, key_value, data)?; + ArrayBuffer::new(ctx, bytes.as_slice()) } -pub async fn subtle_derive_bits( - ctx: Ctx<'_>, - algorithm: Value<'_>, - key_value: Vec, +pub async fn subtle_derive_bits<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + key_value: Value<'js>, length: u32, -) -> Result> { +) -> Result> { let derive_algorithm = extract_derive_algorithm(&ctx, &algorithm)?; - derive_bits(&ctx, &derive_algorithm, key_value, length) + let key_value = get_array_bytes(&key_value, 0, None)?.unwrap_or_else(Vec::new); + + let bytes = derive_bits(&ctx, &derive_algorithm, key_value, length)?; + ArrayBuffer::new(ctx, bytes.as_slice()) } -pub async fn subtle_digest(ctx: Ctx<'_>, name: String, data: Vec) -> Result> { - digest(ctx, &name, data) +pub async fn subtle_digest<'js>( + ctx: Ctx<'js>, + name: Value<'js>, + data: Value<'js>, +) -> Result> { + let name = if name.is_string() { + name.as_string().unwrap().to_string().unwrap() + } else { + name.get_optional::<_, String>("name")?.ok_or_else(|| { + Exception::throw_message(&ctx, "Missing algorithm name should cause TypeError") + })? + }; + let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); + + let bytes = digest(&ctx, &name, data)?; + ArrayBuffer::new(ctx, bytes.as_slice()) } -pub async fn subtle_encrypt( - ctx: Ctx<'_>, - algorithm: Value<'_>, - key_value: Vec, - data: Vec, -) -> Result> { +pub async fn subtle_encrypt<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + key_value: Value<'js>, + data: Value<'js>, +) -> Result> { let algorithm = extract_algorithm_object(&ctx, &algorithm)?; - encrypt(&ctx, &algorithm, key_value, data) + let key_value = get_array_bytes(&key_value, 0, None)?.unwrap_or_else(Vec::new); + let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); + + let bytes = encrypt(&ctx, &algorithm, key_value, data)?; + ArrayBuffer::new(ctx, bytes.as_slice()) } -pub async fn subtle_generate_key(ctx: Ctx<'_>, algorithm: Value<'_>) -> Result> { +pub async fn subtle_generate_key<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, +) -> Result> { let key_gen_algorithm = extract_generate_key_algorithm(&ctx, &algorithm)?; - generate_key(&ctx, &key_gen_algorithm) + + let bytes = generate_key(&ctx, &key_gen_algorithm)?; + ArrayBuffer::new(ctx, bytes.as_slice()) } -pub async fn subtle_sign( - ctx: Ctx<'_>, - algorithm: Value<'_>, - key_value: Vec, - data: Vec, -) -> Result> { +pub async fn subtle_sign<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + key_value: Value<'js>, + data: Value<'js>, +) -> Result> { let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; - sign(&ctx, &algorithm, key_value, data) + let key_value = get_array_bytes(&key_value, 0, None)?.unwrap_or_else(Vec::new); + let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); + + let bytes = sign(&ctx, &algorithm, key_value, data)?; + ArrayBuffer::new(ctx, bytes.as_slice()) } -pub async fn subtle_verify( - ctx: Ctx<'_>, - algorithm: Value<'_>, - key_value: Vec, - signature: Vec, - data: Vec, +pub async fn subtle_verify<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + key_value: Value<'js>, + signature: Value<'js>, + data: Value<'js>, ) -> Result { let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; + let key_value = get_array_bytes(&key_value, 0, None)?.unwrap_or_else(Vec::new); + let signature = get_array_bytes(&signature, 0, None)?.unwrap_or_else(Vec::new); + let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); + verify(&ctx, &algorithm, key_value, signature, data) } From a49891948984b55b9ac58c4c19477974bc7f7e6e Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Sun, 24 Nov 2024 21:57:04 +0900 Subject: [PATCH 05/22] Refactor argument names --- modules/llrt_crypto/src/subtle/decrypt.rs | 14 +++--- modules/llrt_crypto/src/subtle/derive_bits.rs | 12 ++--- modules/llrt_crypto/src/subtle/digest.rs | 4 +- modules/llrt_crypto/src/subtle/encrypt.rs | 21 ++++---- modules/llrt_crypto/src/subtle/mod.rs | 50 ++++++++++--------- modules/llrt_crypto/src/subtle/sign.rs | 17 +++---- modules/llrt_crypto/src/subtle/verify.rs | 12 ++--- 7 files changed, 64 insertions(+), 66 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/decrypt.rs b/modules/llrt_crypto/src/subtle/decrypt.rs index ed99d7112..737d4ff3c 100644 --- a/modules/llrt_crypto/src/subtle/decrypt.rs +++ b/modules/llrt_crypto/src/subtle/decrypt.rs @@ -15,12 +15,12 @@ type Aes256CbcDec = cbc::Decryptor; pub fn decrypt( ctx: &Ctx<'_>, algorithm: &Algorithm, - key_value: Vec, + key: Vec, data: Vec, ) -> Result> { match algorithm { Algorithm::AesGcm(iv) => { - let cipher = Aes256Gcm::new_from_slice(&key_value).or_throw(ctx)?; + let cipher = Aes256Gcm::new_from_slice(&key).or_throw(ctx)?; let nonce = Nonce::from_slice(iv); match cipher.decrypt(nonce, data.as_ref()) { @@ -29,7 +29,7 @@ pub fn decrypt( } }, Algorithm::AesCbc(iv) => { - match Aes256CbcDec::new(key_value.as_slice().into(), iv.as_slice().into()) + match Aes256CbcDec::new(key.as_slice().into(), iv.as_slice().into()) .decrypt_padded_vec_mut::(&data) { Ok(result) => Ok(result), @@ -37,16 +37,16 @@ pub fn decrypt( } }, Algorithm::AesCtr(counter, length) => match length { - 32 => decrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), - 64 => decrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), - 128 => decrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), + 32 => decrypt_aes_ctr_gen::>(ctx, &key, counter, &data), + 64 => decrypt_aes_ctr_gen::>(ctx, &key, counter, &data), + 128 => decrypt_aes_ctr_gen::>(ctx, &key, counter, &data), _ => Err(Exception::throw_message( ctx, "invalid counter length. Currently supported 32/64/128 bits", )), }, Algorithm::RsaOaep(label) => { - let private_key = RsaPrivateKey::from_pkcs1_der(&key_value).or_throw(ctx)?; + let private_key = RsaPrivateKey::from_pkcs1_der(&key).or_throw(ctx)?; let padding = match label { Some(buf) => { Oaep::new_with_label::(String::from_utf8(buf.to_vec())?) diff --git a/modules/llrt_crypto/src/subtle/derive_bits.rs b/modules/llrt_crypto/src/subtle/derive_bits.rs index 62c536782..67ae05e73 100644 --- a/modules/llrt_crypto/src/subtle/derive_bits.rs +++ b/modules/llrt_crypto/src/subtle/derive_bits.rs @@ -20,13 +20,13 @@ impl hkdf::KeyType for HkdfOutput { pub fn derive_bits( ctx: &Ctx<'_>, algorithm: &DeriveAlgorithm, - key_value: Vec, + base_key: Vec, length: u32, ) -> Result> { match algorithm { DeriveAlgorithm::Edch { curve, public } => match curve { CryptoNamedCurve::P256 => { - let secret_key = p256::SecretKey::from_pkcs8_der(&key_value).map_err(|_| { + let secret_key = p256::SecretKey::from_pkcs8_der(&base_key).map_err(|_| { Exception::throw_message(ctx, "Unexpected error decoding private key") })?; @@ -44,7 +44,7 @@ pub fn derive_bits( Ok(shared_secret.raw_secret_bytes().to_vec()) }, CryptoNamedCurve::P384 => { - let secret_key = p384::SecretKey::from_pkcs8_der(&key_value).map_err(|_| { + let secret_key = p384::SecretKey::from_pkcs8_der(&base_key).map_err(|_| { Exception::throw_message(ctx, "Unexpected error decoding private key") })?; @@ -82,7 +82,7 @@ pub fn derive_bits( hash_algorithm, not_zero_iterations, salt, - &key_value, + &base_key, &mut out, ); @@ -104,12 +104,12 @@ pub fn derive_bits( let boxed_slice = info.clone().into_boxed_slice(); let info: &[&[u8]] = &[&*boxed_slice]; - let prk = salt.extract(&key_value); + let prk = salt.extract(&base_key); let out_length = (length / 8).try_into().or_throw(ctx)?; let okm = prk .expand(info, HkdfOutput((length / 8).try_into().or_throw(ctx)?)) - .map_err(|_e| { + .map_err(|_| { Exception::throw_message(ctx, "The length provided for HKDF is too large") })?; diff --git a/modules/llrt_crypto/src/subtle/digest.rs b/modules/llrt_crypto/src/subtle/digest.rs index dabdc339a..6d1f111e6 100644 --- a/modules/llrt_crypto/src/subtle/digest.rs +++ b/modules/llrt_crypto/src/subtle/digest.rs @@ -6,8 +6,8 @@ use sha2::{Digest, Sha256, Sha384, Sha512}; use crate::subtle::{get_sha, Sha}; -pub fn digest(ctx: &Ctx<'_>, name: &str, data: Vec) -> Result> { - let sha = get_sha(ctx, name)?; +pub fn digest(ctx: &Ctx<'_>, algorithm: &str, data: Vec) -> Result> { + let sha = get_sha(ctx, algorithm)?; match sha { Sha::Sha1 => { diff --git a/modules/llrt_crypto/src/subtle/encrypt.rs b/modules/llrt_crypto/src/subtle/encrypt.rs index 35a3098ef..7db07c903 100644 --- a/modules/llrt_crypto/src/subtle/encrypt.rs +++ b/modules/llrt_crypto/src/subtle/encrypt.rs @@ -15,12 +15,12 @@ type Aes256CbcEnc = cbc::Encryptor; pub fn encrypt( ctx: &Ctx<'_>, algorithm: &Algorithm, - key_value: Vec, + key: Vec, data: Vec, ) -> Result> { match algorithm { Algorithm::AesGcm(iv) => { - let cipher = Aes256Gcm::new_from_slice(&key_value).or_throw(ctx)?; + let cipher = Aes256Gcm::new_from_slice(&key).or_throw(ctx)?; let nonce = Nonce::from_slice(iv); match cipher.encrypt(nonce, data.as_ref()) { @@ -28,22 +28,21 @@ pub fn encrypt( Err(_) => Err(Exception::throw_message(ctx, "Encryption failed")), } }, - Algorithm::AesCbc(iv) => Ok(Aes256CbcEnc::new( - key_value.as_slice().into(), - iv.as_slice().into(), - ) - .encrypt_padded_vec_mut::(&data)), + Algorithm::AesCbc(iv) => Ok( + Aes256CbcEnc::new(key.as_slice().into(), iv.as_slice().into()) + .encrypt_padded_vec_mut::(&data), + ), Algorithm::AesCtr(counter, length) => match length { - 32 => encrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), - 64 => encrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), - 128 => encrypt_aes_ctr_gen::>(ctx, &key_value, counter, &data), + 32 => encrypt_aes_ctr_gen::>(ctx, &key, counter, &data), + 64 => encrypt_aes_ctr_gen::>(ctx, &key, counter, &data), + 128 => encrypt_aes_ctr_gen::>(ctx, &key, counter, &data), _ => Err(Exception::throw_message( ctx, "invalid counter length. Currently supported 32/64/128 bits", )), }, Algorithm::RsaOaep(label) => { - let public_key = RsaPrivateKey::from_pkcs1_der(&key_value) + let public_key = RsaPrivateKey::from_pkcs1_der(&key) .or_throw(ctx)? .to_public_key(); let mut rng = OsRng; diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index 9cdb7900a..a08986000 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -20,7 +20,7 @@ use aes::{cipher::typenum::U16, Aes256}; use aes_gcm::AesGcm; use hmac::Hmac; use llrt_utils::{bytes::get_array_bytes, object::ObjectExt}; -use rquickjs::{ArrayBuffer, Ctx, Exception, Result, Value}; +use rquickjs::{Array, ArrayBuffer, Ctx, Exception, Result, Value}; use sha2::Sha256; pub type HmacSha256 = Hmac; @@ -109,65 +109,69 @@ pub enum KeyGenAlgorithm { pub async fn subtle_decrypt<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - key_value: Value<'js>, + key: Value<'js>, data: Value<'js>, ) -> Result> { let algorithm = extract_algorithm_object(&ctx, &algorithm)?; - let key_value = get_array_bytes(&key_value, 0, None)?.unwrap_or_else(Vec::new); + let key = get_array_bytes(&key, 0, None)?.unwrap_or_else(Vec::new); let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); - let bytes = decrypt(&ctx, &algorithm, key_value, data)?; + let bytes = decrypt(&ctx, &algorithm, key, data)?; ArrayBuffer::new(ctx, bytes.as_slice()) } pub async fn subtle_derive_bits<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - key_value: Value<'js>, + base_key: Value<'js>, length: u32, ) -> Result> { let derive_algorithm = extract_derive_algorithm(&ctx, &algorithm)?; - let key_value = get_array_bytes(&key_value, 0, None)?.unwrap_or_else(Vec::new); + let base_key = get_array_bytes(&base_key, 0, None)?.unwrap_or_else(Vec::new); - let bytes = derive_bits(&ctx, &derive_algorithm, key_value, length)?; + let bytes = derive_bits(&ctx, &derive_algorithm, base_key, length)?; ArrayBuffer::new(ctx, bytes.as_slice()) } pub async fn subtle_digest<'js>( ctx: Ctx<'js>, - name: Value<'js>, + algorithm: Value<'js>, data: Value<'js>, ) -> Result> { - let name = if name.is_string() { - name.as_string().unwrap().to_string().unwrap() + let algorithm = if algorithm.is_string() { + algorithm.as_string().unwrap().to_string().unwrap() } else { - name.get_optional::<_, String>("name")?.ok_or_else(|| { - Exception::throw_message(&ctx, "Missing algorithm name should cause TypeError") - })? + algorithm + .get_optional::<_, String>("name")? + .ok_or_else(|| { + Exception::throw_message(&ctx, "Missing algorithm name should cause TypeError") + })? }; let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); - let bytes = digest(&ctx, &name, data)?; + let bytes = digest(&ctx, &algorithm, data)?; ArrayBuffer::new(ctx, bytes.as_slice()) } pub async fn subtle_encrypt<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - key_value: Value<'js>, + key: Value<'js>, data: Value<'js>, ) -> Result> { let algorithm = extract_algorithm_object(&ctx, &algorithm)?; - let key_value = get_array_bytes(&key_value, 0, None)?.unwrap_or_else(Vec::new); + let key = get_array_bytes(&key, 0, None)?.unwrap_or_else(Vec::new); let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); - let bytes = encrypt(&ctx, &algorithm, key_value, data)?; + let bytes = encrypt(&ctx, &algorithm, key, data)?; ArrayBuffer::new(ctx, bytes.as_slice()) } pub async fn subtle_generate_key<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, + _extractable: bool, + _key_usages: Array<'js>, ) -> Result> { let key_gen_algorithm = extract_generate_key_algorithm(&ctx, &algorithm)?; @@ -178,30 +182,30 @@ pub async fn subtle_generate_key<'js>( pub async fn subtle_sign<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - key_value: Value<'js>, + key: Value<'js>, data: Value<'js>, ) -> Result> { let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; - let key_value = get_array_bytes(&key_value, 0, None)?.unwrap_or_else(Vec::new); + let key = get_array_bytes(&key, 0, None)?.unwrap_or_else(Vec::new); let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); - let bytes = sign(&ctx, &algorithm, key_value, data)?; + let bytes = sign(&ctx, &algorithm, key, data)?; ArrayBuffer::new(ctx, bytes.as_slice()) } pub async fn subtle_verify<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - key_value: Value<'js>, + key: Value<'js>, signature: Value<'js>, data: Value<'js>, ) -> Result { let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; - let key_value = get_array_bytes(&key_value, 0, None)?.unwrap_or_else(Vec::new); + let key = get_array_bytes(&key, 0, None)?.unwrap_or_else(Vec::new); let signature = get_array_bytes(&signature, 0, None)?.unwrap_or_else(Vec::new); let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); - verify(&ctx, &algorithm, key_value, signature, data) + verify(&ctx, &algorithm, key, signature, data) } fn extract_algorithm_object(ctx: &Ctx<'_>, algorithm: &Value) -> Result { diff --git a/modules/llrt_crypto/src/subtle/sign.rs b/modules/llrt_crypto/src/subtle/sign.rs index 0086c4547..78654f7d2 100644 --- a/modules/llrt_crypto/src/subtle/sign.rs +++ b/modules/llrt_crypto/src/subtle/sign.rs @@ -14,21 +14,16 @@ use rsa::{Pkcs1v15Sign, RsaPrivateKey}; use crate::subtle::{Algorithm, HmacSha256, Sha}; -pub fn sign( - ctx: &Ctx<'_>, - algorithm: &Algorithm, - key_value: Vec, - data: Vec, -) -> Result> { +pub fn sign(ctx: &Ctx<'_>, algorithm: &Algorithm, key: Vec, data: Vec) -> Result> { match algorithm { Algorithm::Hmac => { - let mut mac = HmacSha256::new_from_slice(&key_value).or_throw(ctx)?; + let mut mac = HmacSha256::new_from_slice(&key).or_throw(ctx)?; mac.update(&data); Ok(mac.finalize().into_bytes().to_vec()) }, Algorithm::RsassaPkcs1v15 => { - let private_key = RsaPrivateKey::from_pkcs1_der(&key_value).or_throw(ctx)?; + let private_key = RsaPrivateKey::from_pkcs1_der(&key).or_throw(ctx)?; let mut hasher = Sha256::new(); hasher.update(&data); @@ -39,7 +34,7 @@ pub fn sign( .or_throw(ctx)?) }, Algorithm::RsaPss(salt_length) => { - let private_key = RsaPrivateKey::from_pkcs1_der(&key_value).or_throw(ctx)?; + let private_key = RsaPrivateKey::from_pkcs1_der(&key).or_throw(ctx)?; let mut rng = OsRng; let mut hasher = Sha256::new(); hasher.update(&data); @@ -58,7 +53,7 @@ pub fn sign( Sha::Sha256 => { let curve = &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING; let rng = SystemRandom::new(); - let key_pair = EcdsaKeyPair::from_pkcs8(curve, &key_value, &rng).or_throw(ctx)?; + let key_pair = EcdsaKeyPair::from_pkcs8(curve, &key, &rng).or_throw(ctx)?; let signature = key_pair.sign(&rng, &data).or_throw(ctx)?; @@ -67,7 +62,7 @@ pub fn sign( Sha::Sha384 => { let curve = &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING; let rng = SystemRandom::new(); - let key_pair = EcdsaKeyPair::from_pkcs8(curve, &key_value, &rng).or_throw(ctx)?; + let key_pair = EcdsaKeyPair::from_pkcs8(curve, &key, &rng).or_throw(ctx)?; let signature = key_pair.sign(&rng, &data).or_throw(ctx)?; diff --git a/modules/llrt_crypto/src/subtle/verify.rs b/modules/llrt_crypto/src/subtle/verify.rs index 865de6d4e..48d80a071 100644 --- a/modules/llrt_crypto/src/subtle/verify.rs +++ b/modules/llrt_crypto/src/subtle/verify.rs @@ -20,19 +20,19 @@ use crate::subtle::{Algorithm, HmacSha256, Sha}; pub fn verify( ctx: &Ctx<'_>, algorithm: &Algorithm, - key_value: Vec, + key: Vec, signature: Vec, data: Vec, ) -> Result { match algorithm { Algorithm::Hmac => { - let mut mac = HmacSha256::new_from_slice(&key_value).or_throw(ctx)?; + let mut mac = HmacSha256::new_from_slice(&key).or_throw(ctx)?; mac.update(&data); Ok(mac.verify_slice(&signature).is_ok()) }, Algorithm::RsassaPkcs1v15 => { - let public_key = RsaPrivateKey::from_pkcs1_der(&key_value) + let public_key = RsaPrivateKey::from_pkcs1_der(&key) .or_throw(ctx)? .to_public_key(); let mut hasher = Sha256::new(); @@ -45,7 +45,7 @@ pub fn verify( .is_ok()) }, Algorithm::RsaPss(salt_length) => { - let public_key = RsaPrivateKey::from_pkcs1_der(&key_value) + let public_key = RsaPrivateKey::from_pkcs1_der(&key) .or_throw(ctx)? .to_public_key(); let mut hasher = Sha256::new(); @@ -66,7 +66,7 @@ pub fn verify( let rng = SystemRandom::new(); let private_key = EcdsaKeyPair::from_pkcs8( &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING, - &key_value, + &key, &rng, ) .or_throw(ctx)?; @@ -83,7 +83,7 @@ pub fn verify( let rng = SystemRandom::new(); let private_key = EcdsaKeyPair::from_pkcs8( &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING, - &key_value, + &key, &rng, ) .or_throw(ctx)?; From 1588058672412e728fd3d0565bc6ffd3af1d6e8a Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Mon, 25 Nov 2024 20:03:39 +0900 Subject: [PATCH 06/22] Use ObjectBytes --- modules/llrt_crypto/src/subtle/decrypt.rs | 23 ++++---- modules/llrt_crypto/src/subtle/derive_bits.rs | 10 ++-- modules/llrt_crypto/src/subtle/digest.rs | 2 +- modules/llrt_crypto/src/subtle/encrypt.rs | 25 ++++----- modules/llrt_crypto/src/subtle/mod.rs | 53 +++++++++---------- modules/llrt_crypto/src/subtle/sign.rs | 22 ++++---- modules/llrt_crypto/src/subtle/verify.rs | 32 +++++------ 7 files changed, 75 insertions(+), 92 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/decrypt.rs b/modules/llrt_crypto/src/subtle/decrypt.rs index 737d4ff3c..08f5a94e7 100644 --- a/modules/llrt_crypto/src/subtle/decrypt.rs +++ b/modules/llrt_crypto/src/subtle/decrypt.rs @@ -12,15 +12,10 @@ use crate::subtle::{Aes256Gcm, Algorithm}; type Aes256CbcDec = cbc::Decryptor; -pub fn decrypt( - ctx: &Ctx<'_>, - algorithm: &Algorithm, - key: Vec, - data: Vec, -) -> Result> { +pub fn decrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Result> { match algorithm { Algorithm::AesGcm(iv) => { - let cipher = Aes256Gcm::new_from_slice(&key).or_throw(ctx)?; + let cipher = Aes256Gcm::new_from_slice(key).or_throw(ctx)?; let nonce = Nonce::from_slice(iv); match cipher.decrypt(nonce, data.as_ref()) { @@ -29,24 +24,24 @@ pub fn decrypt( } }, Algorithm::AesCbc(iv) => { - match Aes256CbcDec::new(key.as_slice().into(), iv.as_slice().into()) - .decrypt_padded_vec_mut::(&data) + match Aes256CbcDec::new(key.into(), iv.as_slice().into()) + .decrypt_padded_vec_mut::(data) { Ok(result) => Ok(result), Err(_) => Err(Exception::throw_message(ctx, "Decryption failed")), } }, Algorithm::AesCtr(counter, length) => match length { - 32 => decrypt_aes_ctr_gen::>(ctx, &key, counter, &data), - 64 => decrypt_aes_ctr_gen::>(ctx, &key, counter, &data), - 128 => decrypt_aes_ctr_gen::>(ctx, &key, counter, &data), + 32 => decrypt_aes_ctr_gen::>(ctx, key, counter, data), + 64 => decrypt_aes_ctr_gen::>(ctx, key, counter, data), + 128 => decrypt_aes_ctr_gen::>(ctx, key, counter, data), _ => Err(Exception::throw_message( ctx, "invalid counter length. Currently supported 32/64/128 bits", )), }, Algorithm::RsaOaep(label) => { - let private_key = RsaPrivateKey::from_pkcs1_der(&key).or_throw(ctx)?; + let private_key = RsaPrivateKey::from_pkcs1_der(key).or_throw(ctx)?; let padding = match label { Some(buf) => { Oaep::new_with_label::(String::from_utf8(buf.to_vec())?) @@ -55,7 +50,7 @@ pub fn decrypt( }; private_key - .decrypt(padding, &data) + .decrypt(padding, data) .map_err(|e| Exception::throw_message(ctx, e.to_string().as_str())) }, _ => Err(Exception::throw_message(ctx, "Algorithm not supported")), diff --git a/modules/llrt_crypto/src/subtle/derive_bits.rs b/modules/llrt_crypto/src/subtle/derive_bits.rs index 67ae05e73..539fcf570 100644 --- a/modules/llrt_crypto/src/subtle/derive_bits.rs +++ b/modules/llrt_crypto/src/subtle/derive_bits.rs @@ -20,13 +20,13 @@ impl hkdf::KeyType for HkdfOutput { pub fn derive_bits( ctx: &Ctx<'_>, algorithm: &DeriveAlgorithm, - base_key: Vec, + base_key: &[u8], length: u32, ) -> Result> { match algorithm { DeriveAlgorithm::Edch { curve, public } => match curve { CryptoNamedCurve::P256 => { - let secret_key = p256::SecretKey::from_pkcs8_der(&base_key).map_err(|_| { + let secret_key = p256::SecretKey::from_pkcs8_der(base_key).map_err(|_| { Exception::throw_message(ctx, "Unexpected error decoding private key") })?; @@ -44,7 +44,7 @@ pub fn derive_bits( Ok(shared_secret.raw_secret_bytes().to_vec()) }, CryptoNamedCurve::P384 => { - let secret_key = p384::SecretKey::from_pkcs8_der(&base_key).map_err(|_| { + let secret_key = p384::SecretKey::from_pkcs8_der(base_key).map_err(|_| { Exception::throw_message(ctx, "Unexpected error decoding private key") })?; @@ -82,7 +82,7 @@ pub fn derive_bits( hash_algorithm, not_zero_iterations, salt, - &base_key, + base_key, &mut out, ); @@ -104,7 +104,7 @@ pub fn derive_bits( let boxed_slice = info.clone().into_boxed_slice(); let info: &[&[u8]] = &[&*boxed_slice]; - let prk = salt.extract(&base_key); + let prk = salt.extract(base_key); let out_length = (length / 8).try_into().or_throw(ctx)?; let okm = prk diff --git a/modules/llrt_crypto/src/subtle/digest.rs b/modules/llrt_crypto/src/subtle/digest.rs index 6d1f111e6..953338329 100644 --- a/modules/llrt_crypto/src/subtle/digest.rs +++ b/modules/llrt_crypto/src/subtle/digest.rs @@ -6,7 +6,7 @@ use sha2::{Digest, Sha256, Sha384, Sha512}; use crate::subtle::{get_sha, Sha}; -pub fn digest(ctx: &Ctx<'_>, algorithm: &str, data: Vec) -> Result> { +pub fn digest(ctx: &Ctx<'_>, algorithm: &str, data: &[u8]) -> Result> { let sha = get_sha(ctx, algorithm)?; match sha { diff --git a/modules/llrt_crypto/src/subtle/encrypt.rs b/modules/llrt_crypto/src/subtle/encrypt.rs index 7db07c903..207dec3a4 100644 --- a/modules/llrt_crypto/src/subtle/encrypt.rs +++ b/modules/llrt_crypto/src/subtle/encrypt.rs @@ -12,15 +12,10 @@ use crate::subtle::{Aes256Gcm, Algorithm}; type Aes256CbcEnc = cbc::Encryptor; -pub fn encrypt( - ctx: &Ctx<'_>, - algorithm: &Algorithm, - key: Vec, - data: Vec, -) -> Result> { +pub fn encrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Result> { match algorithm { Algorithm::AesGcm(iv) => { - let cipher = Aes256Gcm::new_from_slice(&key).or_throw(ctx)?; + let cipher = Aes256Gcm::new_from_slice(key).or_throw(ctx)?; let nonce = Nonce::from_slice(iv); match cipher.encrypt(nonce, data.as_ref()) { @@ -28,21 +23,19 @@ pub fn encrypt( Err(_) => Err(Exception::throw_message(ctx, "Encryption failed")), } }, - Algorithm::AesCbc(iv) => Ok( - Aes256CbcEnc::new(key.as_slice().into(), iv.as_slice().into()) - .encrypt_padded_vec_mut::(&data), - ), + Algorithm::AesCbc(iv) => Ok(Aes256CbcEnc::new(key.into(), iv.as_slice().into()) + .encrypt_padded_vec_mut::(data)), Algorithm::AesCtr(counter, length) => match length { - 32 => encrypt_aes_ctr_gen::>(ctx, &key, counter, &data), - 64 => encrypt_aes_ctr_gen::>(ctx, &key, counter, &data), - 128 => encrypt_aes_ctr_gen::>(ctx, &key, counter, &data), + 32 => encrypt_aes_ctr_gen::>(ctx, key, counter, data), + 64 => encrypt_aes_ctr_gen::>(ctx, key, counter, data), + 128 => encrypt_aes_ctr_gen::>(ctx, key, counter, data), _ => Err(Exception::throw_message( ctx, "invalid counter length. Currently supported 32/64/128 bits", )), }, Algorithm::RsaOaep(label) => { - let public_key = RsaPrivateKey::from_pkcs1_der(&key) + let public_key = RsaPrivateKey::from_pkcs1_der(key) .or_throw(ctx)? .to_public_key(); let mut rng = OsRng; @@ -53,7 +46,7 @@ pub fn encrypt( None => Oaep::new::(), }; let encrypted = public_key - .encrypt(&mut rng, padding, &data) + .encrypt(&mut rng, padding, data) .map_err(|_| Exception::throw_message(ctx, "Encryption failed"))?; Ok(encrypted) diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index a08986000..306023457 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -19,7 +19,7 @@ use verify::verify; use aes::{cipher::typenum::U16, Aes256}; use aes_gcm::AesGcm; use hmac::Hmac; -use llrt_utils::{bytes::get_array_bytes, object::ObjectExt}; +use llrt_utils::{bytes::ObjectBytes, object::ObjectExt}; use rquickjs::{Array, ArrayBuffer, Ctx, Exception, Result, Value}; use sha2::Sha256; @@ -109,34 +109,31 @@ pub enum KeyGenAlgorithm { pub async fn subtle_decrypt<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - key: Value<'js>, - data: Value<'js>, + key: ObjectBytes<'js>, + data: ObjectBytes<'js>, ) -> Result> { let algorithm = extract_algorithm_object(&ctx, &algorithm)?; - let key = get_array_bytes(&key, 0, None)?.unwrap_or_else(Vec::new); - let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); - let bytes = decrypt(&ctx, &algorithm, key, data)?; + let bytes = decrypt(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; ArrayBuffer::new(ctx, bytes.as_slice()) } pub async fn subtle_derive_bits<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - base_key: Value<'js>, + base_key: ObjectBytes<'js>, length: u32, ) -> Result> { let derive_algorithm = extract_derive_algorithm(&ctx, &algorithm)?; - let base_key = get_array_bytes(&base_key, 0, None)?.unwrap_or_else(Vec::new); - let bytes = derive_bits(&ctx, &derive_algorithm, base_key, length)?; + let bytes = derive_bits(&ctx, &derive_algorithm, base_key.as_bytes(), length)?; ArrayBuffer::new(ctx, bytes.as_slice()) } pub async fn subtle_digest<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - data: Value<'js>, + data: ObjectBytes<'js>, ) -> Result> { let algorithm = if algorithm.is_string() { algorithm.as_string().unwrap().to_string().unwrap() @@ -147,23 +144,20 @@ pub async fn subtle_digest<'js>( Exception::throw_message(&ctx, "Missing algorithm name should cause TypeError") })? }; - let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); - let bytes = digest(&ctx, &algorithm, data)?; + let bytes = digest(&ctx, &algorithm, data.as_bytes())?; ArrayBuffer::new(ctx, bytes.as_slice()) } pub async fn subtle_encrypt<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - key: Value<'js>, - data: Value<'js>, + key: ObjectBytes<'js>, + data: ObjectBytes<'js>, ) -> Result> { let algorithm = extract_algorithm_object(&ctx, &algorithm)?; - let key = get_array_bytes(&key, 0, None)?.unwrap_or_else(Vec::new); - let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); - let bytes = encrypt(&ctx, &algorithm, key, data)?; + let bytes = encrypt(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; ArrayBuffer::new(ctx, bytes.as_slice()) } @@ -182,30 +176,31 @@ pub async fn subtle_generate_key<'js>( pub async fn subtle_sign<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - key: Value<'js>, - data: Value<'js>, + key: ObjectBytes<'js>, + data: ObjectBytes<'js>, ) -> Result> { let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; - let key = get_array_bytes(&key, 0, None)?.unwrap_or_else(Vec::new); - let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); - let bytes = sign(&ctx, &algorithm, key, data)?; + let bytes = sign(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; ArrayBuffer::new(ctx, bytes.as_slice()) } pub async fn subtle_verify<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - key: Value<'js>, - signature: Value<'js>, - data: Value<'js>, + key: ObjectBytes<'js>, + signature: ObjectBytes<'js>, + data: ObjectBytes<'js>, ) -> Result { let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; - let key = get_array_bytes(&key, 0, None)?.unwrap_or_else(Vec::new); - let signature = get_array_bytes(&signature, 0, None)?.unwrap_or_else(Vec::new); - let data = get_array_bytes(&data, 0, None)?.unwrap_or_else(Vec::new); - verify(&ctx, &algorithm, key, signature, data) + verify( + &ctx, + &algorithm, + key.as_bytes(), + signature.as_bytes(), + data.as_bytes(), + ) } fn extract_algorithm_object(ctx: &Ctx<'_>, algorithm: &Value) -> Result { diff --git a/modules/llrt_crypto/src/subtle/sign.rs b/modules/llrt_crypto/src/subtle/sign.rs index 78654f7d2..94fc1cb35 100644 --- a/modules/llrt_crypto/src/subtle/sign.rs +++ b/modules/llrt_crypto/src/subtle/sign.rs @@ -14,18 +14,18 @@ use rsa::{Pkcs1v15Sign, RsaPrivateKey}; use crate::subtle::{Algorithm, HmacSha256, Sha}; -pub fn sign(ctx: &Ctx<'_>, algorithm: &Algorithm, key: Vec, data: Vec) -> Result> { +pub fn sign(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Result> { match algorithm { Algorithm::Hmac => { - let mut mac = HmacSha256::new_from_slice(&key).or_throw(ctx)?; - mac.update(&data); + let mut mac = HmacSha256::new_from_slice(key).or_throw(ctx)?; + mac.update(data); Ok(mac.finalize().into_bytes().to_vec()) }, Algorithm::RsassaPkcs1v15 => { - let private_key = RsaPrivateKey::from_pkcs1_der(&key).or_throw(ctx)?; + let private_key = RsaPrivateKey::from_pkcs1_der(key).or_throw(ctx)?; let mut hasher = Sha256::new(); - hasher.update(&data); + hasher.update(data); let hashed = hasher.finalize()[..].to_vec(); @@ -34,10 +34,10 @@ pub fn sign(ctx: &Ctx<'_>, algorithm: &Algorithm, key: Vec, data: Vec) - .or_throw(ctx)?) }, Algorithm::RsaPss(salt_length) => { - let private_key = RsaPrivateKey::from_pkcs1_der(&key).or_throw(ctx)?; + let private_key = RsaPrivateKey::from_pkcs1_der(key).or_throw(ctx)?; let mut rng = OsRng; let mut hasher = Sha256::new(); - hasher.update(&data); + hasher.update(data); let hashed = hasher.finalize()[..].to_vec(); @@ -53,18 +53,18 @@ pub fn sign(ctx: &Ctx<'_>, algorithm: &Algorithm, key: Vec, data: Vec) - Sha::Sha256 => { let curve = &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING; let rng = SystemRandom::new(); - let key_pair = EcdsaKeyPair::from_pkcs8(curve, &key, &rng).or_throw(ctx)?; + let key_pair = EcdsaKeyPair::from_pkcs8(curve, key, &rng).or_throw(ctx)?; - let signature = key_pair.sign(&rng, &data).or_throw(ctx)?; + let signature = key_pair.sign(&rng, data).or_throw(ctx)?; Ok(signature.as_ref().to_vec()) }, Sha::Sha384 => { let curve = &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING; let rng = SystemRandom::new(); - let key_pair = EcdsaKeyPair::from_pkcs8(curve, &key, &rng).or_throw(ctx)?; + let key_pair = EcdsaKeyPair::from_pkcs8(curve, key, &rng).or_throw(ctx)?; - let signature = key_pair.sign(&rng, &data).or_throw(ctx)?; + let signature = key_pair.sign(&rng, data).or_throw(ctx)?; Ok(signature.as_ref().to_vec()) }, diff --git a/modules/llrt_crypto/src/subtle/verify.rs b/modules/llrt_crypto/src/subtle/verify.rs index 48d80a071..88d156f06 100644 --- a/modules/llrt_crypto/src/subtle/verify.rs +++ b/modules/llrt_crypto/src/subtle/verify.rs @@ -20,44 +20,44 @@ use crate::subtle::{Algorithm, HmacSha256, Sha}; pub fn verify( ctx: &Ctx<'_>, algorithm: &Algorithm, - key: Vec, - signature: Vec, - data: Vec, + key: &[u8], + signature: &[u8], + data: &[u8], ) -> Result { match algorithm { Algorithm::Hmac => { - let mut mac = HmacSha256::new_from_slice(&key).or_throw(ctx)?; - mac.update(&data); + let mut mac = HmacSha256::new_from_slice(key).or_throw(ctx)?; + mac.update(data); - Ok(mac.verify_slice(&signature).is_ok()) + Ok(mac.verify_slice(signature).is_ok()) }, Algorithm::RsassaPkcs1v15 => { - let public_key = RsaPrivateKey::from_pkcs1_der(&key) + let public_key = RsaPrivateKey::from_pkcs1_der(key) .or_throw(ctx)? .to_public_key(); let mut hasher = Sha256::new(); - hasher.update(&data); + hasher.update(data); let hashed = hasher.finalize()[..].to_vec(); Ok(public_key - .verify(Pkcs1v15Sign::new::(), &hashed, &signature) + .verify(Pkcs1v15Sign::new::(), &hashed, signature) .is_ok()) }, Algorithm::RsaPss(salt_length) => { - let public_key = RsaPrivateKey::from_pkcs1_der(&key) + let public_key = RsaPrivateKey::from_pkcs1_der(key) .or_throw(ctx)? .to_public_key(); let mut hasher = Sha256::new(); - hasher.update(&data); + hasher.update(data); let hashed = hasher.finalize()[..].to_vec(); Ok(public_key .verify( Pss::new_with_salt::(*salt_length as usize), &hashed, - &signature, + signature, ) .is_ok()) }, @@ -66,7 +66,7 @@ pub fn verify( let rng = SystemRandom::new(); let private_key = EcdsaKeyPair::from_pkcs8( &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING, - &key, + key, &rng, ) .or_throw(ctx)?; @@ -77,13 +77,13 @@ pub fn verify( &public_key_bytes, ); - Ok(public_key.verify(&data, &signature).is_ok()) + Ok(public_key.verify(data, signature).is_ok()) }, Sha::Sha384 => { let rng = SystemRandom::new(); let private_key = EcdsaKeyPair::from_pkcs8( &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING, - &key, + key, &rng, ) .or_throw(ctx)?; @@ -94,7 +94,7 @@ pub fn verify( &public_key_bytes, ); - Ok(public_key.verify(&data, &signature).is_ok()) + Ok(public_key.verify(data, signature).is_ok()) }, _ => Err(Exception::throw_message( ctx, From e34046a0d52941e44fe6f0f067d40c660f6f0bb0 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Mon, 25 Nov 2024 20:23:09 +0900 Subject: [PATCH 07/22] Refactor Error Handling --- modules/llrt_crypto/src/subtle/decrypt.rs | 24 +++++-------------- modules/llrt_crypto/src/subtle/derive_bits.rs | 20 ++++------------ modules/llrt_crypto/src/subtle/encrypt.rs | 13 +++------- .../llrt_crypto/src/subtle/generate_key.rs | 16 +++++-------- modules/llrt_crypto/src/subtle/mod.rs | 6 ++--- 5 files changed, 23 insertions(+), 56 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/decrypt.rs b/modules/llrt_crypto/src/subtle/decrypt.rs index 08f5a94e7..21743beec 100644 --- a/modules/llrt_crypto/src/subtle/decrypt.rs +++ b/modules/llrt_crypto/src/subtle/decrypt.rs @@ -18,19 +18,11 @@ pub fn decrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> let cipher = Aes256Gcm::new_from_slice(key).or_throw(ctx)?; let nonce = Nonce::from_slice(iv); - match cipher.decrypt(nonce, data.as_ref()) { - Ok(result) => Ok(result), - Err(_) => Err(Exception::throw_message(ctx, "Decryption failed"))?, - } - }, - Algorithm::AesCbc(iv) => { - match Aes256CbcDec::new(key.into(), iv.as_slice().into()) - .decrypt_padded_vec_mut::(data) - { - Ok(result) => Ok(result), - Err(_) => Err(Exception::throw_message(ctx, "Decryption failed")), - } + cipher.decrypt(nonce, data.as_ref()).or_throw(ctx) }, + Algorithm::AesCbc(iv) => Aes256CbcDec::new(key.into(), iv.as_slice().into()) + .decrypt_padded_vec_mut::(data) + .or_throw(ctx), Algorithm::AesCtr(counter, length) => match length { 32 => decrypt_aes_ctr_gen::>(ctx, key, counter, data), 64 => decrypt_aes_ctr_gen::>(ctx, key, counter, data), @@ -49,9 +41,7 @@ pub fn decrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> None => Oaep::new::(), }; - private_key - .decrypt(padding, data) - .map_err(|e| Exception::throw_message(ctx, e.to_string().as_str())) + private_key.decrypt(padding, data).or_throw(ctx) }, _ => Err(Exception::throw_message(ctx, "Algorithm not supported")), } @@ -64,9 +54,7 @@ where let mut cipher = B::new(key.into(), counter.into()); let mut plaintext = data.to_vec(); - cipher - .try_apply_keystream(&mut plaintext) - .map_err(|_| Exception::throw_message(ctx, "tried to decrypt too much data"))?; + cipher.try_apply_keystream(&mut plaintext).or_throw(ctx)?; Ok(plaintext) } diff --git a/modules/llrt_crypto/src/subtle/derive_bits.rs b/modules/llrt_crypto/src/subtle/derive_bits.rs index 539fcf570..814297e08 100644 --- a/modules/llrt_crypto/src/subtle/derive_bits.rs +++ b/modules/llrt_crypto/src/subtle/derive_bits.rs @@ -26,14 +26,10 @@ pub fn derive_bits( match algorithm { DeriveAlgorithm::Edch { curve, public } => match curve { CryptoNamedCurve::P256 => { - let secret_key = p256::SecretKey::from_pkcs8_der(base_key).map_err(|_| { - Exception::throw_message(ctx, "Unexpected error decoding private key") - })?; + let secret_key = p256::SecretKey::from_pkcs8_der(base_key).or_throw(ctx)?; let public_key = p256::SecretKey::from_pkcs8_der(public) - .map_err(|_| { - Exception::throw_message(ctx, "Unexpected error decoding public key") - })? + .or_throw(ctx)? .public_key(); let shared_secret = p256::elliptic_curve::ecdh::diffie_hellman( @@ -44,14 +40,10 @@ pub fn derive_bits( Ok(shared_secret.raw_secret_bytes().to_vec()) }, CryptoNamedCurve::P384 => { - let secret_key = p384::SecretKey::from_pkcs8_der(base_key).map_err(|_| { - Exception::throw_message(ctx, "Unexpected error decoding private key") - })?; + let secret_key = p384::SecretKey::from_pkcs8_der(base_key).or_throw(ctx)?; let public_key = p384::SecretKey::from_pkcs8_der(public) - .map_err(|_| { - Exception::throw_message(ctx, "Unexpected error decoding public key") - })? + .or_throw(ctx)? .public_key(); let shared_secret = p384::elliptic_curve::ecdh::diffie_hellman( @@ -109,9 +101,7 @@ pub fn derive_bits( let okm = prk .expand(info, HkdfOutput((length / 8).try_into().or_throw(ctx)?)) - .map_err(|_| { - Exception::throw_message(ctx, "The length provided for HKDF is too large") - })?; + .or_throw(ctx)?; let mut out = vec![0u8; out_length]; let _ = okm.fill(&mut out).or_throw(ctx); diff --git a/modules/llrt_crypto/src/subtle/encrypt.rs b/modules/llrt_crypto/src/subtle/encrypt.rs index 207dec3a4..95495fae2 100644 --- a/modules/llrt_crypto/src/subtle/encrypt.rs +++ b/modules/llrt_crypto/src/subtle/encrypt.rs @@ -18,10 +18,7 @@ pub fn encrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> let cipher = Aes256Gcm::new_from_slice(key).or_throw(ctx)?; let nonce = Nonce::from_slice(iv); - match cipher.encrypt(nonce, data.as_ref()) { - Ok(result) => Ok(result), - Err(_) => Err(Exception::throw_message(ctx, "Encryption failed")), - } + cipher.encrypt(nonce, data.as_ref()).or_throw(ctx) }, Algorithm::AesCbc(iv) => Ok(Aes256CbcEnc::new(key.into(), iv.as_slice().into()) .encrypt_padded_vec_mut::(data)), @@ -45,9 +42,7 @@ pub fn encrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> }, None => Oaep::new::(), }; - let encrypted = public_key - .encrypt(&mut rng, padding, data) - .map_err(|_| Exception::throw_message(ctx, "Encryption failed"))?; + let encrypted = public_key.encrypt(&mut rng, padding, data).or_throw(ctx)?; Ok(encrypted) }, @@ -62,9 +57,7 @@ where let mut cipher = B::new(key.into(), counter.into()); let mut ciphertext = data.to_vec(); - cipher - .try_apply_keystream(&mut ciphertext) - .map_err(|_| Exception::throw_message(ctx, "tried to encrypt too much data"))?; + cipher.try_apply_keystream(&mut ciphertext).or_throw(ctx)?; Ok(ciphertext) } diff --git a/modules/llrt_crypto/src/subtle/generate_key.rs b/modules/llrt_crypto/src/subtle/generate_key.rs index 00832b0f2..1ecb018d2 100644 --- a/modules/llrt_crypto/src/subtle/generate_key.rs +++ b/modules/llrt_crypto/src/subtle/generate_key.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use std::sync::OnceLock; +use llrt_utils::result::ResultExt; use num_traits::FromPrimitive; use ring::{ rand::{SecureRandom, SystemRandom}, @@ -34,11 +35,9 @@ pub fn generate_key(ctx: &Ctx<'_>, algorithm: &KeyGenAlgorithm) -> Result, algorithm: &KeyGenAlgorithm) -> Result &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING, }; let rng = SystemRandom::new(); - let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng) - .map_err(|_| Exception::throw_message(ctx, "Failed to generate EC key"))?; + let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng).or_throw(ctx)?; Ok(pkcs8.as_ref().to_vec()) }, @@ -62,8 +60,7 @@ pub fn generate_key(ctx: &Ctx<'_>, algorithm: &KeyGenAlgorithm) -> Result, algorithm: &KeyGenAlgorithm) -> Result( algorithm: Value<'js>, data: ObjectBytes<'js>, ) -> Result> { - let algorithm = if algorithm.is_string() { - algorithm.as_string().unwrap().to_string().unwrap() + let algorithm = if let Some(algorithm) = algorithm.as_string() { + algorithm.to_string().or_throw(&ctx)? } else { algorithm .get_optional::<_, String>("name")? From be813aaa55aef7a5af1bf37ebaf7b85e2ab0f637 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Mon, 25 Nov 2024 20:26:00 +0900 Subject: [PATCH 08/22] Fix --- modules/llrt_crypto/src/lib.rs | 2 +- modules/llrt_crypto/src/subtle/derive_bits.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/llrt_crypto/src/lib.rs b/modules/llrt_crypto/src/lib.rs index ea9a124c0..476f56666 100644 --- a/modules/llrt_crypto/src/lib.rs +++ b/modules/llrt_crypto/src/lib.rs @@ -196,8 +196,8 @@ pub fn init(ctx: &Ctx<'_>) -> Result<()> { subtle.set("digest", Func::from(Async(subtle_digest)))?; subtle.set("encrypt", Func::from(Async(subtle_encrypt)))?; subtle.set("generateKey", Func::from(Async(subtle_generate_key)))?; - subtle.set("verify", Func::from(Async(subtle_verify)))?; subtle.set("sign", Func::from(Async(subtle_sign)))?; + subtle.set("verify", Func::from(Async(subtle_verify)))?; crypto.set("subtle", subtle)?; globals.set("crypto", crypto)?; diff --git a/modules/llrt_crypto/src/subtle/derive_bits.rs b/modules/llrt_crypto/src/subtle/derive_bits.rs index 814297e08..e1eb8c62b 100644 --- a/modules/llrt_crypto/src/subtle/derive_bits.rs +++ b/modules/llrt_crypto/src/subtle/derive_bits.rs @@ -93,8 +93,7 @@ pub fn derive_bits( }; let salt = hkdf::Salt::new(hash_algorithm, salt); - let boxed_slice = info.clone().into_boxed_slice(); - let info: &[&[u8]] = &[&*boxed_slice]; + let info: &[&[u8]] = &[&info[..]]; let prk = salt.extract(base_key); let out_length = (length / 8).try_into().or_throw(ctx)?; From 5c1a0382669114165c3895505fa7523aff27cf6f Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Mon, 25 Nov 2024 20:46:49 +0900 Subject: [PATCH 09/22] Use common SYSTEM_RANDOM --- .../llrt_crypto/src/subtle/generate_key.rs | 20 ++++++++-------- modules/llrt_crypto/src/subtle/sign.rs | 23 ++++++++++++------- modules/llrt_crypto/src/subtle/verify.rs | 16 ++++++------- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/generate_key.rs b/modules/llrt_crypto/src/subtle/generate_key.rs index 1ecb018d2..0d006df32 100644 --- a/modules/llrt_crypto/src/subtle/generate_key.rs +++ b/modules/llrt_crypto/src/subtle/generate_key.rs @@ -4,15 +4,15 @@ use std::sync::OnceLock; use llrt_utils::result::ResultExt; use num_traits::FromPrimitive; -use ring::{ - rand::{SecureRandom, SystemRandom}, - signature::EcdsaKeyPair, -}; +use ring::{rand::SecureRandom, signature::EcdsaKeyPair}; use rquickjs::{Ctx, Exception, Result}; use rsa::pkcs1::EncodeRsaPrivateKey; use rsa::{rand_core::OsRng, BigUint, RsaPrivateKey}; -use crate::subtle::{CryptoNamedCurve, KeyGenAlgorithm, Sha}; +use crate::{ + subtle::{CryptoNamedCurve, KeyGenAlgorithm, Sha}, + SYSTEM_RANDOM, +}; static PUB_EXPONENT_1: OnceLock = OnceLock::new(); static PUB_EXPONENT_2: OnceLock = OnceLock::new(); @@ -46,8 +46,8 @@ pub fn generate_key(ctx: &Ctx<'_>, algorithm: &KeyGenAlgorithm) -> Result &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING, CryptoNamedCurve::P384 => &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING, }; - let rng = SystemRandom::new(); - let pkcs8 = EcdsaKeyPair::generate_pkcs8(curve, &rng).or_throw(ctx)?; + let pkcs8 = + EcdsaKeyPair::generate_pkcs8(curve, &SYSTEM_RANDOM.to_owned()).or_throw(ctx)?; Ok(pkcs8.as_ref().to_vec()) }, @@ -59,8 +59,7 @@ pub fn generate_key(ctx: &Ctx<'_>, algorithm: &KeyGenAlgorithm) -> Result, algorithm: &KeyGenAlgorithm) -> Result, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Result> { match algorithm { @@ -52,19 +55,23 @@ pub fn sign(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Re Algorithm::Ecdsa(sha) => match sha { Sha::Sha256 => { let curve = &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING; - let rng = SystemRandom::new(); - let key_pair = EcdsaKeyPair::from_pkcs8(curve, key, &rng).or_throw(ctx)?; + let key_pair = EcdsaKeyPair::from_pkcs8(curve, key, &SYSTEM_RANDOM.to_owned()) + .or_throw(ctx)?; - let signature = key_pair.sign(&rng, data).or_throw(ctx)?; + let signature = key_pair + .sign(&SYSTEM_RANDOM.to_owned(), data) + .or_throw(ctx)?; Ok(signature.as_ref().to_vec()) }, Sha::Sha384 => { let curve = &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING; - let rng = SystemRandom::new(); - let key_pair = EcdsaKeyPair::from_pkcs8(curve, key, &rng).or_throw(ctx)?; + let key_pair = EcdsaKeyPair::from_pkcs8(curve, key, &SYSTEM_RANDOM.to_owned()) + .or_throw(ctx)?; - let signature = key_pair.sign(&rng, data).or_throw(ctx)?; + let signature = key_pair + .sign(&SYSTEM_RANDOM.to_owned(), data) + .or_throw(ctx)?; Ok(signature.as_ref().to_vec()) }, diff --git a/modules/llrt_crypto/src/subtle/verify.rs b/modules/llrt_crypto/src/subtle/verify.rs index 88d156f06..d3a97750a 100644 --- a/modules/llrt_crypto/src/subtle/verify.rs +++ b/modules/llrt_crypto/src/subtle/verify.rs @@ -2,10 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use hmac::Mac; use llrt_utils::result::ResultExt; -use ring::{ - rand::SystemRandom, - signature::{EcdsaKeyPair, KeyPair}, -}; +use ring::signature::{EcdsaKeyPair, KeyPair}; use rquickjs::{Ctx, Exception, Result}; use rsa::{ pkcs1::DecodeRsaPrivateKey, @@ -15,7 +12,10 @@ use rsa::{ RsaPrivateKey, }; -use crate::subtle::{Algorithm, HmacSha256, Sha}; +use crate::{ + subtle::{Algorithm, HmacSha256, Sha}, + SYSTEM_RANDOM, +}; pub fn verify( ctx: &Ctx<'_>, @@ -63,11 +63,10 @@ pub fn verify( }, Algorithm::Ecdsa(sha) => match sha { Sha::Sha256 => { - let rng = SystemRandom::new(); let private_key = EcdsaKeyPair::from_pkcs8( &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING, key, - &rng, + &SYSTEM_RANDOM.to_owned(), ) .or_throw(ctx)?; @@ -80,11 +79,10 @@ pub fn verify( Ok(public_key.verify(data, signature).is_ok()) }, Sha::Sha384 => { - let rng = SystemRandom::new(); let private_key = EcdsaKeyPair::from_pkcs8( &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING, key, - &rng, + &SYSTEM_RANDOM.to_owned(), ) .or_throw(ctx)?; From 4187f5a43911bfc4cd5b2f63104103ac415782fc Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Mon, 25 Nov 2024 21:52:05 +0900 Subject: [PATCH 10/22] Refactor --- modules/llrt_crypto/src/subtle/decrypt.rs | 9 +++------ modules/llrt_crypto/src/subtle/encrypt.rs | 14 +++++--------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/decrypt.rs b/modules/llrt_crypto/src/subtle/decrypt.rs index 21743beec..bd751dfdb 100644 --- a/modules/llrt_crypto/src/subtle/decrypt.rs +++ b/modules/llrt_crypto/src/subtle/decrypt.rs @@ -34,12 +34,9 @@ pub fn decrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> }, Algorithm::RsaOaep(label) => { let private_key = RsaPrivateKey::from_pkcs1_der(key).or_throw(ctx)?; - let padding = match label { - Some(buf) => { - Oaep::new_with_label::(String::from_utf8(buf.to_vec())?) - }, - None => Oaep::new::(), - }; + let padding = label.as_ref().map_or(Oaep::new::(), |buf| { + Oaep::new_with_label::(&String::from_utf8_lossy(buf)) + }); private_key.decrypt(padding, data).or_throw(ctx) }, diff --git a/modules/llrt_crypto/src/subtle/encrypt.rs b/modules/llrt_crypto/src/subtle/encrypt.rs index 95495fae2..be61603b2 100644 --- a/modules/llrt_crypto/src/subtle/encrypt.rs +++ b/modules/llrt_crypto/src/subtle/encrypt.rs @@ -35,16 +35,12 @@ pub fn encrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> let public_key = RsaPrivateKey::from_pkcs1_der(key) .or_throw(ctx)? .to_public_key(); + let padding = label.as_ref().map_or(Oaep::new::(), |buf| { + Oaep::new_with_label::(&String::from_utf8_lossy(buf)) + }); let mut rng = OsRng; - let padding = match label { - Some(buf) => { - Oaep::new_with_label::(String::from_utf8(buf.to_vec())?) - }, - None => Oaep::new::(), - }; - let encrypted = public_key.encrypt(&mut rng, padding, data).or_throw(ctx)?; - - Ok(encrypted) + + Ok(public_key.encrypt(&mut rng, padding, data).or_throw(ctx)?) }, _ => Err(Exception::throw_message(ctx, "Algorithm not supported")), } From 095d5ac39965575ffbdfba68e268af558b6d9fdd Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Mon, 25 Nov 2024 22:36:54 +0900 Subject: [PATCH 11/22] Remove unnecessary to_vec() --- modules/llrt_crypto/src/subtle/verify.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/verify.rs b/modules/llrt_crypto/src/subtle/verify.rs index d3a97750a..b268432d3 100644 --- a/modules/llrt_crypto/src/subtle/verify.rs +++ b/modules/llrt_crypto/src/subtle/verify.rs @@ -38,7 +38,7 @@ pub fn verify( let mut hasher = Sha256::new(); hasher.update(data); - let hashed = hasher.finalize()[..].to_vec(); + let hashed = hasher.finalize(); Ok(public_key .verify(Pkcs1v15Sign::new::(), &hashed, signature) @@ -51,7 +51,7 @@ pub fn verify( let mut hasher = Sha256::new(); hasher.update(data); - let hashed = hasher.finalize()[..].to_vec(); + let hashed = hasher.finalize(); Ok(public_key .verify( From 2a9a2aba53fcf26fade4a5a71c2f8269095922f3 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Mon, 25 Nov 2024 22:51:47 +0900 Subject: [PATCH 12/22] Remove more unnecessary to_vec() --- modules/llrt_crypto/src/subtle/sign.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/sign.rs b/modules/llrt_crypto/src/subtle/sign.rs index 3b689fd0a..62d7cb282 100644 --- a/modules/llrt_crypto/src/subtle/sign.rs +++ b/modules/llrt_crypto/src/subtle/sign.rs @@ -30,7 +30,7 @@ pub fn sign(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Re let mut hasher = Sha256::new(); hasher.update(data); - let hashed = hasher.finalize()[..].to_vec(); + let hashed = hasher.finalize(); Ok(private_key .sign(Pkcs1v15Sign::new::(), &hashed) @@ -42,7 +42,7 @@ pub fn sign(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Re let mut hasher = Sha256::new(); hasher.update(data); - let hashed = hasher.finalize()[..].to_vec(); + let hashed = hasher.finalize(); Ok(private_key .sign_with_rng( From 51af5dbeb28f1a652dce69abaf7c755e1790d892 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Mon, 25 Nov 2024 23:19:47 +0900 Subject: [PATCH 13/22] Optimize ArrayBuffer arguments --- modules/llrt_crypto/src/subtle/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index c72a59da4..59c965005 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -115,7 +115,7 @@ pub async fn subtle_decrypt<'js>( let algorithm = extract_algorithm_object(&ctx, &algorithm)?; let bytes = decrypt(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; - ArrayBuffer::new(ctx, bytes.as_slice()) + ArrayBuffer::new(ctx, bytes) } pub async fn subtle_derive_bits<'js>( @@ -127,7 +127,7 @@ pub async fn subtle_derive_bits<'js>( let derive_algorithm = extract_derive_algorithm(&ctx, &algorithm)?; let bytes = derive_bits(&ctx, &derive_algorithm, base_key.as_bytes(), length)?; - ArrayBuffer::new(ctx, bytes.as_slice()) + ArrayBuffer::new(ctx, bytes) } pub async fn subtle_digest<'js>( @@ -146,7 +146,7 @@ pub async fn subtle_digest<'js>( }; let bytes = digest(&ctx, &algorithm, data.as_bytes())?; - ArrayBuffer::new(ctx, bytes.as_slice()) + ArrayBuffer::new(ctx, bytes) } pub async fn subtle_encrypt<'js>( @@ -158,7 +158,7 @@ pub async fn subtle_encrypt<'js>( let algorithm = extract_algorithm_object(&ctx, &algorithm)?; let bytes = encrypt(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; - ArrayBuffer::new(ctx, bytes.as_slice()) + ArrayBuffer::new(ctx, bytes) } pub async fn subtle_generate_key<'js>( @@ -170,7 +170,7 @@ pub async fn subtle_generate_key<'js>( let key_gen_algorithm = extract_generate_key_algorithm(&ctx, &algorithm)?; let bytes = generate_key(&ctx, &key_gen_algorithm)?; - ArrayBuffer::new(ctx, bytes.as_slice()) + ArrayBuffer::new(ctx, bytes) } pub async fn subtle_sign<'js>( @@ -182,7 +182,7 @@ pub async fn subtle_sign<'js>( let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; let bytes = sign(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; - ArrayBuffer::new(ctx, bytes.as_slice()) + ArrayBuffer::new(ctx, bytes) } pub async fn subtle_verify<'js>( From 87e2c0e6bbc4dbad02676ab899baa842c80f1e4a Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Tue, 26 Nov 2024 20:05:27 +0900 Subject: [PATCH 14/22] chore --- modules/llrt_crypto/src/subtle/decrypt.rs | 6 +++--- modules/llrt_crypto/src/subtle/encrypt.rs | 6 +++--- modules/llrt_crypto/src/subtle/mod.rs | 20 ++++++++++++++++---- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/decrypt.rs b/modules/llrt_crypto/src/subtle/decrypt.rs index bd751dfdb..bc9b2720b 100644 --- a/modules/llrt_crypto/src/subtle/decrypt.rs +++ b/modules/llrt_crypto/src/subtle/decrypt.rs @@ -44,11 +44,11 @@ pub fn decrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> } } -fn decrypt_aes_ctr_gen(ctx: &Ctx<'_>, key: &[u8], counter: &[u8], data: &[u8]) -> Result> +fn decrypt_aes_ctr_gen(ctx: &Ctx<'_>, key: &[u8], counter: &[u8], data: &[u8]) -> Result> where - B: KeyIvInit + StreamCipher, + T: KeyIvInit + StreamCipher, { - let mut cipher = B::new(key.into(), counter.into()); + let mut cipher = T::new(key.into(), counter.into()); let mut plaintext = data.to_vec(); cipher.try_apply_keystream(&mut plaintext).or_throw(ctx)?; diff --git a/modules/llrt_crypto/src/subtle/encrypt.rs b/modules/llrt_crypto/src/subtle/encrypt.rs index be61603b2..2aaeb8bea 100644 --- a/modules/llrt_crypto/src/subtle/encrypt.rs +++ b/modules/llrt_crypto/src/subtle/encrypt.rs @@ -46,11 +46,11 @@ pub fn encrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> } } -fn encrypt_aes_ctr_gen(ctx: &Ctx<'_>, key: &[u8], counter: &[u8], data: &[u8]) -> Result> +fn encrypt_aes_ctr_gen(ctx: &Ctx<'_>, key: &[u8], counter: &[u8], data: &[u8]) -> Result> where - B: KeyIvInit + StreamCipher, + T: KeyIvInit + StreamCipher, { - let mut cipher = B::new(key.into(), counter.into()); + let mut cipher = T::new(key.into(), counter.into()); let mut ciphertext = data.to_vec(); cipher.try_apply_keystream(&mut ciphertext).or_throw(ctx)?; diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index 59c965005..9441f7d1e 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -240,7 +240,10 @@ fn extract_algorithm_object(ctx: &Ctx<'_>, algorithm: &Value) -> Result Err(Exception::throw_message(ctx, "Algorithm not supported")), + _ => Err(Exception::throw_message( + ctx, + "Algorithm name must be HMAC | AES-GCM | AES-CBC | AES-CTR | RSA-OAEP", + )), } } @@ -282,7 +285,10 @@ fn extract_sign_verify_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result Err(Exception::throw_message(ctx, "Algorithm not supported")), + _ => Err(Exception::throw_message( + ctx, + "Algorithm name must be RSASSA-PKCS1-v1_5 | HMAC | RSA-PSS | ECDSA", + )), } } @@ -345,7 +351,10 @@ fn extract_derive_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result Err(Exception::throw_message(ctx, "Algorithm not supported")), + _ => Err(Exception::throw_message( + ctx, + "Algorithm name must be ECDH | HKDF | PBKDF2", + )), } } @@ -399,6 +408,9 @@ fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result Err(Exception::throw_message(ctx,"Algorithm must be RsaHashedKeyGenParams | EcKeyGenParams | HmacKeyGenParams | AesKeyGenParams")) + _ => Err(Exception::throw_message( + ctx, + "Algorithm must be RsaHashedKeyGenParams | EcKeyGenParams | HmacKeyGenParams | AesKeyGenParams", + )), } } From ae81bbc85ec27d7a58ad93e7a364df57d302df7b Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Tue, 26 Nov 2024 20:30:00 +0900 Subject: [PATCH 15/22] Implement try_into() for enums --- modules/llrt_crypto/src/subtle/digest.rs | 5 +- modules/llrt_crypto/src/subtle/mod.rs | 60 ++++++++++++++---------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/digest.rs b/modules/llrt_crypto/src/subtle/digest.rs index 953338329..b14609bc4 100644 --- a/modules/llrt_crypto/src/subtle/digest.rs +++ b/modules/llrt_crypto/src/subtle/digest.rs @@ -1,13 +1,14 @@ +use llrt_utils::result::ResultExt; // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 use rquickjs::{Ctx, Result}; use sha1::Sha1; use sha2::{Digest, Sha256, Sha384, Sha512}; -use crate::subtle::{get_sha, Sha}; +use crate::subtle::Sha; pub fn digest(ctx: &Ctx<'_>, algorithm: &str, data: &[u8]) -> Result> { - let sha = get_sha(ctx, algorithm)?; + let sha = Sha::try_from(algorithm).or_throw(ctx)?; match sha { Sha::Sha1 => { diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index 9441f7d1e..6446f2aad 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -34,13 +34,35 @@ pub enum Sha { Sha512, } -fn get_sha(ctx: &Ctx<'_>, hash: &str) -> Result { - match hash.to_ascii_uppercase().as_str() { - "SHA-1" => Ok(Sha::Sha1), - "SHA-256" => Ok(Sha::Sha256), - "SHA-384" => Ok(Sha::Sha384), - "SHA-512" => Ok(Sha::Sha512), - _ => Err(Exception::throw_message(ctx, "hash not found")), +impl TryFrom<&str> for Sha { + type Error = &'static str; + + fn try_from(hash: &str) -> std::result::Result { + match hash.to_ascii_uppercase().as_str() { + "SHA-1" => Ok(Sha::Sha1), + "SHA-256" => Ok(Sha::Sha256), + "SHA-384" => Ok(Sha::Sha384), + "SHA-512" => Ok(Sha::Sha512), + _ => Err("hash not found"), + } + } +} + +#[derive(Debug)] +pub enum CryptoNamedCurve { + P256, + P384, +} + +impl TryFrom<&str> for CryptoNamedCurve { + type Error = &'static str; + + fn try_from(curve: &str) -> std::result::Result { + match curve.to_ascii_uppercase().as_str() { + "P256" => Ok(CryptoNamedCurve::P256), + "P384" => Ok(CryptoNamedCurve::P384), + _ => Err("named_curve not found"), + } } } @@ -56,20 +78,6 @@ pub enum Algorithm { RsaOaep(Option>), } -#[derive(Debug)] -pub enum CryptoNamedCurve { - P256, - P384, -} - -fn get_named_curve(ctx: &Ctx<'_>, curve: &str) -> Result { - match curve.to_ascii_uppercase().as_str() { - "P-256" => Ok(CryptoNamedCurve::P256), - "P-384" => Ok(CryptoNamedCurve::P384), - _ => Err(Exception::throw_message(ctx, "named_curve not found")), - } -} - #[derive(Debug)] pub enum DeriveAlgorithm { Edch { @@ -252,7 +260,7 @@ fn extract_sha_hash(ctx: &Ctx<'_>, algorithm: &Value) -> Result { .get_optional::<_, String>("hash")? .ok_or_else(|| Exception::throw_message(ctx, "hash not found"))?; - get_sha(ctx, &hash) + Sha::try_from(hash.as_str()).or_throw(ctx) } fn extract_sign_verify_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { @@ -305,7 +313,7 @@ fn extract_derive_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result, algorithm: &Value) -> Result("hash")? .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have hash"))?; - let hash = get_sha(ctx, &hash)?; + let hash = Sha::try_from(hash.as_str()).or_throw(ctx)?; let salt = algorithm .get_optional("salt")? @@ -335,7 +343,7 @@ fn extract_derive_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result("hash")? .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have hash"))?; - let hash = get_sha(ctx, &hash)?; + let hash = Sha::try_from(hash.as_str()).or_throw(ctx)?; let salt = algorithm .get_optional("salt")? @@ -383,7 +391,7 @@ fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result("namedCurve")? .ok_or_else(|| Exception::throw_message(ctx, "Algorithm namedCurve not found"))?; - let curve = get_named_curve(ctx, &namedcurve)?; + let curve = CryptoNamedCurve::try_from(namedcurve.as_str()).or_throw(ctx)?; Ok(KeyGenAlgorithm::Ec { curve }) }, From e9962844b60e5e0badb71c5d01102eb02ea999af Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Tue, 26 Nov 2024 21:57:36 +0900 Subject: [PATCH 16/22] Refactor the structure --- modules/llrt_crypto/src/lib.rs | 3 +- modules/llrt_crypto/src/subtle/decrypt.rs | 20 ++- modules/llrt_crypto/src/subtle/derive_bits.rs | 20 ++- modules/llrt_crypto/src/subtle/digest.rs | 25 +++- modules/llrt_crypto/src/subtle/encrypt.rs | 20 ++- .../llrt_crypto/src/subtle/generate_key.rs | 18 ++- modules/llrt_crypto/src/subtle/mod.rs | 115 ++---------------- modules/llrt_crypto/src/subtle/sign.rs | 20 ++- modules/llrt_crypto/src/subtle/verify.rs | 26 +++- 9 files changed, 134 insertions(+), 133 deletions(-) diff --git a/modules/llrt_crypto/src/lib.rs b/modules/llrt_crypto/src/lib.rs index 476f56666..d8d7bc481 100644 --- a/modules/llrt_crypto/src/lib.rs +++ b/modules/llrt_crypto/src/lib.rs @@ -3,9 +3,10 @@ mod crc32; mod md5_hash; mod sha_hash; -use std::slice; mod subtle; +use std::slice; + use llrt_buffer::Buffer; use llrt_context::CtxExtension; use llrt_encoding::{bytes_to_b64_string, bytes_to_hex_string}; diff --git a/modules/llrt_crypto/src/subtle/decrypt.rs b/modules/llrt_crypto/src/subtle/decrypt.rs index bc9b2720b..0caecfe5f 100644 --- a/modules/llrt_crypto/src/subtle/decrypt.rs +++ b/modules/llrt_crypto/src/subtle/decrypt.rs @@ -3,16 +3,28 @@ use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, KeyIvInit}; use aes_gcm::{aead::Aead, KeyInit, Nonce}; use ctr::{cipher::StreamCipher, Ctr128BE, Ctr32BE, Ctr64BE}; -use llrt_utils::result::ResultExt; -use rquickjs::{Ctx, Exception, Result}; +use llrt_utils::{bytes::ObjectBytes, result::ResultExt}; +use rquickjs::{ArrayBuffer, Ctx, Exception, Result, Value}; use rsa::{pkcs1::DecodeRsaPrivateKey, Oaep, RsaPrivateKey}; use sha2::Sha256; -use crate::subtle::{Aes256Gcm, Algorithm}; +use crate::subtle::{extract_algorithm_object, Aes256Gcm, Algorithm}; type Aes256CbcDec = cbc::Decryptor; -pub fn decrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Result> { +pub async fn subtle_decrypt<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + key: ObjectBytes<'js>, + data: ObjectBytes<'js>, +) -> Result> { + let algorithm = extract_algorithm_object(&ctx, &algorithm)?; + + let bytes = decrypt(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; + ArrayBuffer::new(ctx, bytes) +} + +fn decrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Result> { match algorithm { Algorithm::AesGcm(iv) => { let cipher = Aes256Gcm::new_from_slice(key).or_throw(ctx)?; diff --git a/modules/llrt_crypto/src/subtle/derive_bits.rs b/modules/llrt_crypto/src/subtle/derive_bits.rs index e1eb8c62b..95abf44ff 100644 --- a/modules/llrt_crypto/src/subtle/derive_bits.rs +++ b/modules/llrt_crypto/src/subtle/derive_bits.rs @@ -2,12 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use std::num::NonZeroU32; -use llrt_utils::result::ResultExt; +use llrt_utils::{bytes::ObjectBytes, result::ResultExt}; use p256::pkcs8::DecodePrivateKey; use ring::{hkdf, pbkdf2}; -use rquickjs::{Ctx, Exception, Result}; +use rquickjs::{ArrayBuffer, Ctx, Exception, Result, Value}; -use crate::subtle::{CryptoNamedCurve, DeriveAlgorithm, Sha}; +use crate::subtle::{extract_derive_algorithm, CryptoNamedCurve, DeriveAlgorithm, Sha}; struct HkdfOutput(usize); @@ -17,7 +17,19 @@ impl hkdf::KeyType for HkdfOutput { } } -pub fn derive_bits( +pub async fn subtle_derive_bits<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + base_key: ObjectBytes<'js>, + length: u32, +) -> Result> { + let derive_algorithm = extract_derive_algorithm(&ctx, &algorithm)?; + + let bytes = derive_bits(&ctx, &derive_algorithm, base_key.as_bytes(), length)?; + ArrayBuffer::new(ctx, bytes) +} + +fn derive_bits( ctx: &Ctx<'_>, algorithm: &DeriveAlgorithm, base_key: &[u8], diff --git a/modules/llrt_crypto/src/subtle/digest.rs b/modules/llrt_crypto/src/subtle/digest.rs index b14609bc4..069ae25e3 100644 --- a/modules/llrt_crypto/src/subtle/digest.rs +++ b/modules/llrt_crypto/src/subtle/digest.rs @@ -1,13 +1,32 @@ -use llrt_utils::result::ResultExt; // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -use rquickjs::{Ctx, Result}; +use llrt_utils::{bytes::ObjectBytes, object::ObjectExt, result::ResultExt}; +use rquickjs::{ArrayBuffer, Ctx, Exception, Result, Value}; use sha1::Sha1; use sha2::{Digest, Sha256, Sha384, Sha512}; use crate::subtle::Sha; -pub fn digest(ctx: &Ctx<'_>, algorithm: &str, data: &[u8]) -> Result> { +pub async fn subtle_digest<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + data: ObjectBytes<'js>, +) -> Result> { + let algorithm = if let Some(algorithm) = algorithm.as_string() { + algorithm.to_string().or_throw(&ctx)? + } else { + algorithm + .get_optional::<_, String>("name")? + .ok_or_else(|| { + Exception::throw_message(&ctx, "Missing algorithm name should cause TypeError") + })? + }; + + let bytes = digest(&ctx, &algorithm, data.as_bytes())?; + ArrayBuffer::new(ctx, bytes) +} + +fn digest(ctx: &Ctx<'_>, algorithm: &str, data: &[u8]) -> Result> { let sha = Sha::try_from(algorithm).or_throw(ctx)?; match sha { diff --git a/modules/llrt_crypto/src/subtle/encrypt.rs b/modules/llrt_crypto/src/subtle/encrypt.rs index 2aaeb8bea..14155408d 100644 --- a/modules/llrt_crypto/src/subtle/encrypt.rs +++ b/modules/llrt_crypto/src/subtle/encrypt.rs @@ -3,16 +3,28 @@ use aes::cipher::{block_padding::Pkcs7, BlockEncryptMut, KeyIvInit}; use aes_gcm::{aead::Aead, KeyInit, Nonce}; use ctr::{cipher::StreamCipher, Ctr128BE, Ctr32BE, Ctr64BE}; -use llrt_utils::result::ResultExt; -use rquickjs::{Ctx, Exception, Result}; +use llrt_utils::{bytes::ObjectBytes, result::ResultExt}; +use rquickjs::{ArrayBuffer, Ctx, Exception, Result, Value}; use rsa::{pkcs1::DecodeRsaPrivateKey, rand_core::OsRng, Oaep, RsaPrivateKey}; use sha2::Sha256; -use crate::subtle::{Aes256Gcm, Algorithm}; +use crate::subtle::{extract_algorithm_object, Aes256Gcm, Algorithm}; type Aes256CbcEnc = cbc::Encryptor; -pub fn encrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Result> { +pub async fn subtle_encrypt<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + key: ObjectBytes<'js>, + data: ObjectBytes<'js>, +) -> Result> { + let algorithm = extract_algorithm_object(&ctx, &algorithm)?; + + let bytes = encrypt(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; + ArrayBuffer::new(ctx, bytes) +} + +fn encrypt(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Result> { match algorithm { Algorithm::AesGcm(iv) => { let cipher = Aes256Gcm::new_from_slice(key).or_throw(ctx)?; diff --git a/modules/llrt_crypto/src/subtle/generate_key.rs b/modules/llrt_crypto/src/subtle/generate_key.rs index 0d006df32..d75333638 100644 --- a/modules/llrt_crypto/src/subtle/generate_key.rs +++ b/modules/llrt_crypto/src/subtle/generate_key.rs @@ -5,19 +5,31 @@ use std::sync::OnceLock; use llrt_utils::result::ResultExt; use num_traits::FromPrimitive; use ring::{rand::SecureRandom, signature::EcdsaKeyPair}; -use rquickjs::{Ctx, Exception, Result}; +use rquickjs::{Array, ArrayBuffer, Ctx, Exception, Result, Value}; use rsa::pkcs1::EncodeRsaPrivateKey; use rsa::{rand_core::OsRng, BigUint, RsaPrivateKey}; use crate::{ - subtle::{CryptoNamedCurve, KeyGenAlgorithm, Sha}, + subtle::{extract_generate_key_algorithm, CryptoNamedCurve, KeyGenAlgorithm, Sha}, SYSTEM_RANDOM, }; static PUB_EXPONENT_1: OnceLock = OnceLock::new(); static PUB_EXPONENT_2: OnceLock = OnceLock::new(); -pub fn generate_key(ctx: &Ctx<'_>, algorithm: &KeyGenAlgorithm) -> Result> { +pub async fn subtle_generate_key<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + _extractable: bool, + _key_usages: Array<'js>, +) -> Result> { + let key_gen_algorithm = extract_generate_key_algorithm(&ctx, &algorithm)?; + + let bytes = generate_key(&ctx, &key_gen_algorithm)?; + ArrayBuffer::new(ctx, bytes) +} + +fn generate_key(ctx: &Ctx<'_>, algorithm: &KeyGenAlgorithm) -> Result> { match algorithm { KeyGenAlgorithm::Rsa { modulus_length, diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index 6446f2aad..2f7fb714a 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -8,19 +8,19 @@ mod generate_key; mod sign; mod verify; -use decrypt::decrypt; -use derive_bits::derive_bits; -use digest::digest; -use encrypt::encrypt; -use generate_key::generate_key; -use sign::sign; -use verify::verify; +pub use decrypt::subtle_decrypt; +pub use derive_bits::subtle_derive_bits; +pub use digest::subtle_digest; +pub use encrypt::subtle_encrypt; +pub use generate_key::subtle_generate_key; +pub use sign::subtle_sign; +pub use verify::subtle_verify; use aes::{cipher::typenum::U16, Aes256}; use aes_gcm::AesGcm; use hmac::Hmac; -use llrt_utils::{bytes::ObjectBytes, object::ObjectExt, result::ResultExt}; -use rquickjs::{Array, ArrayBuffer, Ctx, Exception, Result, Value}; +use llrt_utils::{object::ObjectExt, result::ResultExt}; +use rquickjs::{Ctx, Exception, Result, Value}; use sha2::Sha256; pub type HmacSha256 = Hmac; @@ -114,103 +114,6 @@ pub enum KeyGenAlgorithm { }, } -pub async fn subtle_decrypt<'js>( - ctx: Ctx<'js>, - algorithm: Value<'js>, - key: ObjectBytes<'js>, - data: ObjectBytes<'js>, -) -> Result> { - let algorithm = extract_algorithm_object(&ctx, &algorithm)?; - - let bytes = decrypt(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; - ArrayBuffer::new(ctx, bytes) -} - -pub async fn subtle_derive_bits<'js>( - ctx: Ctx<'js>, - algorithm: Value<'js>, - base_key: ObjectBytes<'js>, - length: u32, -) -> Result> { - let derive_algorithm = extract_derive_algorithm(&ctx, &algorithm)?; - - let bytes = derive_bits(&ctx, &derive_algorithm, base_key.as_bytes(), length)?; - ArrayBuffer::new(ctx, bytes) -} - -pub async fn subtle_digest<'js>( - ctx: Ctx<'js>, - algorithm: Value<'js>, - data: ObjectBytes<'js>, -) -> Result> { - let algorithm = if let Some(algorithm) = algorithm.as_string() { - algorithm.to_string().or_throw(&ctx)? - } else { - algorithm - .get_optional::<_, String>("name")? - .ok_or_else(|| { - Exception::throw_message(&ctx, "Missing algorithm name should cause TypeError") - })? - }; - - let bytes = digest(&ctx, &algorithm, data.as_bytes())?; - ArrayBuffer::new(ctx, bytes) -} - -pub async fn subtle_encrypt<'js>( - ctx: Ctx<'js>, - algorithm: Value<'js>, - key: ObjectBytes<'js>, - data: ObjectBytes<'js>, -) -> Result> { - let algorithm = extract_algorithm_object(&ctx, &algorithm)?; - - let bytes = encrypt(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; - ArrayBuffer::new(ctx, bytes) -} - -pub async fn subtle_generate_key<'js>( - ctx: Ctx<'js>, - algorithm: Value<'js>, - _extractable: bool, - _key_usages: Array<'js>, -) -> Result> { - let key_gen_algorithm = extract_generate_key_algorithm(&ctx, &algorithm)?; - - let bytes = generate_key(&ctx, &key_gen_algorithm)?; - ArrayBuffer::new(ctx, bytes) -} - -pub async fn subtle_sign<'js>( - ctx: Ctx<'js>, - algorithm: Value<'js>, - key: ObjectBytes<'js>, - data: ObjectBytes<'js>, -) -> Result> { - let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; - - let bytes = sign(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; - ArrayBuffer::new(ctx, bytes) -} - -pub async fn subtle_verify<'js>( - ctx: Ctx<'js>, - algorithm: Value<'js>, - key: ObjectBytes<'js>, - signature: ObjectBytes<'js>, - data: ObjectBytes<'js>, -) -> Result { - let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; - - verify( - &ctx, - &algorithm, - key.as_bytes(), - signature.as_bytes(), - data.as_bytes(), - ) -} - fn extract_algorithm_object(ctx: &Ctx<'_>, algorithm: &Value) -> Result { let name = algorithm .get_optional::<_, String>("name")? diff --git a/modules/llrt_crypto/src/subtle/sign.rs b/modules/llrt_crypto/src/subtle/sign.rs index 62d7cb282..60d120562 100644 --- a/modules/llrt_crypto/src/subtle/sign.rs +++ b/modules/llrt_crypto/src/subtle/sign.rs @@ -1,10 +1,10 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 use hmac::Mac; -use llrt_utils::result::ResultExt; +use llrt_utils::{bytes::ObjectBytes, result::ResultExt}; use rand::rngs::OsRng; use ring::signature::EcdsaKeyPair; -use rquickjs::{Ctx, Exception, Result}; +use rquickjs::{ArrayBuffer, Ctx, Exception, Result, Value}; use rsa::{ pkcs1::DecodeRsaPrivateKey, pss::Pss, @@ -13,11 +13,23 @@ use rsa::{ use rsa::{Pkcs1v15Sign, RsaPrivateKey}; use crate::{ - subtle::{Algorithm, HmacSha256, Sha}, + subtle::{extract_sign_verify_algorithm, Algorithm, HmacSha256, Sha}, SYSTEM_RANDOM, }; -pub fn sign(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Result> { +pub async fn subtle_sign<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + key: ObjectBytes<'js>, + data: ObjectBytes<'js>, +) -> Result> { + let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; + + let bytes = sign(&ctx, &algorithm, key.as_bytes(), data.as_bytes())?; + ArrayBuffer::new(ctx, bytes) +} + +fn sign(ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], data: &[u8]) -> Result> { match algorithm { Algorithm::Hmac => { let mut mac = HmacSha256::new_from_slice(key).or_throw(ctx)?; diff --git a/modules/llrt_crypto/src/subtle/verify.rs b/modules/llrt_crypto/src/subtle/verify.rs index b268432d3..e589d71d2 100644 --- a/modules/llrt_crypto/src/subtle/verify.rs +++ b/modules/llrt_crypto/src/subtle/verify.rs @@ -1,9 +1,9 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 use hmac::Mac; -use llrt_utils::result::ResultExt; +use llrt_utils::{bytes::ObjectBytes, result::ResultExt}; use ring::signature::{EcdsaKeyPair, KeyPair}; -use rquickjs::{Ctx, Exception, Result}; +use rquickjs::{Ctx, Exception, Result, Value}; use rsa::{ pkcs1::DecodeRsaPrivateKey, pkcs1v15::Pkcs1v15Sign, @@ -13,11 +13,29 @@ use rsa::{ }; use crate::{ - subtle::{Algorithm, HmacSha256, Sha}, + subtle::{extract_sign_verify_algorithm, Algorithm, HmacSha256, Sha}, SYSTEM_RANDOM, }; -pub fn verify( +pub async fn subtle_verify<'js>( + ctx: Ctx<'js>, + algorithm: Value<'js>, + key: ObjectBytes<'js>, + signature: ObjectBytes<'js>, + data: ObjectBytes<'js>, +) -> Result { + let algorithm = extract_sign_verify_algorithm(&ctx, &algorithm)?; + + verify( + &ctx, + &algorithm, + key.as_bytes(), + signature.as_bytes(), + data.as_bytes(), + ) +} + +fn verify( ctx: &Ctx<'_>, algorithm: &Algorithm, key: &[u8], From 9a12840d745d9d48fd134a56c806502649919916 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Tue, 26 Nov 2024 22:04:34 +0900 Subject: [PATCH 17/22] Fix error messages --- modules/llrt_crypto/src/subtle/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index 2f7fb714a..a8dc24e10 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -35,7 +35,7 @@ pub enum Sha { } impl TryFrom<&str> for Sha { - type Error = &'static str; + type Error = String; fn try_from(hash: &str) -> std::result::Result { match hash.to_ascii_uppercase().as_str() { @@ -43,7 +43,7 @@ impl TryFrom<&str> for Sha { "SHA-256" => Ok(Sha::Sha256), "SHA-384" => Ok(Sha::Sha384), "SHA-512" => Ok(Sha::Sha512), - _ => Err("hash not found"), + _ => Err(["'", hash, "' not available"].concat()), } } } @@ -55,13 +55,13 @@ pub enum CryptoNamedCurve { } impl TryFrom<&str> for CryptoNamedCurve { - type Error = &'static str; + type Error = String; fn try_from(curve: &str) -> std::result::Result { match curve.to_ascii_uppercase().as_str() { "P256" => Ok(CryptoNamedCurve::P256), "P384" => Ok(CryptoNamedCurve::P384), - _ => Err("named_curve not found"), + _ => Err(["'", curve, "' not available"].concat()), } } } From d3ea7f3b58f488d6ed994c17164c0d5d8f295907 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Tue, 26 Nov 2024 22:29:37 +0900 Subject: [PATCH 18/22] Refactor --- modules/llrt_crypto/src/subtle/derive_bits.rs | 70 ++++++++- .../llrt_crypto/src/subtle/generate_key.rs | 61 +++++++- modules/llrt_crypto/src/subtle/mod.rs | 133 +----------------- 3 files changed, 132 insertions(+), 132 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/derive_bits.rs b/modules/llrt_crypto/src/subtle/derive_bits.rs index 95abf44ff..8c4b72d8a 100644 --- a/modules/llrt_crypto/src/subtle/derive_bits.rs +++ b/modules/llrt_crypto/src/subtle/derive_bits.rs @@ -2,12 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use std::num::NonZeroU32; -use llrt_utils::{bytes::ObjectBytes, result::ResultExt}; +use llrt_utils::{bytes::ObjectBytes, object::ObjectExt, result::ResultExt}; use p256::pkcs8::DecodePrivateKey; use ring::{hkdf, pbkdf2}; use rquickjs::{ArrayBuffer, Ctx, Exception, Result, Value}; -use crate::subtle::{extract_derive_algorithm, CryptoNamedCurve, DeriveAlgorithm, Sha}; +use crate::subtle::{CryptoNamedCurve, DeriveAlgorithm, Sha}; struct HkdfOutput(usize); @@ -29,6 +29,72 @@ pub async fn subtle_derive_bits<'js>( ArrayBuffer::new(ctx, bytes) } +fn extract_derive_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { + let name = algorithm + .get_optional::<_, String>("name")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; + + match name.as_str() { + "ECDH" => { + let namedcurve = algorithm + .get_optional::<_, String>("namedcurve")? + .ok_or_else(|| { + Exception::throw_message(ctx, "ECDH namedCurve must be one of: P-256 or P-384") + })?; + + let curve = CryptoNamedCurve::try_from(namedcurve.as_str()).or_throw(ctx)?; + + let public = algorithm + .get_optional("public")? + .ok_or_else(|| Exception::throw_message(ctx, "ECDH must have CryptoKey"))?; + + Ok(DeriveAlgorithm::Edch { curve, public }) + }, + "HKDF" => { + let hash = algorithm + .get_optional::<_, String>("hash")? + .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have hash"))?; + + let hash = Sha::try_from(hash.as_str()).or_throw(ctx)?; + + let salt = algorithm + .get_optional("salt")? + .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have salt"))?; + + let info = algorithm + .get_optional("info")? + .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have info"))?; + + Ok(DeriveAlgorithm::Hkdf { hash, salt, info }) + }, + "PBKDF2" => { + let hash = algorithm + .get_optional::<_, String>("hash")? + .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have hash"))?; + + let hash = Sha::try_from(hash.as_str()).or_throw(ctx)?; + + let salt = algorithm + .get_optional("salt")? + .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have salt"))?; + + let iterations = algorithm + .get_optional("iterations")? + .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have iterations"))?; + + Ok(DeriveAlgorithm::Pbkdf2 { + hash, + salt, + iterations, + }) + }, + _ => Err(Exception::throw_message( + ctx, + "Algorithm name must be ECDH | HKDF | PBKDF2", + )), + } +} + fn derive_bits( ctx: &Ctx<'_>, algorithm: &DeriveAlgorithm, diff --git a/modules/llrt_crypto/src/subtle/generate_key.rs b/modules/llrt_crypto/src/subtle/generate_key.rs index d75333638..ddea34d5a 100644 --- a/modules/llrt_crypto/src/subtle/generate_key.rs +++ b/modules/llrt_crypto/src/subtle/generate_key.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use std::sync::OnceLock; -use llrt_utils::result::ResultExt; +use llrt_utils::{object::ObjectExt, result::ResultExt}; use num_traits::FromPrimitive; use ring::{rand::SecureRandom, signature::EcdsaKeyPair}; use rquickjs::{Array, ArrayBuffer, Ctx, Exception, Result, Value}; @@ -10,7 +10,7 @@ use rsa::pkcs1::EncodeRsaPrivateKey; use rsa::{rand_core::OsRng, BigUint, RsaPrivateKey}; use crate::{ - subtle::{extract_generate_key_algorithm, CryptoNamedCurve, KeyGenAlgorithm, Sha}, + subtle::{extract_sha_hash, CryptoNamedCurve, KeyGenAlgorithm, Sha}, SYSTEM_RANDOM, }; @@ -29,6 +29,63 @@ pub async fn subtle_generate_key<'js>( ArrayBuffer::new(ctx, bytes) } +fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { + let name = algorithm + .get_optional::<_, String>("name")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; + + match name.as_str() { + "RSASSA-PKCS1-v1_5" | "RSA-PSS" | "RSA-OAEP" => { + let modulus_length = algorithm.get_optional("modulusLength")?.ok_or_else(|| { + Exception::throw_message(ctx, "Algorithm modulusLength not found") + })?; + + let public_exponent = algorithm.get_optional("publicExponent")?.ok_or_else(|| { + Exception::throw_message(ctx, "Algorithm publicExponent not found") + })?; + + Ok(KeyGenAlgorithm::Rsa { + modulus_length, + public_exponent, + }) + }, + "ECDSA" | "ECDH" => { + let namedcurve = algorithm + .get_optional::<_, String>("namedCurve")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm namedCurve not found"))?; + + let curve = CryptoNamedCurve::try_from(namedcurve.as_str()).or_throw(ctx)?; + + Ok(KeyGenAlgorithm::Ec { curve }) + }, + "HMAC" => { + let hash = extract_sha_hash(ctx, algorithm)?; + + let length = algorithm.get_optional::<_, u32>("length")?; + + Ok(KeyGenAlgorithm::Hmac { hash, length }) + }, + "AES-CTR" | "AES-CBC" | "AES-GCM" | "AES-KW" => { + let length = algorithm + .get_optional("length")? + .ok_or_else(|| Exception::throw_message(ctx, "Algorithm length not found"))?; + + if length != 128 && length != 192 && length != 256 { + return Err(Exception::throw_message( + ctx, + "Algorithm length must be one of: 128, 192, or 256.", + )); + } + + Ok(KeyGenAlgorithm::Aes { length }) + }, + _ => Err(Exception::throw_message( + ctx, + "Algorithm must be RsaHashedKeyGenParams | EcKeyGenParams | HmacKeyGenParams | AesKeyGenParams", + )), + } +} + fn generate_key(ctx: &Ctx<'_>, algorithm: &KeyGenAlgorithm) -> Result> { match algorithm { KeyGenAlgorithm::Rsa { diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index a8dc24e10..d65dd6b3e 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -158,14 +158,6 @@ fn extract_algorithm_object(ctx: &Ctx<'_>, algorithm: &Value) -> Result, algorithm: &Value) -> Result { - let hash = algorithm - .get_optional::<_, String>("hash")? - .ok_or_else(|| Exception::throw_message(ctx, "hash not found"))?; - - Sha::try_from(hash.as_str()).or_throw(ctx) -} - fn extract_sign_verify_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { if algorithm.is_string() { let algorithm_name = algorithm.as_string().unwrap().to_string()?; @@ -203,125 +195,10 @@ fn extract_sign_verify_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result, algorithm: &Value) -> Result { - let name = algorithm - .get_optional::<_, String>("name")? - .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; - - match name.as_str() { - "ECDH" => { - let namedcurve = algorithm - .get_optional::<_, String>("namedcurve")? - .ok_or_else(|| { - Exception::throw_message(ctx, "ECDH namedCurve must be one of: P-256 or P-384") - })?; - - let curve = CryptoNamedCurve::try_from(namedcurve.as_str()).or_throw(ctx)?; - - let public = algorithm - .get_optional("public")? - .ok_or_else(|| Exception::throw_message(ctx, "ECDH must have CryptoKey"))?; - - Ok(DeriveAlgorithm::Edch { curve, public }) - }, - "HKDF" => { - let hash = algorithm - .get_optional::<_, String>("hash")? - .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have hash"))?; - - let hash = Sha::try_from(hash.as_str()).or_throw(ctx)?; - - let salt = algorithm - .get_optional("salt")? - .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have salt"))?; - - let info = algorithm - .get_optional("info")? - .ok_or_else(|| Exception::throw_message(ctx, "HKDF must have info"))?; - - Ok(DeriveAlgorithm::Hkdf { hash, salt, info }) - }, - "PBKDF2" => { - let hash = algorithm - .get_optional::<_, String>("hash")? - .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have hash"))?; - - let hash = Sha::try_from(hash.as_str()).or_throw(ctx)?; - - let salt = algorithm - .get_optional("salt")? - .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have salt"))?; - - let iterations = algorithm - .get_optional("iterations")? - .ok_or_else(|| Exception::throw_message(ctx, "PBKDF2 must have iterations"))?; - - Ok(DeriveAlgorithm::Pbkdf2 { - hash, - salt, - iterations, - }) - }, - _ => Err(Exception::throw_message( - ctx, - "Algorithm name must be ECDH | HKDF | PBKDF2", - )), - } -} - -fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { - let name = algorithm - .get_optional::<_, String>("name")? - .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; - - match name.as_str() { - "RSASSA-PKCS1-v1_5" | "RSA-PSS" | "RSA-OAEP" => { - let modulus_length = algorithm.get_optional("modulusLength")?.ok_or_else(|| { - Exception::throw_message(ctx, "Algorithm modulusLength not found") - })?; - - let public_exponent = algorithm.get_optional("publicExponent")?.ok_or_else(|| { - Exception::throw_message(ctx, "Algorithm publicExponent not found") - })?; - - Ok(KeyGenAlgorithm::Rsa { - modulus_length, - public_exponent, - }) - }, - "ECDSA" | "ECDH" => { - let namedcurve = algorithm - .get_optional::<_, String>("namedCurve")? - .ok_or_else(|| Exception::throw_message(ctx, "Algorithm namedCurve not found"))?; - - let curve = CryptoNamedCurve::try_from(namedcurve.as_str()).or_throw(ctx)?; - - Ok(KeyGenAlgorithm::Ec { curve }) - }, - "HMAC" => { - let hash = extract_sha_hash(ctx, algorithm)?; - - let length = algorithm.get_optional::<_, u32>("length")?; - - Ok(KeyGenAlgorithm::Hmac { hash, length }) - }, - "AES-CTR" | "AES-CBC" | "AES-GCM" | "AES-KW" => { - let length = algorithm - .get_optional("length")? - .ok_or_else(|| Exception::throw_message(ctx, "Algorithm length not found"))?; - - if length != 128 && length != 192 && length != 256 { - return Err(Exception::throw_message( - ctx, - "Algorithm length must be one of: 128, 192, or 256.", - )); - } +fn extract_sha_hash(ctx: &Ctx<'_>, algorithm: &Value) -> Result { + let hash = algorithm + .get_optional::<_, String>("hash")? + .ok_or_else(|| Exception::throw_message(ctx, "hash not found"))?; - Ok(KeyGenAlgorithm::Aes { length }) - }, - _ => Err(Exception::throw_message( - ctx, - "Algorithm must be RsaHashedKeyGenParams | EcKeyGenParams | HmacKeyGenParams | AesKeyGenParams", - )), - } + Sha::try_from(hash.as_str()).or_throw(ctx) } From 7d9cb6fe71108c843838b34ab1ff3429c4a6c6c1 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Tue, 26 Nov 2024 23:03:38 +0900 Subject: [PATCH 19/22] Create CryptoKey Object --- modules/llrt_crypto/src/subtle/crypto_key.rs | 55 ++++++++++++++++ .../llrt_crypto/src/subtle/generate_key.rs | 62 ++++++++++++++----- modules/llrt_crypto/src/subtle/mod.rs | 1 + 3 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 modules/llrt_crypto/src/subtle/crypto_key.rs diff --git a/modules/llrt_crypto/src/subtle/crypto_key.rs b/modules/llrt_crypto/src/subtle/crypto_key.rs new file mode 100644 index 000000000..a9309ec2a --- /dev/null +++ b/modules/llrt_crypto/src/subtle/crypto_key.rs @@ -0,0 +1,55 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +use rquickjs::{class::Trace, Array, Ctx, JsLifetime, Object, Result}; + +#[rquickjs::class] +#[derive(Clone, Trace, rquickjs::JsLifetime)] +pub struct CryptoKey<'js> { + type_name: String, + extractable: bool, + #[qjs(skip_trace)] + algorithm: Object<'js>, + usages: Array<'js>, + handle: Vec, +} + +#[rquickjs::methods] +impl<'js> CryptoKey<'js> { + #[qjs(constructor)] + pub fn new( + _ctx: Ctx<'js>, + type_name: String, + extractable: bool, + algorithm: Object<'js>, + usages: Array<'js>, + handle: Vec, + ) -> Result { + Ok(Self { + type_name, + extractable, + algorithm, + usages, + handle, + }) + } + + #[qjs(get, rename = "type")] + pub fn get_type(&self) -> &str { + self.type_name.as_str() + } + + #[qjs(get)] + pub fn extractable(&self) -> bool { + self.extractable + } + + #[qjs(get)] + pub fn algorithm(&self) -> Object<'js> { + self.algorithm.clone() + } + + #[qjs(get)] + pub fn usages(&self) -> Array<'js> { + self.usages.clone() + } +} diff --git a/modules/llrt_crypto/src/subtle/generate_key.rs b/modules/llrt_crypto/src/subtle/generate_key.rs index ddea34d5a..4bd0d8669 100644 --- a/modules/llrt_crypto/src/subtle/generate_key.rs +++ b/modules/llrt_crypto/src/subtle/generate_key.rs @@ -5,7 +5,7 @@ use std::sync::OnceLock; use llrt_utils::{object::ObjectExt, result::ResultExt}; use num_traits::FromPrimitive; use ring::{rand::SecureRandom, signature::EcdsaKeyPair}; -use rquickjs::{Array, ArrayBuffer, Ctx, Exception, Result, Value}; +use rquickjs::{Array, Ctx, Exception, Object, Result, Value}; use rsa::pkcs1::EncodeRsaPrivateKey; use rsa::{rand_core::OsRng, BigUint, RsaPrivateKey}; @@ -14,22 +14,35 @@ use crate::{ SYSTEM_RANDOM, }; +use super::crypto_key::CryptoKey; + static PUB_EXPONENT_1: OnceLock = OnceLock::new(); static PUB_EXPONENT_2: OnceLock = OnceLock::new(); pub async fn subtle_generate_key<'js>( ctx: Ctx<'js>, algorithm: Value<'js>, - _extractable: bool, - _key_usages: Array<'js>, -) -> Result> { - let key_gen_algorithm = extract_generate_key_algorithm(&ctx, &algorithm)?; + extractable: bool, + key_usages: Array<'js>, +) -> Result> { + let (algorithm, key_gen_algorithm) = extract_generate_key_algorithm(&ctx, &algorithm)?; let bytes = generate_key(&ctx, &key_gen_algorithm)?; - ArrayBuffer::new(ctx, bytes) + + CryptoKey::new( + ctx, + "secret".to_string(), // dummy + extractable, + algorithm, + key_usages, + bytes, // dummy + ) } -fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { +fn extract_generate_key_algorithm<'js>( + ctx: &Ctx<'js>, + algorithm: &Value, +) -> Result<(Object<'js>, KeyGenAlgorithm)> { let name = algorithm .get_optional::<_, String>("name")? .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; @@ -40,30 +53,45 @@ fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result = algorithm.get_optional("publicExponent")?.ok_or_else(|| { Exception::throw_message(ctx, "Algorithm publicExponent not found") })?; + let public_exponent_1 = public_exponent.clone(); + + let obj = Object::new(ctx.clone())?; + obj.set("name", name)?; + obj.set("modulusLength", modulus_length)?; + obj.set("publicExponent", public_exponent_1)?; - Ok(KeyGenAlgorithm::Rsa { + Ok((obj, + KeyGenAlgorithm::Rsa { modulus_length, public_exponent, - }) + })) }, "ECDSA" | "ECDH" => { - let namedcurve = algorithm + let named_curve = algorithm .get_optional::<_, String>("namedCurve")? .ok_or_else(|| Exception::throw_message(ctx, "Algorithm namedCurve not found"))?; - let curve = CryptoNamedCurve::try_from(namedcurve.as_str()).or_throw(ctx)?; + let curve = CryptoNamedCurve::try_from(named_curve.as_str()).or_throw(ctx)?; - Ok(KeyGenAlgorithm::Ec { curve }) + let obj = Object::new(ctx.clone())?; + obj.set("name", name)?; + obj.set("namedCurve", named_curve)?; + + Ok((obj, KeyGenAlgorithm::Ec { curve })) }, "HMAC" => { let hash = extract_sha_hash(ctx, algorithm)?; let length = algorithm.get_optional::<_, u32>("length")?; - Ok(KeyGenAlgorithm::Hmac { hash, length }) + let obj = Object::new(ctx.clone())?; + obj.set("name", name)?; + obj.set("length", length)?; + + Ok((obj, KeyGenAlgorithm::Hmac { hash, length })) }, "AES-CTR" | "AES-CBC" | "AES-GCM" | "AES-KW" => { let length = algorithm @@ -77,7 +105,11 @@ fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result Err(Exception::throw_message( ctx, diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index d65dd6b3e..ef4e4d97c 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -1,5 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +mod crypto_key; mod decrypt; mod derive_bits; mod digest; From 4c19eb5f815c9bbadbaf77b34f66c7d9be6f1641 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Tue, 26 Nov 2024 23:09:30 +0900 Subject: [PATCH 20/22] Fix --- modules/llrt_crypto/src/subtle/crypto_key.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/llrt_crypto/src/subtle/crypto_key.rs b/modules/llrt_crypto/src/subtle/crypto_key.rs index a9309ec2a..02f4919f0 100644 --- a/modules/llrt_crypto/src/subtle/crypto_key.rs +++ b/modules/llrt_crypto/src/subtle/crypto_key.rs @@ -7,7 +7,6 @@ use rquickjs::{class::Trace, Array, Ctx, JsLifetime, Object, Result}; pub struct CryptoKey<'js> { type_name: String, extractable: bool, - #[qjs(skip_trace)] algorithm: Object<'js>, usages: Array<'js>, handle: Vec, From ab0b0a7fbd3d2b774792fe9e1b51ec500b709c18 Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Wed, 27 Nov 2024 11:44:12 +0900 Subject: [PATCH 21/22] Refactor generateKey --- modules/llrt_crypto/src/subtle/crypto_key.rs | 8 ++-- .../llrt_crypto/src/subtle/generate_key.rs | 43 ++++--------------- 2 files changed, 13 insertions(+), 38 deletions(-) diff --git a/modules/llrt_crypto/src/subtle/crypto_key.rs b/modules/llrt_crypto/src/subtle/crypto_key.rs index 02f4919f0..80cb35186 100644 --- a/modules/llrt_crypto/src/subtle/crypto_key.rs +++ b/modules/llrt_crypto/src/subtle/crypto_key.rs @@ -1,13 +1,13 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -use rquickjs::{class::Trace, Array, Ctx, JsLifetime, Object, Result}; +use rquickjs::{class::Trace, Array, Ctx, JsLifetime, Result, Value}; #[rquickjs::class] #[derive(Clone, Trace, rquickjs::JsLifetime)] pub struct CryptoKey<'js> { type_name: String, extractable: bool, - algorithm: Object<'js>, + algorithm: Value<'js>, usages: Array<'js>, handle: Vec, } @@ -19,7 +19,7 @@ impl<'js> CryptoKey<'js> { _ctx: Ctx<'js>, type_name: String, extractable: bool, - algorithm: Object<'js>, + algorithm: Value<'js>, usages: Array<'js>, handle: Vec, ) -> Result { @@ -43,7 +43,7 @@ impl<'js> CryptoKey<'js> { } #[qjs(get)] - pub fn algorithm(&self) -> Object<'js> { + pub fn algorithm(&self) -> Value<'js> { self.algorithm.clone() } diff --git a/modules/llrt_crypto/src/subtle/generate_key.rs b/modules/llrt_crypto/src/subtle/generate_key.rs index 4bd0d8669..6ee0c5ed0 100644 --- a/modules/llrt_crypto/src/subtle/generate_key.rs +++ b/modules/llrt_crypto/src/subtle/generate_key.rs @@ -5,7 +5,7 @@ use std::sync::OnceLock; use llrt_utils::{object::ObjectExt, result::ResultExt}; use num_traits::FromPrimitive; use ring::{rand::SecureRandom, signature::EcdsaKeyPair}; -use rquickjs::{Array, Ctx, Exception, Object, Result, Value}; +use rquickjs::{Array, Ctx, Exception, Result, Value}; use rsa::pkcs1::EncodeRsaPrivateKey; use rsa::{rand_core::OsRng, BigUint, RsaPrivateKey}; @@ -25,7 +25,7 @@ pub async fn subtle_generate_key<'js>( extractable: bool, key_usages: Array<'js>, ) -> Result> { - let (algorithm, key_gen_algorithm) = extract_generate_key_algorithm(&ctx, &algorithm)?; + let key_gen_algorithm = extract_generate_key_algorithm(&ctx, &algorithm)?; let bytes = generate_key(&ctx, &key_gen_algorithm)?; @@ -39,10 +39,7 @@ pub async fn subtle_generate_key<'js>( ) } -fn extract_generate_key_algorithm<'js>( - ctx: &Ctx<'js>, - algorithm: &Value, -) -> Result<(Object<'js>, KeyGenAlgorithm)> { +fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { let name = algorithm .get_optional::<_, String>("name")? .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; @@ -53,21 +50,11 @@ fn extract_generate_key_algorithm<'js>( Exception::throw_message(ctx, "Algorithm modulusLength not found") })?; - let public_exponent: Vec = algorithm.get_optional("publicExponent")?.ok_or_else(|| { + let public_exponent = algorithm.get_optional("publicExponent")?.ok_or_else(|| { Exception::throw_message(ctx, "Algorithm publicExponent not found") })?; - let public_exponent_1 = public_exponent.clone(); - - let obj = Object::new(ctx.clone())?; - obj.set("name", name)?; - obj.set("modulusLength", modulus_length)?; - obj.set("publicExponent", public_exponent_1)?; - - Ok((obj, - KeyGenAlgorithm::Rsa { - modulus_length, - public_exponent, - })) + + Ok(KeyGenAlgorithm::Rsa { modulus_length, public_exponent }) }, "ECDSA" | "ECDH" => { let named_curve = algorithm @@ -76,22 +63,14 @@ fn extract_generate_key_algorithm<'js>( let curve = CryptoNamedCurve::try_from(named_curve.as_str()).or_throw(ctx)?; - let obj = Object::new(ctx.clone())?; - obj.set("name", name)?; - obj.set("namedCurve", named_curve)?; - - Ok((obj, KeyGenAlgorithm::Ec { curve })) + Ok(KeyGenAlgorithm::Ec { curve }) }, "HMAC" => { let hash = extract_sha_hash(ctx, algorithm)?; let length = algorithm.get_optional::<_, u32>("length")?; - let obj = Object::new(ctx.clone())?; - obj.set("name", name)?; - obj.set("length", length)?; - - Ok((obj, KeyGenAlgorithm::Hmac { hash, length })) + Ok(KeyGenAlgorithm::Hmac { hash, length }) }, "AES-CTR" | "AES-CBC" | "AES-GCM" | "AES-KW" => { let length = algorithm @@ -105,11 +84,7 @@ fn extract_generate_key_algorithm<'js>( )); } - let obj = Object::new(ctx.clone())?; - obj.set("name", name)?; - obj.set("length", length)?; - - Ok((obj, KeyGenAlgorithm::Aes { length })) + Ok(KeyGenAlgorithm::Aes { length }) }, _ => Err(Exception::throw_message( ctx, From 988590ad861a1ba911edd69d97fa47628bc3d66d Mon Sep 17 00:00:00 2001 From: WATANABE Shinya Date: Wed, 27 Nov 2024 23:41:37 +0900 Subject: [PATCH 22/22] Expose CryptoKey and CryptoKeyPair --- modules/llrt_crypto/src/lib.rs | 4 +- .../llrt_crypto/src/subtle/generate_key.rs | 59 ++++++++++++++----- modules/llrt_crypto/src/subtle/mod.rs | 5 +- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/modules/llrt_crypto/src/lib.rs b/modules/llrt_crypto/src/lib.rs index d8d7bc481..2bca01bf9 100644 --- a/modules/llrt_crypto/src/lib.rs +++ b/modules/llrt_crypto/src/lib.rs @@ -29,7 +29,7 @@ use rquickjs::{ }; use subtle::{ subtle_decrypt, subtle_derive_bits, subtle_digest, subtle_encrypt, subtle_generate_key, - subtle_sign, subtle_verify, + subtle_sign, subtle_verify, CryptoKey, }; use uuid::Uuid; use uuid_simd::UuidExt; @@ -180,6 +180,8 @@ fn uuidv4() -> String { pub fn init(ctx: &Ctx<'_>) -> Result<()> { let globals = ctx.globals(); + Class::::define(&globals)?; + let crypto = Object::new(ctx.clone())?; crypto.set("createHash", Func::from(Hash::new))?; diff --git a/modules/llrt_crypto/src/subtle/generate_key.rs b/modules/llrt_crypto/src/subtle/generate_key.rs index 6ee0c5ed0..032986281 100644 --- a/modules/llrt_crypto/src/subtle/generate_key.rs +++ b/modules/llrt_crypto/src/subtle/generate_key.rs @@ -5,7 +5,7 @@ use std::sync::OnceLock; use llrt_utils::{object::ObjectExt, result::ResultExt}; use num_traits::FromPrimitive; use ring::{rand::SecureRandom, signature::EcdsaKeyPair}; -use rquickjs::{Array, Ctx, Exception, Result, Value}; +use rquickjs::{Array, Ctx, Exception, IntoJs, Object, Result, Value}; use rsa::pkcs1::EncodeRsaPrivateKey; use rsa::{rand_core::OsRng, BigUint, RsaPrivateKey}; @@ -24,22 +24,49 @@ pub async fn subtle_generate_key<'js>( algorithm: Value<'js>, extractable: bool, key_usages: Array<'js>, -) -> Result> { - let key_gen_algorithm = extract_generate_key_algorithm(&ctx, &algorithm)?; +) -> Result> { + let (name, key_gen_algorithm) = extract_generate_key_algorithm(&ctx, &algorithm)?; let bytes = generate_key(&ctx, &key_gen_algorithm)?; - CryptoKey::new( - ctx, - "secret".to_string(), // dummy - extractable, - algorithm, - key_usages, - bytes, // dummy - ) + if name.starts_with("AES") || name == "HMAC" { + CryptoKey::new( + ctx.clone(), + "secret".to_string(), + extractable, + algorithm, + key_usages, // for test + bytes, // for test + ) + .into_js(&ctx) + } else { + let private = CryptoKey::new( + ctx.clone(), + "private".to_string(), + extractable, + algorithm.clone(), + key_usages.clone(), // for test + bytes.clone(), // for test + )?; + let public = CryptoKey::new( + ctx.clone(), + "public".to_string(), + true, + algorithm, + key_usages, // for test + bytes, // for test + )?; + let obj = Object::new(ctx)?; + obj.set("privateKey", private)?; + obj.set("publicKey", public)?; + Ok(obj.into()) + } } -fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { +fn extract_generate_key_algorithm( + ctx: &Ctx<'_>, + algorithm: &Value, +) -> Result<(String, KeyGenAlgorithm)> { let name = algorithm .get_optional::<_, String>("name")? .ok_or_else(|| Exception::throw_message(ctx, "Algorithm name not found"))?; @@ -54,7 +81,7 @@ fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { let named_curve = algorithm @@ -63,14 +90,14 @@ fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result { let hash = extract_sha_hash(ctx, algorithm)?; let length = algorithm.get_optional::<_, u32>("length")?; - Ok(KeyGenAlgorithm::Hmac { hash, length }) + Ok((name, KeyGenAlgorithm::Hmac { hash, length })) }, "AES-CTR" | "AES-CBC" | "AES-GCM" | "AES-KW" => { let length = algorithm @@ -84,7 +111,7 @@ fn extract_generate_key_algorithm(ctx: &Ctx<'_>, algorithm: &Value) -> Result Err(Exception::throw_message( ctx, diff --git a/modules/llrt_crypto/src/subtle/mod.rs b/modules/llrt_crypto/src/subtle/mod.rs index ef4e4d97c..4774eea92 100644 --- a/modules/llrt_crypto/src/subtle/mod.rs +++ b/modules/llrt_crypto/src/subtle/mod.rs @@ -9,6 +9,7 @@ mod generate_key; mod sign; mod verify; +pub use crypto_key::CryptoKey; pub use decrypt::subtle_decrypt; pub use derive_bits::subtle_derive_bits; pub use digest::subtle_digest; @@ -60,8 +61,8 @@ impl TryFrom<&str> for CryptoNamedCurve { fn try_from(curve: &str) -> std::result::Result { match curve.to_ascii_uppercase().as_str() { - "P256" => Ok(CryptoNamedCurve::P256), - "P384" => Ok(CryptoNamedCurve::P384), + "P-256" => Ok(CryptoNamedCurve::P256), + "P-384" => Ok(CryptoNamedCurve::P384), _ => Err(["'", curve, "' not available"].concat()), } }