diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/node/Cargo.toml | 1 | ||||
-rw-r--r-- | ext/node/crypto/mod.rs | 58 | ||||
-rw-r--r-- | ext/node/lib.rs | 2 | ||||
-rw-r--r-- | ext/node/polyfills/internal/crypto/hkdf.ts | 28 |
4 files changed, 81 insertions, 8 deletions
diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml index 4dbc79b9e..e74cf3805 100644 --- a/ext/node/Cargo.toml +++ b/ext/node/Cargo.toml @@ -20,6 +20,7 @@ deno_core.workspace = true digest = { version = "0.10.5", features = ["core-api", "std"] } ecb.workspace = true hex.workspace = true +hkdf.workspace = true idna = "0.3.0" indexmap.workspace = true libz-sys = { version = "1.1.8", features = ["static"] } diff --git a/ext/node/crypto/mod.rs b/ext/node/crypto/mod.rs index 499e99fea..adacdf6d6 100644 --- a/ext/node/crypto/mod.rs +++ b/ext/node/crypto/mod.rs @@ -7,6 +7,7 @@ use deno_core::OpState; use deno_core::ResourceId; use deno_core::StringOrBuffer; use deno_core::ZeroCopyBuf; +use hkdf::Hkdf; use num_bigint::BigInt; use rand::Rng; use std::future::Future; @@ -419,3 +420,60 @@ pub async fn op_node_generate_secret_async(len: i32) -> ZeroCopyBuf { .await .unwrap() } + +fn hkdf_sync( + hash: &str, + ikm: &[u8], + salt: &[u8], + info: &[u8], + okm: &mut [u8], +) -> Result<(), AnyError> { + macro_rules! hkdf { + ($hash:ty) => {{ + let hk = Hkdf::<$hash>::new(Some(salt), ikm); + hk.expand(info, okm) + .map_err(|_| type_error("HKDF-Expand failed"))?; + }}; + } + + match hash { + "md4" => hkdf!(md4::Md4), + "md5" => hkdf!(md5::Md5), + "ripemd160" => hkdf!(ripemd::Ripemd160), + "sha1" => hkdf!(sha1::Sha1), + "sha224" => hkdf!(sha2::Sha224), + "sha256" => hkdf!(sha2::Sha256), + "sha384" => hkdf!(sha2::Sha384), + "sha512" => hkdf!(sha2::Sha512), + _ => return Err(type_error("Unknown digest")), + } + + Ok(()) +} + +#[op] +pub fn op_node_hkdf( + hash: &str, + ikm: &[u8], + salt: &[u8], + info: &[u8], + okm: &mut [u8], +) -> Result<(), AnyError> { + hkdf_sync(hash, ikm, salt, info, okm) +} + +#[op] +pub async fn op_node_hkdf_async( + hash: String, + ikm: ZeroCopyBuf, + salt: ZeroCopyBuf, + info: ZeroCopyBuf, + okm_len: usize, +) -> Result<ZeroCopyBuf, AnyError> { + tokio::task::spawn_blocking(move || { + let mut okm = vec![0u8; okm_len]; + hkdf_sync(&hash, &ikm, &salt, &info, &mut okm)?; + Ok(okm.into()) + }) + .await? +} diff --git a/ext/node/lib.rs b/ext/node/lib.rs index 478efaf27..bf947f5e8 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -189,6 +189,8 @@ deno_core::extension!(deno_node, crypto::op_node_check_prime_bytes_async, crypto::op_node_pbkdf2, crypto::op_node_pbkdf2_async, + crypto::op_node_hkdf, + crypto::op_node_hkdf_async, crypto::op_node_generate_secret, crypto::op_node_generate_secret_async, crypto::op_node_sign, diff --git a/ext/node/polyfills/internal/crypto/hkdf.ts b/ext/node/polyfills/internal/crypto/hkdf.ts index deeba102f..fb26053df 100644 --- a/ext/node/polyfills/internal/crypto/hkdf.ts +++ b/ext/node/polyfills/internal/crypto/hkdf.ts @@ -7,6 +7,7 @@ import { validateString, } from "ext:deno_node/internal/validators.mjs"; import { + ERR_CRYPTO_INVALID_DIGEST, ERR_INVALID_ARG_TYPE, ERR_OUT_OF_RANGE, hideStackFrames, @@ -26,17 +27,19 @@ import { isAnyArrayBuffer, isArrayBufferView, } from "ext:deno_node/internal/util/types.ts"; -import { notImplemented } from "ext:deno_node/_utils.ts"; -const validateParameters = hideStackFrames((hash, key, salt, info, length) => { - key = prepareKey(key); - salt = toBuf(salt); - info = toBuf(info); +const { core } = globalThis.__bootstrap; +const { ops } = core; +const validateParameters = hideStackFrames((hash, key, salt, info, length) => { validateString(hash, "digest"); + key = new Uint8Array(prepareKey(key)); validateByteSource(salt, "salt"); validateByteSource(info, "info"); + salt = new Uint8Array(toBuf(salt)); + info = new Uint8Array(toBuf(info)); + validateInteger(length, "length", 0, kMaxLength); if (info.byteLength > 1024) { @@ -91,7 +94,7 @@ export function hkdf( salt: BinaryLike, info: BinaryLike, length: number, - callback: (err: Error | null, derivedKey: ArrayBuffer) => void, + callback: (err: Error | null, derivedKey: ArrayBuffer | undefined) => void, ) { ({ hash, key, salt, info, length } = validateParameters( hash, @@ -103,7 +106,9 @@ export function hkdf( validateFunction(callback, "callback"); - notImplemented("crypto.hkdf"); + core.opAsync("op_node_hkdf_async", hash, key, salt, info, length) + .then((okm) => callback(null, okm.buffer)) + .catch((err) => callback(new ERR_CRYPTO_INVALID_DIGEST(err), undefined)); } export function hkdfSync( @@ -121,7 +126,14 @@ export function hkdfSync( length, )); - notImplemented("crypto.hkdfSync"); + const okm = new Uint8Array(length); + try { + ops.op_node_hkdf(hash, key, salt, info, okm); + } catch (e) { + throw new ERR_CRYPTO_INVALID_DIGEST(e); + } + + return okm.buffer; } export default { |