summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2024-07-05 10:10:22 +0200
committerGitHub <noreply@github.com>2024-07-05 10:10:22 +0200
commit08e5606c3400d3a993c0ce6748901c56fc3db35b (patch)
tree032d3a09c6d22763ceb703e7908ca159d3d7a809
parentb290fd01f3f5d32f9d010fc719ced0240759c049 (diff)
fix(ext/node): rewrite digest handling (#24392)
Previously we had many different code paths all handling digests in different places, all with wildly different digest support. This commit rewrites this to use a single digest handling mechanism for all digest operations. It adds various aliases for digest algorithms, like node does. For example `sha1WithRSAEncryption` is an alias for `sha1`. It also adds support for `md5-sha1` digests in various places.
-rw-r--r--ext/crypto/Cargo.toml2
-rw-r--r--ext/node/Cargo.toml6
-rw-r--r--ext/node/ops/crypto/digest.rs344
-rw-r--r--ext/node/ops/crypto/md5_sha1.rs99
-rw-r--r--ext/node/ops/crypto/mod.rs163
-rw-r--r--ext/node/polyfills/internal/crypto/hkdf.ts7
-rw-r--r--ext/node/polyfills/internal/crypto/pbkdf2.ts76
-rw-r--r--ext/node/polyfills/internal/crypto/sig.ts9
-rw-r--r--ext/node/polyfills/internal/crypto/types.ts2
-rw-r--r--tests/integration/node_unit_tests.rs7
-rw-r--r--tests/node_compat/config.jsonc2
-rw-r--r--tests/node_compat/runner/TODO.md1
-rw-r--r--tests/node_compat/test/parallel/test-crypto-pbkdf2.js251
-rw-r--r--tests/unit_node/crypto/crypto_hkdf_test.ts36
-rw-r--r--tests/unit_node/crypto/crypto_pbkdf2_test.ts (renamed from tests/unit_node/internal/pbkdf2_test.ts)32
-rw-r--r--tests/unit_node/crypto/crypto_scrypt_test.ts (renamed from tests/unit_node/internal/scrypt_test.ts)0
-rw-r--r--tests/unit_node/crypto/crypto_sign_test.ts41
-rw-r--r--tests/unit_node/crypto/generate_fixture.mjs69
-rw-r--r--tests/unit_node/testdata/crypto_digest_fixtures.json366
19 files changed, 1219 insertions, 294 deletions
diff --git a/ext/crypto/Cargo.toml b/ext/crypto/Cargo.toml
index e1fc16275..418394584 100644
--- a/ext/crypto/Cargo.toml
+++ b/ext/crypto/Cargo.toml
@@ -35,7 +35,7 @@ ring = { workspace = true, features = ["std"] }
rsa.workspace = true
serde.workspace = true
serde_bytes.workspace = true
-sha1 = { version = "0.10.6", features = ["oid"] }
+sha1.workspace = true
sha2.workspace = true
signature.workspace = true
spki.workspace = true
diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml
index b1d40756b..b9228dfdd 100644
--- a/ext/node/Cargo.toml
+++ b/ext/node/Cargo.toml
@@ -49,7 +49,7 @@ k256 = "0.13.1"
lazy-regex.workspace = true
libc.workspace = true
libz-sys.workspace = true
-md-5 = "0.10.5"
+md-5 = { version = "0.10.5", features = ["oid"] }
md4 = "0.10.2"
num-bigint.workspace = true
num-bigint-dig = "0.8.2"
@@ -66,14 +66,14 @@ rand.workspace = true
regex.workspace = true
reqwest.workspace = true
ring.workspace = true
-ripemd = "0.1.3"
+ripemd = { version = "0.1.3", features = ["oid"] }
rsa.workspace = true
scrypt = "0.11.0"
sec1 = "0.7"
serde = "1.0.149"
sha1.workspace = true
sha2.workspace = true
-sha3 = "0.10.8"
+sha3 = { version = "0.10.8", features = ["oid"] }
signature.workspace = true
simd-json = "0.13.4"
sm3 = "0.4.2"
diff --git a/ext/node/ops/crypto/digest.rs b/ext/node/ops/crypto/digest.rs
index e3a91e338..0a21a395a 100644
--- a/ext/node/ops/crypto/digest.rs
+++ b/ext/node/ops/crypto/digest.rs
@@ -56,30 +56,110 @@ impl Hasher {
}
}
-pub enum Hash {
- Blake2b512(Box<blake2::Blake2b512>),
- Blake2s256(Box<blake2::Blake2s256>),
-
- Md4(Box<md4::Md4>),
- Md5(Box<md5::Md5>),
-
- Ripemd160(Box<ripemd::Ripemd160>),
-
- Sha1(Box<sha1::Sha1>),
-
- Sha224(Box<sha2::Sha224>),
- Sha256(Box<sha2::Sha256>),
- Sha384(Box<sha2::Sha384>),
- Sha512(Box<sha2::Sha512>),
- Sha512_224(Box<sha2::Sha512_224>),
- Sha512_256(Box<sha2::Sha512_256>),
+macro_rules! match_fixed_digest {
+ ($algorithm_name:expr, fn <$type:ident>() $body:block, _ => $other:block) => {
+ match $algorithm_name {
+ "blake2b512" => {
+ type $type = ::blake2::Blake2b512;
+ $body
+ }
+ "blake2s256" => {
+ type $type = ::blake2::Blake2s256;
+ $body
+ }
+ _ => match_fixed_digest_with_eager_block_buffer!($algorithm_name, fn <$type>() $body, _ => $other)
+ }
+ };
+}
+pub(crate) use match_fixed_digest;
+
+macro_rules! match_fixed_digest_with_eager_block_buffer {
+ ($algorithm_name:expr, fn <$type:ident>() $body:block, _ => $other:block) => {
+ match $algorithm_name {
+ "rsa-sm3" | "sm3" | "sm3withrsaencryption" => {
+ type $type = ::sm3::Sm3;
+ $body
+ }
+ "md5-sha1" => {
+ type $type = crate::ops::crypto::md5_sha1::Md5Sha1;
+ $body
+ }
+ _ => match_fixed_digest_with_oid!($algorithm_name, fn <$type>() $body, _ => $other)
+ }
+ };
+}
+pub(crate) use match_fixed_digest_with_eager_block_buffer;
+
+macro_rules! match_fixed_digest_with_oid {
+ ($algorithm_name:expr, fn <$type:ident>() $body:block, _ => $other:block) => {
+ match $algorithm_name {
+ "rsa-md5" | "md5" | "md5withrsaencryption" | "ssl3-md5" => {
+ type $type = ::md5::Md5;
+ $body
+ }
+ "rsa-ripemd160" | "ripemd" | "ripemd160" | "ripemd160withrsa"
+ | "rmd160" => {
+ type $type = ::ripemd::Ripemd160;
+ $body
+ }
+ "rsa-sha1"
+ | "rsa-sha1-2"
+ | "sha1"
+ | "sha1-2"
+ | "sha1withrsaencryption"
+ | "ssl3-sha1" => {
+ type $type = ::sha1::Sha1;
+ $body
+ }
+ "rsa-sha224" | "sha224" | "sha224withrsaencryption" => {
+ type $type = ::sha2::Sha224;
+ $body
+ }
+ "rsa-sha256" | "sha256" | "sha256withrsaencryption" => {
+ type $type = ::sha2::Sha256;
+ $body
+ }
+ "rsa-sha384" | "sha384" | "sha384withrsaencryption" => {
+ type $type = ::sha2::Sha384;
+ $body
+ }
+ "rsa-sha512" | "sha512" | "sha512withrsaencryption" => {
+ type $type = ::sha2::Sha512;
+ $body
+ }
+ "rsa-sha512/224" | "sha512-224" | "sha512-224withrsaencryption" => {
+ type $type = ::sha2::Sha512_224;
+ $body
+ }
+ "rsa-sha512/256" | "sha512-256" | "sha512-256withrsaencryption" => {
+ type $type = ::sha2::Sha512_256;
+ $body
+ }
+ "rsa-sha3-224" | "id-rsassa-pkcs1-v1_5-with-sha3-224" | "sha3-224" => {
+ type $type = ::sha3::Sha3_224;
+ $body
+ }
+ "rsa-sha3-256" | "id-rsassa-pkcs1-v1_5-with-sha3-256" | "sha3-256" => {
+ type $type = ::sha3::Sha3_256;
+ $body
+ }
+ "rsa-sha3-384" | "id-rsassa-pkcs1-v1_5-with-sha3-384" | "sha3-384" => {
+ type $type = ::sha3::Sha3_384;
+ $body
+ }
+ "rsa-sha3-512" | "id-rsassa-pkcs1-v1_5-with-sha3-512" | "sha3-512" => {
+ type $type = ::sha3::Sha3_512;
+ $body
+ }
+ _ => $other,
+ }
+ };
+}
- Sha3_224(Box<sha3::Sha3_224>),
- Sha3_256(Box<sha3::Sha3_256>),
- Sha3_384(Box<sha3::Sha3_384>),
- Sha3_512(Box<sha3::Sha3_512>),
+pub(crate) use match_fixed_digest_with_oid;
- Sm3(Box<sm3::Sm3>),
+pub enum Hash {
+ FixedSize(Box<dyn DynDigest>),
Shake128(Box<sha3::Shake128>, /* output_length: */ Option<usize>),
Shake256(Box<sha3::Shake256>, /* output_length: */ Option<usize>),
@@ -98,105 +178,32 @@ impl Hash {
_ => {}
}
- let algorithm = match algorithm_name {
- "blake2b512" => Blake2b512(Default::default()),
- "blake2s256" => Blake2s256(Default::default()),
-
- "md4" => Md4(Default::default()),
- "md5" => Md5(Default::default()),
-
- "ripemd160" => Ripemd160(Default::default()),
-
- "sha1" => Sha1(Default::default()),
- "sha224" => Sha224(Default::default()),
- "sha256" => Sha256(Default::default()),
- "sha384" => Sha384(Default::default()),
- "sha512" => Sha512(Default::default()),
- "sha512-224" => Sha512_224(Default::default()),
- "sha512-256" => Sha512_256(Default::default()),
-
- "sha3-224" => Sha3_224(Default::default()),
- "sha3-256" => Sha3_256(Default::default()),
- "sha3-384" => Sha3_384(Default::default()),
- "sha3-512" => Sha3_512(Default::default()),
-
- "sm3" => Sm3(Default::default()),
-
+ let algorithm = match_fixed_digest!(
+ algorithm_name,
+ fn <D>() {
+ let digest: D = Digest::new();
+ if let Some(length) = output_length {
+ if length != digest.output_size() {
+ return Err(generic_error(
+ "Output length mismatch for non-extendable algorithm",
+ ));
+ }
+ }
+ FixedSize(Box::new(digest))
+ },
_ => {
return Err(generic_error(format!(
"Digest method not supported: {algorithm_name}"
)))
}
- };
- if let Some(length) = output_length {
- if length != algorithm.output_length() {
- return Err(generic_error(
- "Output length mismatch for non-extendable algorithm",
- ));
- }
- }
- Ok(algorithm)
- }
+ );
- pub fn output_length(&self) -> usize {
- match self {
- Blake2b512(context) => context.output_size(),
- Blake2s256(context) => context.output_size(),
-
- Md4(context) => context.output_size(),
- Md5(context) => context.output_size(),
-
- Ripemd160(context) => context.output_size(),
-
- Sha1(context) => context.output_size(),
- Sha224(context) => context.output_size(),
- Sha256(context) => context.output_size(),
- Sha384(context) => context.output_size(),
- Sha512(context) => context.output_size(),
- Sha512_224(context) => context.output_size(),
- Sha512_256(context) => context.output_size(),
-
- Sha3_224(context) => context.output_size(),
- Sha3_256(context) => context.output_size(),
- Sha3_384(context) => context.output_size(),
- Sha3_512(context) => context.output_size(),
-
- Sm3(context) => context.output_size(),
-
- Shake128(_, _) => unreachable!(
- "output_length() should not be called on extendable algorithms"
- ),
- Shake256(_, _) => unreachable!(
- "output_length() should not be called on extendable algorithms"
- ),
- }
+ Ok(algorithm)
}
pub fn update(&mut self, data: &[u8]) {
match self {
- Blake2b512(context) => Digest::update(&mut **context, data),
- Blake2s256(context) => Digest::update(&mut **context, data),
-
- Md4(context) => Digest::update(&mut **context, data),
- Md5(context) => Digest::update(&mut **context, data),
-
- Ripemd160(context) => Digest::update(&mut **context, data),
-
- Sha1(context) => Digest::update(&mut **context, data),
- Sha224(context) => Digest::update(&mut **context, data),
- Sha256(context) => Digest::update(&mut **context, data),
- Sha384(context) => Digest::update(&mut **context, data),
- Sha512(context) => Digest::update(&mut **context, data),
- Sha512_224(context) => Digest::update(&mut **context, data),
- Sha512_256(context) => Digest::update(&mut **context, data),
-
- Sha3_224(context) => Digest::update(&mut **context, data),
- Sha3_256(context) => Digest::update(&mut **context, data),
- Sha3_384(context) => Digest::update(&mut **context, data),
- Sha3_512(context) => Digest::update(&mut **context, data),
-
- Sm3(context) => Digest::update(&mut **context, data),
-
+ FixedSize(context) => DynDigest::update(&mut **context, data),
Shake128(context, _) => Update::update(&mut **context, data),
Shake256(context, _) => Update::update(&mut **context, data),
};
@@ -204,28 +211,7 @@ impl Hash {
pub fn digest_and_drop(self) -> Box<[u8]> {
match self {
- Blake2b512(context) => context.finalize(),
- Blake2s256(context) => context.finalize(),
-
- Md4(context) => context.finalize(),
- Md5(context) => context.finalize(),
-
- Ripemd160(context) => context.finalize(),
-
- Sha1(context) => context.finalize(),
- Sha224(context) => context.finalize(),
- Sha256(context) => context.finalize(),
- Sha384(context) => context.finalize(),
- Sha512(context) => context.finalize(),
- Sha512_224(context) => context.finalize(),
- Sha512_256(context) => context.finalize(),
-
- Sha3_224(context) => context.finalize(),
- Sha3_256(context) => context.finalize(),
- Sha3_384(context) => context.finalize(),
- Sha3_512(context) => context.finalize(),
-
- Sm3(context) => context.finalize(),
+ FixedSize(context) => context.finalize(),
// The default output lengths align with Node.js
Shake128(context, output_length) => {
@@ -242,69 +228,77 @@ impl Hash {
output_length: Option<usize>,
) -> Result<Self, AnyError> {
let hash = match self {
- Shake128(context, _) => {
- return Ok(Shake128(context.clone(), output_length))
+ FixedSize(context) => {
+ if let Some(length) = output_length {
+ if length != context.output_size() {
+ return Err(generic_error(
+ "Output length mismatch for non-extendable algorithm",
+ ));
+ }
+ }
+ FixedSize(context.box_clone())
}
- Shake256(context, _) => {
- return Ok(Shake256(context.clone(), output_length))
- }
-
- Blake2b512(context) => Blake2b512(context.clone()),
- Blake2s256(context) => Blake2s256(context.clone()),
-
- Md4(context) => Md4(context.clone()),
- Md5(context) => Md5(context.clone()),
-
- Ripemd160(context) => Ripemd160(context.clone()),
-
- Sha1(context) => Sha1(context.clone()),
- Sha224(context) => Sha224(context.clone()),
- Sha256(context) => Sha256(context.clone()),
- Sha384(context) => Sha384(context.clone()),
- Sha512(context) => Sha512(context.clone()),
- Sha512_224(context) => Sha512_224(context.clone()),
- Sha512_256(context) => Sha512_256(context.clone()),
- Sha3_224(context) => Sha3_224(context.clone()),
- Sha3_256(context) => Sha3_256(context.clone()),
- Sha3_384(context) => Sha3_384(context.clone()),
- Sha3_512(context) => Sha3_512(context.clone()),
-
- Sm3(context) => Sm3(context.clone()),
+ Shake128(context, _) => Shake128(context.clone(), output_length),
+ Shake256(context, _) => Shake256(context.clone(), output_length),
};
-
- if let Some(length) = output_length {
- if length != hash.output_length() {
- return Err(generic_error(
- "Output length mismatch for non-extendable algorithm",
- ));
- }
- }
-
Ok(hash)
}
pub fn get_hashes() -> Vec<&'static str> {
vec![
- "blake2s256",
+ "RSA-MD5",
+ "RSA-RIPEMD160",
+ "RSA-SHA1",
+ "RSA-SHA1-2",
+ "RSA-SHA224",
+ "RSA-SHA256",
+ "RSA-SHA3-224",
+ "RSA-SHA3-256",
+ "RSA-SHA3-384",
+ "RSA-SHA3-512",
+ "RSA-SHA384",
+ "RSA-SHA512",
+ "RSA-SHA512/224",
+ "RSA-SHA512/256",
+ "RSA-SM3",
"blake2b512",
- "md4",
+ "blake2s256",
+ "id-rsassa-pkcs1-v1_5-with-sha3-224",
+ "id-rsassa-pkcs1-v1_5-with-sha3-256",
+ "id-rsassa-pkcs1-v1_5-with-sha3-384",
+ "id-rsassa-pkcs1-v1_5-with-sha3-512",
"md5",
+ "md5-sha1",
+ "md5WithRSAEncryption",
+ "ripemd",
"ripemd160",
+ "ripemd160WithRSA",
+ "rmd160",
"sha1",
+ "sha1WithRSAEncryption",
"sha224",
+ "sha224WithRSAEncryption",
"sha256",
- "sha384",
- "sha512",
- "sha512-224",
- "sha512-256",
+ "sha256WithRSAEncryption",
"sha3-224",
"sha3-256",
"sha3-384",
"sha3-512",
+ "sha384",
+ "sha384WithRSAEncryption",
+ "sha512",
+ "sha512-224",
+ "sha512-224WithRSAEncryption",
+ "sha512-256",
+ "sha512-256WithRSAEncryption",
+ "sha512WithRSAEncryption",
"shake128",
"shake256",
"sm3",
+ "sm3WithRSAEncryption",
+ "ssl3-md5",
+ "ssl3-sha1",
]
}
}
diff --git a/ext/node/ops/crypto/md5_sha1.rs b/ext/node/ops/crypto/md5_sha1.rs
new file mode 100644
index 000000000..9164b0a1c
--- /dev/null
+++ b/ext/node/ops/crypto/md5_sha1.rs
@@ -0,0 +1,99 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+use core::fmt;
+use digest::core_api::AlgorithmName;
+use digest::core_api::BlockSizeUser;
+use digest::core_api::Buffer;
+use digest::core_api::BufferKindUser;
+use digest::core_api::CoreWrapper;
+use digest::core_api::FixedOutputCore;
+use digest::core_api::OutputSizeUser;
+use digest::core_api::UpdateCore;
+use digest::HashMarker;
+use digest::Output;
+use digest::Reset;
+
+pub type Md5Sha1 = CoreWrapper<Md5Sha1Core>;
+
+pub struct Md5Sha1Core {
+ md5: md5::Md5Core,
+ sha1: sha1::Sha1Core,
+}
+
+impl HashMarker for Md5Sha1Core {}
+
+impl BlockSizeUser for Md5Sha1Core {
+ type BlockSize = sec1::consts::U64;
+}
+
+impl BufferKindUser for Md5Sha1Core {
+ type BufferKind = digest::block_buffer::Eager;
+}
+
+impl OutputSizeUser for Md5Sha1Core {
+ type OutputSize = sec1::consts::U36;
+}
+
+impl UpdateCore for Md5Sha1Core {
+ #[inline]
+ fn update_blocks(&mut self, blocks: &[digest::core_api::Block<Self>]) {
+ self.md5.update_blocks(blocks);
+ self.sha1.update_blocks(blocks);
+ }
+}
+
+impl FixedOutputCore for Md5Sha1Core {
+ #[inline]
+ fn finalize_fixed_core(
+ &mut self,
+ buffer: &mut Buffer<Self>,
+ out: &mut Output<Self>,
+ ) {
+ let mut md5_output = Output::<md5::Md5Core>::default();
+ self
+ .md5
+ .finalize_fixed_core(&mut buffer.clone(), &mut md5_output);
+ let mut sha1_output = Output::<sha1::Sha1Core>::default();
+ self.sha1.finalize_fixed_core(buffer, &mut sha1_output);
+ out[..16].copy_from_slice(&md5_output);
+ out[16..].copy_from_slice(&sha1_output);
+ }
+}
+
+impl Default for Md5Sha1Core {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ md5: Default::default(),
+ sha1: Default::default(),
+ }
+ }
+}
+
+impl Clone for Md5Sha1Core {
+ #[inline]
+ fn clone(&self) -> Self {
+ Self {
+ md5: self.md5.clone(),
+ sha1: self.sha1.clone(),
+ }
+ }
+}
+
+impl Reset for Md5Sha1Core {
+ #[inline]
+ fn reset(&mut self) {
+ *self = Default::default();
+ }
+}
+
+impl AlgorithmName for Md5Sha1Core {
+ fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("Md5Sha1")
+ }
+}
+
+impl fmt::Debug for Md5Sha1Core {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("Md5Sha1Core { ... }")
+ }
+}
diff --git a/ext/node/ops/crypto/mod.rs b/ext/node/ops/crypto/mod.rs
index 8ded3420a..1b545e024 100644
--- a/ext/node/ops/crypto/mod.rs
+++ b/ext/node/ops/crypto/mod.rs
@@ -46,9 +46,13 @@ use spki::EncodePublicKey;
mod cipher;
mod dh;
mod digest;
+mod md5_sha1;
mod primes;
pub mod x509;
+use self::digest::match_fixed_digest_with_eager_block_buffer;
+use self::digest::match_fixed_digest_with_oid;
+
#[op2(fast)]
pub fn op_node_check_prime(
#[bigint] num: i64,
@@ -382,33 +386,30 @@ pub fn op_node_sign(
RSA_ENCRYPTION_OID => {
use rsa::pkcs1v15::SigningKey;
let key = RsaPrivateKey::from_pkcs1_der(pkey)?;
- Ok(
- match digest_type {
- "sha224" => {
- let signing_key = SigningKey::<sha2::Sha224>::new(key);
- signing_key.sign_prehash(digest)?.to_vec()
- }
- "sha256" => {
- let signing_key = SigningKey::<sha2::Sha256>::new(key);
- signing_key.sign_prehash(digest)?.to_vec()
- }
- "sha384" => {
- let signing_key = SigningKey::<sha2::Sha384>::new(key);
- signing_key.sign_prehash(digest)?.to_vec()
- }
- "sha512" => {
- let signing_key = SigningKey::<sha2::Sha512>::new(key);
- signing_key.sign_prehash(digest)?.to_vec()
- }
- _ => {
- return Err(type_error(format!(
- "Unknown digest algorithm: {}",
- digest_type
- )))
- }
+
+ // md5-sha1 is special, because it's not wrapped in an ASN.1 DigestInfo
+ // (so has no prefix).
+ // See https://github.com/openssl/openssl/blob/af82623d32962b3eff5b0f0b0dedec5eb730b231/crypto/rsa/rsa_sign.c#L285
+ if digest_type == "md5-sha1" {
+ let signing_key = SigningKey::<md5_sha1::Md5Sha1>::new_unprefixed(key);
+ let signature = signing_key.sign_prehash(digest)?.to_vec();
+ return Ok(signature.into());
+ }
+
+ let signature = match_fixed_digest_with_oid!(
+ digest_type,
+ fn <D>() {
+ let signing_key = SigningKey::<D>::new(key);
+ signing_key.sign_prehash(digest)?.to_vec()
+ },
+ _ => {
+ return Err(type_error(format!(
+ "digest not allowed for RSA signature: {}",
+ digest_type
+ )))
}
- .into(),
- )
+ );
+ Ok(signature.into())
}
// signature structure encoding is DER by default for DSA and ECDSA.
//
@@ -456,29 +457,35 @@ pub fn op_node_verify(
)))
}
};
- Ok(match digest_type {
- "sha224" => VerifyingKey::<sha2::Sha224>::new(key)
- .verify_prehash(digest, &signature.try_into()?)
- .is_ok(),
- "sha256" => VerifyingKey::<sha2::Sha256>::new(key)
- .verify_prehash(digest, &signature.try_into()?)
- .is_ok(),
- "sha384" => VerifyingKey::<sha2::Sha384>::new(key)
- .verify_prehash(digest, &signature.try_into()?)
- .is_ok(),
- "sha512" => VerifyingKey::<sha2::Sha512>::new(key)
+
+ // md5-sha1 is special, because it's not wrapped in an ASN.1 DigestInfo
+ // (so has no prefix).
+ // See https://github.com/openssl/openssl/blob/af82623d32962b3eff5b0f0b0dedec5eb730b231/crypto/rsa/rsa_sign.c#L285
+ if digest_type == "md5-sha1" {
+ let verifying_key =
+ VerifyingKey::<md5_sha1::Md5Sha1>::new_unprefixed(key);
+ let verified = verifying_key
.verify_prehash(digest, &signature.try_into()?)
- .is_ok(),
+ .is_ok();
+ return Ok(verified);
+ }
+
+ Ok(match_fixed_digest_with_oid!(
+ digest_type,
+ fn <D>() {
+ let verifying_key = VerifyingKey::<D>::new(key);
+ verifying_key.verify_prehash(digest, &signature.try_into()?).is_ok()
+ },
_ => {
return Err(type_error(format!(
- "Unknown digest algorithm: {}",
+ "digest not allowed for RSA signature: {}",
digest_type
)))
}
- })
+ ))
}
_ => Err(type_error(format!(
- "Verifying with {} keys is not supported yet",
+ "Verifying with {} keys is not supported",
key_type
))),
}
@@ -488,28 +495,22 @@ fn pbkdf2_sync(
password: &[u8],
salt: &[u8],
iterations: u32,
- digest: &str,
+ algorithm_name: &str,
derived_key: &mut [u8],
) -> Result<(), AnyError> {
- macro_rules! pbkdf2_hmac {
- ($digest:ty) => {{
- pbkdf2::pbkdf2_hmac::<$digest>(password, salt, iterations, derived_key)
- }};
- }
-
- match digest {
- "md4" => pbkdf2_hmac!(md4::Md4),
- "md5" => pbkdf2_hmac!(md5::Md5),
- "ripemd160" => pbkdf2_hmac!(ripemd::Ripemd160),
- "sha1" => pbkdf2_hmac!(sha1::Sha1),
- "sha224" => pbkdf2_hmac!(sha2::Sha224),
- "sha256" => pbkdf2_hmac!(sha2::Sha256),
- "sha384" => pbkdf2_hmac!(sha2::Sha384),
- "sha512" => pbkdf2_hmac!(sha2::Sha512),
- _ => return Err(type_error("Unknown digest")),
- }
-
- Ok(())
+ match_fixed_digest_with_eager_block_buffer!(
+ algorithm_name,
+ fn <D>() {
+ pbkdf2::pbkdf2_hmac::<D>(password, salt, iterations, derived_key);
+ Ok(())
+ },
+ _ => {
+ Err(type_error(format!(
+ "unsupported digest: {}",
+ algorithm_name
+ )))
+ }
+ )
}
#[op2]
@@ -558,50 +559,40 @@ pub async fn op_node_generate_secret_async(#[smi] len: i32) -> ToJsBuffer {
}
fn hkdf_sync(
- hash: &str,
+ digest_algorithm: &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);
+ match_fixed_digest_with_eager_block_buffer!(
+ digest_algorithm,
+ fn <D>() {
+ let hk = Hkdf::<D>::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(())
+ .map_err(|_| type_error("HKDF-Expand failed"))
+ },
+ _ => {
+ Err(type_error(format!("Unsupported digest: {}", digest_algorithm)))
+ }
+ )
}
#[op2(fast)]
pub fn op_node_hkdf(
- #[string] hash: &str,
+ #[string] digest_algorithm: &str,
#[buffer] ikm: &[u8],
#[buffer] salt: &[u8],
#[buffer] info: &[u8],
#[buffer] okm: &mut [u8],
) -> Result<(), AnyError> {
- hkdf_sync(hash, ikm, salt, info, okm)
+ hkdf_sync(digest_algorithm, ikm, salt, info, okm)
}
#[op2(async)]
#[serde]
pub async fn op_node_hkdf_async(
- #[string] hash: String,
+ #[string] digest_algorithm: String,
#[buffer] ikm: JsBuffer,
#[buffer] salt: JsBuffer,
#[buffer] info: JsBuffer,
@@ -609,7 +600,7 @@ pub async fn op_node_hkdf_async(
) -> Result<ToJsBuffer, AnyError> {
spawn_blocking(move || {
let mut okm = vec![0u8; okm_len];
- hkdf_sync(&hash, &ikm, &salt, &info, &mut okm)?;
+ hkdf_sync(&digest_algorithm, &ikm, &salt, &info, &mut okm)?;
Ok(okm.into())
})
.await?
diff --git a/ext/node/polyfills/internal/crypto/hkdf.ts b/ext/node/polyfills/internal/crypto/hkdf.ts
index 0a8dcbb2e..cca40a3c6 100644
--- a/ext/node/polyfills/internal/crypto/hkdf.ts
+++ b/ext/node/polyfills/internal/crypto/hkdf.ts
@@ -23,6 +23,7 @@ import {
} from "ext:deno_node/internal/crypto/util.ts";
import {
createSecretKey,
+ getKeyMaterial,
isKeyObject,
KeyObject,
} from "ext:deno_node/internal/crypto/keys.ts";
@@ -35,7 +36,7 @@ import {
const validateParameters = hideStackFrames((hash, key, salt, info, length) => {
validateString(hash, "digest");
- key = new Uint8Array(prepareKey(key));
+ key = getKeyMaterial(prepareKey(key));
validateByteSource(salt, "salt");
validateByteSource(info, "info");
@@ -108,6 +109,8 @@ export function hkdf(
validateFunction(callback, "callback");
+ hash = hash.toLowerCase();
+
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));
@@ -128,6 +131,8 @@ export function hkdfSync(
length,
));
+ hash = hash.toLowerCase();
+
const okm = new Uint8Array(length);
try {
op_node_hkdf(hash, key, salt, info, okm);
diff --git a/ext/node/polyfills/internal/crypto/pbkdf2.ts b/ext/node/polyfills/internal/crypto/pbkdf2.ts
index 5cf102fa9..4e58cb68b 100644
--- a/ext/node/polyfills/internal/crypto/pbkdf2.ts
+++ b/ext/node/polyfills/internal/crypto/pbkdf2.ts
@@ -7,8 +7,19 @@ import { op_node_pbkdf2, op_node_pbkdf2_async } from "ext:core/ops";
import { Buffer } from "node:buffer";
import { HASH_DATA } from "ext:deno_node/internal/crypto/types.ts";
+import {
+ validateFunction,
+ validateString,
+ validateUint32,
+} from "ext:deno_node/internal/validators.mjs";
+import { getArrayBufferOrView } from "ext:deno_node/internal/crypto/keys.ts";
+import {
+ ERR_CRYPTO_INVALID_DIGEST,
+ ERR_OUT_OF_RANGE,
+} from "ext:deno_node/internal/errors.ts";
export const MAX_ALLOC = Math.pow(2, 30) - 1;
+export const MAX_I32 = 2 ** 31 - 1;
export type NormalizedAlgorithms =
| "md5"
@@ -29,6 +40,30 @@ export type Algorithms =
| "sha384"
| "sha512";
+function check(
+ password: HASH_DATA,
+ salt: HASH_DATA,
+ iterations: number,
+ keylen: number,
+ digest: string,
+) {
+ validateString(digest, "digest");
+ password = getArrayBufferOrView(password, "password", "buffer");
+ salt = getArrayBufferOrView(salt, "salt", "buffer");
+ validateUint32(iterations, "iterations", true);
+ validateUint32(keylen, "keylen");
+
+ if (iterations > MAX_I32) {
+ throw new ERR_OUT_OF_RANGE("iterations", `<= ${MAX_I32}`, iterations);
+ }
+
+ if (keylen > MAX_I32) {
+ throw new ERR_OUT_OF_RANGE("keylen", `<= ${MAX_I32}`, keylen);
+ }
+
+ return { password, salt, iterations, keylen, digest };
+}
+
/**
* @param iterations Needs to be higher or equal than zero
* @param keylen Needs to be higher or equal than zero but less than max allocation size (2^30)
@@ -39,18 +74,21 @@ export function pbkdf2Sync(
salt: HASH_DATA,
iterations: number,
keylen: number,
- digest: Algorithms = "sha1",
+ digest: string,
): Buffer {
- if (typeof iterations !== "number" || iterations < 0) {
- throw new TypeError("Bad iterations");
- }
- if (typeof keylen !== "number" || keylen < 0 || keylen > MAX_ALLOC) {
- throw new TypeError("Bad key length");
- }
+ ({ password, salt, iterations, keylen, digest } = check(
+ password,
+ salt,
+ iterations,
+ keylen,
+ digest,
+ ));
+
+ digest = digest.toLowerCase() as NormalizedAlgorithms;
const DK = new Uint8Array(keylen);
if (!op_node_pbkdf2(password, salt, iterations, digest, DK)) {
- throw new Error("Invalid digest");
+ throw new ERR_CRYPTO_INVALID_DIGEST(digest);
}
return Buffer.from(DK);
@@ -66,16 +104,26 @@ export function pbkdf2(
salt: HASH_DATA,
iterations: number,
keylen: number,
- digest: Algorithms = "sha1",
+ digest: string,
callback: (err: Error | null, derivedKey?: Buffer) => void,
) {
- if (typeof iterations !== "number" || iterations < 0) {
- throw new TypeError("Bad iterations");
- }
- if (typeof keylen !== "number" || keylen < 0 || keylen > MAX_ALLOC) {
- throw new TypeError("Bad key length");
+ if (typeof digest === "function") {
+ callback = digest;
+ digest = undefined as unknown as string;
}
+ ({ password, salt, iterations, keylen, digest } = check(
+ password,
+ salt,
+ iterations,
+ keylen,
+ digest,
+ ));
+
+ validateFunction(callback, "callback");
+
+ digest = digest.toLowerCase() as NormalizedAlgorithms;
+
op_node_pbkdf2_async(
password,
salt,
diff --git a/ext/node/polyfills/internal/crypto/sig.ts b/ext/node/polyfills/internal/crypto/sig.ts
index 5a9611780..473670d2a 100644
--- a/ext/node/polyfills/internal/crypto/sig.ts
+++ b/ext/node/polyfills/internal/crypto/sig.ts
@@ -67,10 +67,6 @@ export class SignImpl extends Writable {
algorithm = algorithm.toLowerCase();
- if (algorithm.startsWith("rsa-")) {
- // Allows RSA-[digest_algorithm] as a valid algorithm
- algorithm = algorithm.slice(4);
- }
this.#digestType = algorithm;
this.hash = createHash(this.#digestType);
}
@@ -121,11 +117,6 @@ export class VerifyImpl extends Writable {
algorithm = algorithm.toLowerCase();
- if (algorithm.startsWith("rsa-")) {
- // Allows RSA-[digest_algorithm] as a valid algorithm
- algorithm = algorithm.slice(4);
- }
-
this.#digestType = algorithm;
this.hash = createHash(this.#digestType);
}
diff --git a/ext/node/polyfills/internal/crypto/types.ts b/ext/node/polyfills/internal/crypto/types.ts
index 2b3ce34fe..45c0ea286 100644
--- a/ext/node/polyfills/internal/crypto/types.ts
+++ b/ext/node/polyfills/internal/crypto/types.ts
@@ -3,7 +3,7 @@
import { Buffer } from "../../buffer.ts";
-export type HASH_DATA = string | ArrayBufferView | Buffer;
+export type HASH_DATA = string | ArrayBufferView | Buffer | ArrayBuffer;
export type BinaryToTextEncoding = "base64" | "base64url" | "hex" | "binary";
diff --git a/tests/integration/node_unit_tests.rs b/tests/integration/node_unit_tests.rs
index d0b6d1fbd..15d2021c1 100644
--- a/tests/integration/node_unit_tests.rs
+++ b/tests/integration/node_unit_tests.rs
@@ -57,11 +57,14 @@ util::unit_test_factory!(
buffer_test,
child_process_test,
console_test,
- crypto_cipher_test = crypto / crypto_cipher_test,
crypto_cipher_gcm_test = crypto / crypto_cipher_gcm_test,
+ crypto_cipher_test = crypto / crypto_cipher_test,
crypto_hash_test = crypto / crypto_hash_test,
+ crypto_hkdf_test = crypto / crypto_hkdf_test,
crypto_key_test = crypto / crypto_key_test,
crypto_misc_test = crypto / crypto_misc_test,
+ crypto_pbkdf2_test = crypto / crypto_pbkdf2_test,
+ crypto_scrypt_test = crypto / crypto_scrypt_test,
crypto_sign_test = crypto / crypto_sign_test,
events_test,
dgram_test,
@@ -72,8 +75,6 @@ util::unit_test_factory!(
_randomBytes_test = internal / _randomBytes_test,
_randomFill_test = internal / _randomFill_test,
_randomInt_test = internal / _randomInt_test,
- pbkdf2_test = internal / pbkdf2_test,
- scrypt_test = internal / scrypt_test,
module_test,
net_test,
os_test,
diff --git a/tests/node_compat/config.jsonc b/tests/node_compat/config.jsonc
index 5c0c854a8..f0b667df4 100644
--- a/tests/node_compat/config.jsonc
+++ b/tests/node_compat/config.jsonc
@@ -52,6 +52,7 @@
"test-crypto-dh.js",
"test-crypto-hkdf.js",
"test-crypto-hmac.js",
+ "test-crypto-pbkdf2.js",
"test-crypto-prime.js",
"test-crypto-stream.js",
"test-crypto-x509.js",
@@ -257,6 +258,7 @@
"test-crypto-hash.js",
"test-crypto-hkdf.js",
"test-crypto-hmac.js",
+ "test-crypto-pbkdf2.js",
"test-crypto-prime.js",
"test-crypto-secret-keygen.js",
"test-crypto-stream.js",
diff --git a/tests/node_compat/runner/TODO.md b/tests/node_compat/runner/TODO.md
index a36ad1b63..ec2a2337e 100644
--- a/tests/node_compat/runner/TODO.md
+++ b/tests/node_compat/runner/TODO.md
@@ -505,7 +505,6 @@ NOTE: This file should not be manually edited. Please edit `tests/node_compat/co
- [parallel/test-crypto-op-during-process-exit.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-op-during-process-exit.js)
- [parallel/test-crypto-padding-aes256.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-padding-aes256.js)
- [parallel/test-crypto-padding.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-padding.js)
-- [parallel/test-crypto-pbkdf2.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-pbkdf2.js)
- [parallel/test-crypto-private-decrypt-gh32240.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-private-decrypt-gh32240.js)
- [parallel/test-crypto-psychic-signatures.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-psychic-signatures.js)
- [parallel/test-crypto-publicDecrypt-fails-first-time.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-publicDecrypt-fails-first-time.js)
diff --git a/tests/node_compat/test/parallel/test-crypto-pbkdf2.js b/tests/node_compat/test/parallel/test-crypto-pbkdf2.js
new file mode 100644
index 000000000..263f73130
--- /dev/null
+++ b/tests/node_compat/test/parallel/test-crypto-pbkdf2.js
@@ -0,0 +1,251 @@
+// deno-fmt-ignore-file
+// deno-lint-ignore-file
+
+// Copyright Joyent and Node contributors. All rights reserved. MIT license.
+// Taken from Node 18.12.1
+// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
+
+'use strict';
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const crypto = require('crypto');
+
+function runPBKDF2(password, salt, iterations, keylen, hash) {
+ const syncResult =
+ crypto.pbkdf2Sync(password, salt, iterations, keylen, hash);
+
+ crypto.pbkdf2(password, salt, iterations, keylen, hash,
+ common.mustSucceed((asyncResult) => {
+ assert.deepStrictEqual(asyncResult, syncResult);
+ }));
+
+ return syncResult;
+}
+
+function testPBKDF2(password, salt, iterations, keylen, expected, encoding) {
+ const actual = runPBKDF2(password, salt, iterations, keylen, 'sha256');
+ assert.strictEqual(actual.toString(encoding || 'latin1'), expected);
+}
+
+//
+// Test PBKDF2 with RFC 6070 test vectors (except #4)
+//
+
+testPBKDF2('password', 'salt', 1, 20,
+ '\x12\x0f\xb6\xcf\xfc\xf8\xb3\x2c\x43\xe7\x22\x52' +
+ '\x56\xc4\xf8\x37\xa8\x65\x48\xc9');
+
+testPBKDF2('password', 'salt', 2, 20,
+ '\xae\x4d\x0c\x95\xaf\x6b\x46\xd3\x2d\x0a\xdf\xf9' +
+ '\x28\xf0\x6d\xd0\x2a\x30\x3f\x8e');
+
+testPBKDF2('password', 'salt', 4096, 20,
+ '\xc5\xe4\x78\xd5\x92\x88\xc8\x41\xaa\x53\x0d\xb6' +
+ '\x84\x5c\x4c\x8d\x96\x28\x93\xa0');
+
+testPBKDF2('passwordPASSWORDpassword',
+ 'saltSALTsaltSALTsaltSALTsaltSALTsalt',
+ 4096,
+ 25,
+ '\x34\x8c\x89\xdb\xcb\xd3\x2b\x2f\x32\xd8\x14\xb8\x11' +
+ '\x6e\x84\xcf\x2b\x17\x34\x7e\xbc\x18\x00\x18\x1c');
+
+testPBKDF2('pass\0word', 'sa\0lt', 4096, 16,
+ '\x89\xb6\x9d\x05\x16\xf8\x29\x89\x3c\x69\x62\x26\x65' +
+ '\x0a\x86\x87');
+
+testPBKDF2('password', 'salt', 32, 32,
+ '64c486c55d30d4c5a079b8823b7d7cb37ff0556f537da8410233bcec330ed956',
+ 'hex');
+
+// Error path should not leak memory (check with valgrind).
+assert.throws(
+ () => crypto.pbkdf2('password', 'salt', 1, 20, 'sha1'),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError'
+ }
+);
+
+for (const iterations of [-1, 0, 2147483648]) {
+ assert.throws(
+ () => crypto.pbkdf2Sync('password', 'salt', iterations, 20, 'sha1'),
+ {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ }
+ );
+}
+
+['str', null, undefined, [], {}].forEach((notNumber) => {
+ assert.throws(
+ () => {
+ crypto.pbkdf2Sync('password', 'salt', 1, notNumber, 'sha256');
+ }, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "keylen" argument must be of type number.' +
+ `${common.invalidArgTypeHelper(notNumber)}`
+ });
+});
+
+[Infinity, -Infinity, NaN].forEach((input) => {
+ assert.throws(
+ () => {
+ crypto.pbkdf2('password', 'salt', 1, input, 'sha256',
+ common.mustNotCall());
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ message: 'The value of "keylen" is out of range. It ' +
+ `must be an integer. Received ${input}`
+ });
+});
+
+[-1, 2147483648, 4294967296].forEach((input) => {
+ assert.throws(
+ () => {
+ crypto.pbkdf2('password', 'salt', 1, input, 'sha256',
+ common.mustNotCall());
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ name: 'RangeError',
+ });
+});
+
+// Should not get FATAL ERROR with empty password and salt
+// https://github.com/nodejs/node/issues/8571
+crypto.pbkdf2('', '', 1, 32, 'sha256', common.mustSucceed());
+
+assert.throws(
+ () => crypto.pbkdf2('password', 'salt', 8, 8, common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "digest" argument must be of type string. ' +
+ 'Received undefined'
+ });
+
+assert.throws(
+ () => crypto.pbkdf2Sync('password', 'salt', 8, 8),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "digest" argument must be of type string. ' +
+ 'Received undefined'
+ });
+
+assert.throws(
+ () => crypto.pbkdf2Sync('password', 'salt', 8, 8, null),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: 'The "digest" argument must be of type string. ' +
+ 'Received null'
+ });
+[1, {}, [], true, undefined, null].forEach((input) => {
+ assert.throws(
+ () => crypto.pbkdf2(input, 'salt', 8, 8, 'sha256', common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ }
+ );
+
+ assert.throws(
+ () => crypto.pbkdf2('pass', input, 8, 8, 'sha256', common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ }
+ );
+
+ assert.throws(
+ () => crypto.pbkdf2Sync(input, 'salt', 8, 8, 'sha256'),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ }
+ );
+
+ assert.throws(
+ () => crypto.pbkdf2Sync('pass', input, 8, 8, 'sha256'),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ }
+ );
+});
+
+['test', {}, [], true, undefined, null].forEach((i) => {
+ const received = common.invalidArgTypeHelper(i);
+ assert.throws(
+ () => crypto.pbkdf2('pass', 'salt', i, 8, 'sha256', common.mustNotCall()),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: `The "iterations" argument must be of type number.${received}`
+ }
+ );
+
+ assert.throws(
+ () => crypto.pbkdf2Sync('pass', 'salt', i, 8, 'sha256'),
+ {
+ code: 'ERR_INVALID_ARG_TYPE',
+ name: 'TypeError',
+ message: `The "iterations" argument must be of type number.${received}`
+ }
+ );
+});
+
+// Any TypedArray should work for password and salt.
+// TODO(@lucacasonato): SharedArrayBuffer is not supported
+for (const SomeArray of [Uint8Array, Uint16Array, Uint32Array, Float32Array,
+ Float64Array, ArrayBuffer/*, SharedArrayBuffer*/]) {
+ runPBKDF2(new SomeArray(10), 'salt', 8, 8, 'sha256');
+ runPBKDF2('pass', new SomeArray(10), 8, 8, 'sha256');
+}
+
+// TODO(@lucacasonato): we throw this asynchronously
+// assert.throws(
+// () => crypto.pbkdf2('pass', 'salt', 8, 8, 'md55', common.mustNotCall()),
+// {
+// code: 'ERR_CRYPTO_INVALID_DIGEST',
+// name: 'TypeError',
+// message: 'Invalid digest: md55'
+// }
+// );
+
+assert.throws(
+ () => crypto.pbkdf2Sync('pass', 'salt', 8, 8, 'md55'),
+ {
+ code: 'ERR_CRYPTO_INVALID_DIGEST',
+ name: 'TypeError',
+ message: 'Invalid digest: md55'
+ }
+);
+
+if (!common.hasOpenSSL3) {
+ // TODO(@lucacasonato): we don't support blake2b512 and blake2s256
+ const kNotPBKDF2Supported = ['shake128', 'shake256', 'blake2b512', 'blake2s256'];
+ crypto.getHashes()
+ .filter((hash) => !kNotPBKDF2Supported.includes(hash))
+ .forEach((hash) => {
+ runPBKDF2(new Uint8Array(10), 'salt', 8, 8, hash);
+ });
+}
+
+{
+ // This should not crash.
+ assert.throws(
+ () => crypto.pbkdf2Sync('1', '2', 1, 1, '%'),
+ {
+ code: 'ERR_CRYPTO_INVALID_DIGEST',
+ name: 'TypeError',
+ message: 'Invalid digest: %'
+ }
+ );
+}
diff --git a/tests/unit_node/crypto/crypto_hkdf_test.ts b/tests/unit_node/crypto/crypto_hkdf_test.ts
new file mode 100644
index 000000000..be5d99086
--- /dev/null
+++ b/tests/unit_node/crypto/crypto_hkdf_test.ts
@@ -0,0 +1,36 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+import { hkdfSync } from "node:crypto";
+import { assertEquals } from "@std/assert/mod.ts";
+import { Buffer } from "node:buffer";
+import nodeFixtures from "../testdata/crypto_digest_fixtures.json" with {
+ type: "json",
+};
+
+Deno.test("crypto.hkdfSync - compare with node", async (t) => {
+ const DATA = "Hello, world!";
+ const SALT = "salt";
+ const INFO = "info";
+ const KEY_LEN = 64;
+
+ for (const { digest, hkdf } of nodeFixtures) {
+ await t.step({
+ name: digest,
+ ignore: digest.includes("blake"),
+ fn() {
+ let actual: string | null;
+ try {
+ actual = Buffer.from(hkdfSync(
+ digest,
+ DATA,
+ SALT,
+ INFO,
+ KEY_LEN,
+ )).toString("hex");
+ } catch {
+ actual = null;
+ }
+ assertEquals(actual, hkdf);
+ },
+ });
+ }
+});
diff --git a/tests/unit_node/internal/pbkdf2_test.ts b/tests/unit_node/crypto/crypto_pbkdf2_test.ts
index 6a428b037..8ace870cb 100644
--- a/tests/unit_node/internal/pbkdf2_test.ts
+++ b/tests/unit_node/crypto/crypto_pbkdf2_test.ts
@@ -1,6 +1,9 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { pbkdf2, pbkdf2Sync } from "node:crypto";
import { assert, assertEquals } from "@std/assert/mod.ts";
+import nodeFixtures from "../testdata/crypto_digest_fixtures.json" with {
+ type: "json",
+};
type Algorithms =
| "md5"
@@ -377,6 +380,35 @@ Deno.test("pbkdf2Sync hashes data correctly", () => {
});
});
+Deno.test("crypto.pbkdf2Sync - compare with node", async (t) => {
+ const DATA = "Hello, world!";
+ const SALT = "salt";
+ const ITERATIONS = 1000;
+ const KEY_LEN = 64;
+
+ for (const { digest, pkdf2 } of nodeFixtures) {
+ await t.step({
+ name: digest,
+ ignore: digest.includes("blake"),
+ fn() {
+ let actual: string | null;
+ try {
+ actual = pbkdf2Sync(
+ DATA,
+ SALT,
+ ITERATIONS,
+ KEY_LEN,
+ digest as Algorithms,
+ ).toString("hex");
+ } catch {
+ actual = null;
+ }
+ assertEquals(actual, pkdf2);
+ },
+ });
+ }
+});
+
// TODO(@littledivy): assertCallbackErrorUncaught exits for async operations on the thread pool.
// Deno.test("[std/node/crypto] pbkdf2 callback isn't called twice if error is thrown", async () => {
// const importUrl = new URL("node:crypto", import.meta.url);
diff --git a/tests/unit_node/internal/scrypt_test.ts b/tests/unit_node/crypto/crypto_scrypt_test.ts
index c128abb92..c128abb92 100644
--- a/tests/unit_node/internal/scrypt_test.ts
+++ b/tests/unit_node/crypto/crypto_scrypt_test.ts
diff --git a/tests/unit_node/crypto/crypto_sign_test.ts b/tests/unit_node/crypto/crypto_sign_test.ts
index 2ca0af943..77c5caf75 100644
--- a/tests/unit_node/crypto/crypto_sign_test.ts
+++ b/tests/unit_node/crypto/crypto_sign_test.ts
@@ -3,6 +3,9 @@
import { assert, assertEquals } from "@std/testing/asserts.ts";
import { createSign, createVerify, sign, verify } from "node:crypto";
import { Buffer } from "node:buffer";
+import fixtures from "../testdata/crypto_digest_fixtures.json" with {
+ type: "json",
+};
const rsaPrivatePem = Buffer.from(
await Deno.readFile(
@@ -138,3 +141,41 @@ AwEH
createSign("SHA256").update("test").sign(pem, "base64");
},
});
+
+Deno.test("crypto.createSign|sign - compare with node", async (t) => {
+ const DATA = "Hello, world!";
+ const privateKey = Deno.readTextFileSync(
+ new URL(import.meta.resolve("../testdata/rsa_private.pem")),
+ );
+ for (const { digest, signature } of fixtures) {
+ await t.step(digest, () => {
+ let actual: string | null;
+ try {
+ const s = createSign(digest);
+ s.update(DATA);
+ actual = s.sign(privateKey).toString("hex");
+ } catch {
+ actual = null;
+ }
+ assertEquals(actual, signature);
+ });
+ }
+});
+
+Deno.test("crypto.createVerify|verify - compare with node", async (t) => {
+ const DATA = "Hello, world!";
+ const publicKey = Deno.readTextFileSync(
+ new URL(import.meta.resolve("../testdata/rsa_public.pem")),
+ );
+ for (const { digest, signature } of fixtures) {
+ await t.step({
+ name: digest,
+ ignore: signature === null,
+ fn: () => {
+ const s = createVerify(digest);
+ s.update(DATA);
+ s.verify(publicKey, signature!);
+ },
+ });
+ }
+});
diff --git a/tests/unit_node/crypto/generate_fixture.mjs b/tests/unit_node/crypto/generate_fixture.mjs
new file mode 100644
index 000000000..3724fe4af
--- /dev/null
+++ b/tests/unit_node/crypto/generate_fixture.mjs
@@ -0,0 +1,69 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+// Run this file with `node` to regenerate the testdata/crypto_digest_fixtures.json file.
+
+import { readFileSync, writeFileSync } from "node:fs";
+import { join } from "node:path";
+import crypto from "node:crypto";
+import { Buffer } from "node:buffer";
+
+const privateKey = readFileSync(
+ join(import.meta.dirname, "..", "testdata", "rsa_private.pem"),
+);
+
+const fixtures = [];
+
+const DATA = "Hello, world!";
+const SALT = "salt";
+const INFO = "info";
+const ITERATIONS = 1000;
+const KEY_LEN = 64;
+
+for (const digest of crypto.getHashes()) {
+ const hasher = crypto.createHash(digest);
+ hasher.update(DATA);
+ let hash;
+ try {
+ hash = hasher.digest().toString("hex");
+ } catch {
+ hash = null;
+ }
+
+ const sign = crypto.createSign(digest);
+ sign.update(DATA);
+ let signature;
+ try {
+ signature = sign.sign(privateKey).toString("hex");
+ } catch {
+ signature = null;
+ }
+
+ let pkdf2;
+ try {
+ pkdf2 = crypto.pbkdf2Sync(DATA, SALT, ITERATIONS, KEY_LEN, digest).toString(
+ "hex",
+ );
+ } catch {
+ pkdf2 = null;
+ }
+
+ let hkdf;
+ try {
+ hkdf = Buffer.from(crypto.hkdfSync(digest, DATA, SALT, INFO, KEY_LEN))
+ .toString("hex");
+ } catch {
+ hkdf = null;
+ }
+
+ fixtures.push({
+ digest,
+ hash,
+ signature,
+ pkdf2,
+ hkdf,
+ });
+}
+
+writeFileSync(
+ join(import.meta.dirname, "..", "testdata", "crypto_digest_fixtures.json"),
+ JSON.stringify(fixtures, null, 2),
+);
diff --git a/tests/unit_node/testdata/crypto_digest_fixtures.json b/tests/unit_node/testdata/crypto_digest_fixtures.json
new file mode 100644
index 000000000..c5b65261d
--- /dev/null
+++ b/tests/unit_node/testdata/crypto_digest_fixtures.json
@@ -0,0 +1,366 @@
+[
+ {
+ "digest": "RSA-MD5",
+ "hash": "6cd3556deb0da54bca060b4c39479839",
+ "signature": "45f2e7ac7c0d323c18e9c8554d15e21a8fb72944928e0b7acc2185402448c39af05340391ee9aac64c45a947bc3ed801de8791aaa5788a62e909d7c8d92e63c7f119753219a48c29ea78e371d3a89c0bd64d756b829fa6faaa8fa46bc28228dd4430aca845c02f3b6b835b140247838ac5b96434d1049115785f3f52034e0cc46f6cafc5f2921b9928403aea1edd85f3a99e12324abeeaaaa040b320f8af157c5df7fd7479415771fd116daed933b43eac51b3c274ba9283aaf3f1b6f1f527a0cea76f9a43dca3b9ff03834feed13a0fd488e6750a9d46ddb1ad69ac88090af050458eeafd1e9fa317c4ecc61d90289d5378e6e3693ef6da2e4a4803b6108145",
+ "pkdf2": "3083f052ca2e90daf96a87b8b8c1daa069bff60c73045c9504d3b424807b5410a724ea5ba28b9bccb6bad59c0e181663b07156a59b09cee85ffe223f21ff6db6",
+ "hkdf": "f516674e1b1faf2c1a505041634460d94739e2e39be4e6a097f926f5cc9788c09892efcb407019dc469c4014c8d847cf4c5a6eeefccf8e5266ca3dd02ea57529"
+ },
+ {
+ "digest": "RSA-RIPEMD160",
+ "hash": "58262d1fbdbe4530d8865d3518c6d6e41002610f",
+ "signature": "31b25b680d0df8cb27df71c38fe7931a185c056b98c072a4f4956d6105a44ed53d7e457d366074cc26cd1cd0c226cf0cac509264f42651c208eb73f29f48dc2022009595e4ccf97662cf2840d69987f51118e9854fd10497a9e1dcb2ef390c9d09767f7d801aa2dd3d5c0e51249a195769593696725ba81e9a6c961a4b2c13827c467ccafa76f0ea5a9f43b936f3b35a8c316f116e0ac0d6f56ed8c0189d28ea1dc3a56b97a75c8f5c5cdc1682a76b5d852dd7282371ecb379abf0864eff0c437fca813d0ddc1ce34e8327a604336eeab6d907edf39e0303f0b8a45e0721e15d85c8c329047920b1ec8863bc6c0b172a57a6bb3611edb1f5c4d49aa1089cb5fd",
+ "pkdf2": "2473b58bc86761bd5e8d35153475d44e8ba2dd4a156d6e69d79cbc33244f35bfea27bb3122354d98dbd792c679d8994f10a8eaf7c946e6a65566413a13060386",
+ "hkdf": "c7d8a2fe1ae6d243aef0b989c2483221f0e9c3234719273438dca33b97269435047f441ae104903fafaa051267ab34ba469449511a8e40fc5444a01e03cfe651"
+ },
+ {
+ "digest": "RSA-SHA1",
+ "hash": "943a702d06f34599aee1f8da8ef9f7296031d699",
+ "signature": "80174b0678707d38335940a010bd6acc1a6ade2c911251d013875816eb4c5169d9d4cb2ac9f6ce4b29b92f5750f185a273abd7c8a2434a9d1a50df5311999655d2a535c77b79997ed34fe51a863c450251d1b85bbb4dd10da1162e6e74194af606579a8724e55b93bded2d10216bb63cf00e848ceea6cdba78eab4f735ca620b36fdfd19bf15706df860a4c589160ce3c32aa51c27561de82a00cdcca709045cb8622adb6f759eb5e0f2f3f6056ca1b1a91206712ce92f5684d64931bc001bec7d2e8d2469f0818106070698160e9e21404971ea45940797fa3a61a39a25b7c6c75986accd4832db50a25ef3fceca629e104e2f03affd83b94cf074614e11c18",
+ "pkdf2": "e77df42e685bd1fe2e19e374e1dd8470df71182311e048a6a280f36ef24c661e46fe8e8cc763942615934a631ac3aeda24bb9fda71e04f89f0c85f2f762abd98",
+ "hkdf": "936c59e9394b5b1fdc26bd2eec0dc8c8d52fb97198e021805f0ae58c3f8b631d0020002b1ce0df9d890377fcc808166c906f128d06d77d404061d56560f3340d"
+ },
+ {
+ "digest": "RSA-SHA1-2",
+ "hash": "943a702d06f34599aee1f8da8ef9f7296031d699",
+ "signature": "80174b0678707d38335940a010bd6acc1a6ade2c911251d013875816eb4c5169d9d4cb2ac9f6ce4b29b92f5750f185a273abd7c8a2434a9d1a50df5311999655d2a535c77b79997ed34fe51a863c450251d1b85bbb4dd10da1162e6e74194af606579a8724e55b93bded2d10216bb63cf00e848ceea6cdba78eab4f735ca620b36fdfd19bf15706df860a4c589160ce3c32aa51c27561de82a00cdcca709045cb8622adb6f759eb5e0f2f3f6056ca1b1a91206712ce92f5684d64931bc001bec7d2e8d2469f0818106070698160e9e21404971ea45940797fa3a61a39a25b7c6c75986accd4832db50a25ef3fceca629e104e2f03affd83b94cf074614e11c18",
+ "pkdf2": "e77df42e685bd1fe2e19e374e1dd8470df71182311e048a6a280f36ef24c661e46fe8e8cc763942615934a631ac3aeda24bb9fda71e04f89f0c85f2f762abd98",
+ "hkdf": "936c59e9394b5b1fdc26bd2eec0dc8c8d52fb97198e021805f0ae58c3f8b631d0020002b1ce0df9d890377fcc808166c906f128d06d77d404061d56560f3340d"
+ },
+ {
+ "digest": "RSA-SHA224",
+ "hash": "8552d8b7a7dc5476cb9e25dee69a8091290764b7f2a64fe6e78e9568",
+ "signature": "70a8b455d63d2af5b12b0eefcb50ae245dcac054a74fd8a5beccca5ed12fd545e4dcdf2da3455f49e5eaf559772dc885ae24fd9e42790a1e175ec221a22329f2cc67d5c8ad1f9377fa1d713cb0d554f8335325a6080c272c10fb59f5fb7da9b39dcc76a50b49ed5f28d8cdd0499fbf5a19cae4b5b4a4a103201933a0e94e5532c6aaf05fbb060a3be5dcd5addef23b80651c51831ee479142cb1ddac0a37c6251f6eceee55217fcced2462fb7bef3e3aeeda98672598dc6aca6a49fb2df1b3f0ac569b666afeb8ca3f5b1bfa0bcca49f5fe6d3784fba1bb931077633d5a0a731c2bb22a820c8497ac1db888bd542f73ba2358d3a9bc056a7eca2f3a78b437820",
+ "pkdf2": "d3adee1df932bac56eecdba710702025678d6e024d315c925ae274a3796c474219291983a76f2b8bd67aad26fbebcf5bb5088c99b6124ae1b9c7c9b2eb37c8f4",
+ "hkdf": "1c3a0bd11a8c71c010353b075474aa2a6740f5cade0fff895019e08ebdaa68f8dfc4e74a5e013e2e9e0ab6852884311c1dac89432d34b2f762113ebf9a37597a"
+ },
+ {
+ "digest": "RSA-SHA256",
+ "hash": "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3",
+ "signature": "67b67a87fc4a576342fc46167395a255654dddc5036e8a7d323acf862470e0612b90b1abf22166e3d124d4866e82146b5735fb85895355d027efdcb406a8cb87c8f00aea128e74cb95ca8a69cb970e3f02a11a6911253f9fba54ae7b75d7f1f29d51338d43f4ed59a36e3b7e408591cd9feaa818f1b0c6df6155cc89cc95c6686ce82a78fd8d34e82d9047ce936c3a67ac85d2924083610d6db5040409f09a46f97d35248b5451ca51be6cfbc9f94ff630eb8ff95e114a666cc1cc011af03d77f9b24f8add5244a83e0784dbcf785ebcfcd015b876963666b113dc26f0222aa95fdfbe1e64ac6b48780e1ff69b2588ff4bce9b15f9d53abba96b813a3d657cbe",
+ "pkdf2": "a8a2a7dcf7b65c8498ab1fbc62d56fa47255d668c1c3f21c5b236259d1dd8b11859026e737216cceb7a8facb8d27656f2b990db98786f12a8ce68e56a30f0c0b",
+ "hkdf": "a35a5ba99add2c508b9014ca7eb7d461a85989257b29a46a0041361c85b2c48838199873987b5419ede395aa09129bcb5fbd607b8b769e6711e1fea5e0ebcbc0"
+ },
+ {
+ "digest": "RSA-SHA3-224",
+ "hash": "6a33e22f20f16642697e8bd549ff7b759252ad56c05a1b0acc31dc69",
+ "signature": "2504c7a4735c251aa01644ae56a9f7c891f45e9fb6e25fea1c25074139dcab114e77d64ae7788bcbd8d5d452db60b47e6a0b324b0e3482ff794581da0cbe960a97ba75c1023eab2320fa9022ae715b5aa2fe1186916fb9a1c931d9f28ba8e12a4dd145efff6abfcfb68eca6536655c96cf059df406d5c51d1814b2f61c6bdc10a2b083d29f50a064bc6ffdddf5cb45df2577a7149a430e1314f87427972d8bb4775bd92e99a2298095cb83e60e50f503aab6d9fd41398b55d5dcfa6022049891561e6395a7a3e56a1d92a8667733a68d9b0374952d95e4d5a51b0b22d390cf579bb536e59cea8272b2d5749fa70d48c396b6ba94188ce677beb8f00937640096",
+ "pkdf2": "014d30aa9d1c1d8e3920f4bcc399f37b16d6c346d570d4345229d64ab95e504b1c6b253133c218a2b46f29aa0f9792d7ad60761159cc3550cb9a0914bfdc9951",
+ "hkdf": "b6c671ec02ee7f215dcee9ecade623831658470156f3edab205b7e3a70587f3c538eac8ec92e3a5bf6808b9b939d84e4f8ba5ee3532d7adb152211cc8f79cf9b"
+ },
+ {
+ "digest": "RSA-SHA3-256",
+ "hash": "f345a219da005ebe9c1a1eaad97bbf38a10c8473e41d0af7fb617caa0c6aa722",
+ "signature": "b3b475d03da73b4bf8fefa5f49231dfd8f95605e0c3ea058d4607f1274ddcf4f69b1751df8493df1c5fe31883aff197688de1991885bb9ed4266f7df0db4fc99b33bee32a9237a9c2714e461fefb311923c1e91fe7cbe1830206bb0b3d962bfccdf5c37e8ce9e01f203851e34f22162175f44048002483ff2e3ffc658506a23f358f3192dbba759a8e1f66d3abf934b72295f1b51f8a92c837c76006084b65c0df8e072e43b1122bb15b3043dceb026e2cf311d04d6f4a3506e7e5b8a08fcaa0caeaa18a6397d185e5b5d1bc962f22b80db798a42fa206cd2db53b02bc5e2e69d9566f1ff3fccb4690545ff19424001cf3c0504c53adc0f2ce4354596b8a4d69",
+ "pkdf2": "4ba48814e191c34c9d38f5ccf6c5cf1a61082c2f8b36e99bd8210781af995734f62c6a714ad6639ecb55224d91b2ac7d69030335d2c367d833823814ef9f2213",
+ "hkdf": "e60f1e8214b7907d63d8cfb2bfb083051d3c9a56e4f94aabc1ff3543986aac5d4823db903090af81824964d6ca39da8388495e8838a9c0c407cb3546f44f9a04"
+ },
+ {
+ "digest": "RSA-SHA3-384",
+ "hash": "6ba9ea268965916f5937228dde678c202f9fe756a87d8b1b7362869583a45901fd1a27289d72fc0e3ff48b1b78827d3a",
+ "signature": "256542ac61773cec2261fbc8cde4d6524e7a91f9fefcc08792c7c4b27fb843d099a5fce9819503949ad8fde307a7fc4185754dc5ed3d473da065376e4a9c804265dc4ff858a774d6eb19e663a26339d087a3e96b8f9133becc0ee2b404cfcfca58ffadbd48a5c31dced92f188b40bd179efdf9ae5394d0e02b513958f46adbdf745e8dada0dd97e38bf28bf7ad87aeb6771a40e3fef5f35161d4eeafe7b6ba1c2101388a22e75586fab599cbc070bf4d0fbe8304a7c579a34ce0000c87b33882c2d86ff11dbc218604fa7e7203e4efaa6e9605ae41958c0c2de0b7d76da9a6e606b3c38d29dad55675f9f138b11afc96e71ba5e41924bc5c676db777aed7ea04",
+ "pkdf2": "f609fda1c21cf4e59e7142438f2e04bb29f72010d49546e1c192755c6af3b97903da8483be8356afb865ffc334d23fa2439063c287ec9491618bfb5f791675f4",
+ "hkdf": "818ae5bc92cf582db87d73316e1a0649b457dfcd198db3e4edb1c6b20515dcf14f8758951765d9e2b4f7914a75ea04815e82050a6ca602c1a76f6c9999813955"
+ },
+ {
+ "digest": "RSA-SHA3-512",
+ "hash": "8e47f1185ffd014d238fabd02a1a32defe698cbf38c037a90e3c0a0a32370fb52cbd641250508502295fcabcbf676c09470b27443868c8e5f70e26dc337288af",
+ "signature": "925bd1da0c91caba58c0a407f4f63e9b16f52444c3b71476f4043ee00ef97bb428a396e8a45d75b3204142d2e18886f36b0b0a1c6d25d80b010e4063ffb310741907e3217badadaf53d018100d78eace2e941c0ec2b6f9b47ceee455d55bfb1711b1255ae1fa0d8fb5bf869009c1b558b02fd4cabd83c55a76a1d96bdb4cdbb42f6ad1f36984c39e6c6fe4edc3a771766742ec461d29e8a93704a48323c0c0f9cc066bf1daeb4e83aa3aa7a3c2067495cf320a9e98b7f1db638a23fc135992fcc3bbfb52be115c35b055cdbf4733c30098674ff19f1ef218a4643b0e2ecb7c0597a406b304b67a36eed0300313a65a4af5621ef59a5ffe53e7d6763a83e0014a",
+ "pkdf2": "e1f0b454bf5d729fbb13e534229521a87aee130078555791d83834a8c51fb681ce4dfe02afd5f063082d8abba0b456084c677aeb6f8e0d70305322ec2ea97203",
+ "hkdf": "f27d87f9f6b87718073c8d2ad6bae00b4162cecde350c856252dd611120c433373a0c0d3946a8582bf855bf581439a14ca4f355fcd18881331f4a3b1027e84b2"
+ },
+ {
+ "digest": "RSA-SHA384",
+ "hash": "55bc556b0d2fe0fce582ba5fe07baafff035653638c7ac0d5494c2a64c0bea1cc57331c7c12a45cdbca7f4c34a089eeb",
+ "signature": "77d465006b8843cf30c5e93b7d3f63b0daf2df1d693c4e1c0f9c759ec8410c088f331c5bf89bca7218edd1bdf3f2d948c9be9656f44a630748395429a09289acb05be80b0d000bacd7826c33a584dcbcf658839015d07561668e882bad4505c475a04766a7eabb35b15b8b54d6fcf9ebdd25b699f0d88906ba2999de1e8e59cc75969bc819fd514b1002a6667a03c861fafee03cccb9fd926352139dc1a916ba56b36e9e69fd328cb2403b9f747350721261158021df9ab2a75a7c5a3e39b42f3722ea1997a039ecc033f64366974336dbfd3294820400fe623d2993593c51f4398290a51bf05dc452c5991e26e8971be759472635e86b08230d04d05bce88f4",
+ "pkdf2": "b2e2b9e03d9e6f5218b74be7002c8704558feae855272ab3a973ee7deb387c26483f87fb6463bc5768406b398896a29ac2d17bd45afccf369a403ffa396bb455",
+ "hkdf": "54aef7f7256a147e52d67888a4543c6084b4ac46cd7bf919576bf8c4e9dad6b8a1fc9ad9c6f90f2af8e76d8d815ae2226d67a11ccb524a0c0be3cc858f4ddb10"
+ },
+ {
+ "digest": "RSA-SHA512",
+ "hash": "c1527cd893c124773d811911970c8fe6e857d6df5dc9226bd8a160614c0cd963a4ddea2b94bb7d36021ef9d865d5cea294a82dd49a0bb269f51f6e7a57f79421",
+ "signature": "50e2973977e1be1218134a1f50732a8f54c4b0dfb836be816c304edce9bef4b1be566a295b05c6c82de00eb915bc61ca4bab073a13061987ca19af280202a4c6c496cf6262655e6a6f1a53f923ca048b4bc21e31282edd239cec8840b2411c1aa2abe5b9bf7de5066f43f6e2e0a0691ac6f2fc71ed679ae644b6d799261ed694dc9e27c81142ffb88883440ee92a6086d7c3d62572eac13480034219a9edbda7e5556f335bbe1a37ef0df26ae3ffe99b968d40a93d9ca9a3c76025409b5da041242afa977a5a0438be946562a48a764dc6d4c924fec82590e01b807d410a432b95ee2e5173d245a565cdecdc321521d6f61e965628013181bc7a9462a450d895",
+ "pkdf2": "284f17da4e32b7b4780b31f94405e115ca7e6ae025b05d8398f421c3a3f36d903a1fae9471674342bec7d51c6f32996df0c843a20105c8451e9cd17ecbddb3ed",
+ "hkdf": "cf181757f66abf44c88cd3d4ad0ed99b82cf47a8a6f870ff1561a12da7af03251590250af7473a1a3c5c5e794f29c44e8f25f69fb7985258161e74b433510262"
+ },
+ {
+ "digest": "RSA-SHA512/224",
+ "hash": "32620068b859669b45b31008e08b7384649ad2ca3f5163a3a71e5745",
+ "signature": "b5d1ec54de69d29dbc77595fec62bb16019b7cc275ead04338c17ee4b759fcb8443477e1708d45374b786acfeb616c1078d199b2a28d76f46d4b74a498c2bfb2b174632da895cae5558f36101f0596adb40152ac09b49f1726f293237bcf604ab7bf461c7e2dd78c909d7503ec4132722551842f7e8ef54317f4b58784c447fd68067c689c288c8401dc95276356e1396a127eac82a0bd0753cc4c00718e7240d523af95a1cd960885da64172e3325a225557f96e6307340dd45a499ac20af01a2e3e7a4be706a40249c6ce7e24dabdcbd577744c34cf8e182d9a7923c52cd508a0e39125003a0c74ac714f5c892187c6fc7417d552127b3c24c57e484212ab6",
+ "pkdf2": "69e623258a79c04b84aabc9333b17fc8a5ee8d7ebd06dd80236865584ccc98fce3180319f74748f6a6c2b44833425a6ab52e8ab22db62365799f14727102485d",
+ "hkdf": "c155ac0b2833f309322f258625df2c9926570fabbe66eff9713b977291054b57b8cd3280079613d8167a99f259087422cff9756780148bf683c1d5c03e015907"
+ },
+ {
+ "digest": "RSA-SHA512/256",
+ "hash": "330c723f25267587db0b9f493463e017011239169cb57a6db216c63774367115",
+ "signature": "6313742057ecbf4f54476799b018d1e18c2db920ef23386208f1e23e5af30d38edc0d11f1220e2cc0f898cd3e4cd9d4920fed30ff9f725404d4750f230fe9dafdfde95280a8713043359a09d45fbda484c469e61ae4fd615d616e76f6daa27acd3542d823e88f2dfd943b39f38884f9ed4695b8f004b4c67777de63474fe9dbbfeab966113907663f14c7822658aab70dceb7d1a6ed9842085762ab100ee915941295a045b29ef09af19eab58c79d3e5ffcbda61e2be35770c1d3b55156357c3cca806309b1ddc7e52f47e245d1d49237f0aa7156e89c76a17780a62fa552eeb7b623410e387d0a9412d4688725ed8df0a86e8b548ea6bb785ea48b6c0e39332",
+ "pkdf2": "c3d18f17c825a1630bc10695bfd4faa0309e862d010c0b74fb41b6ce5e46853cc435560a1b9cd940254103068aebc1f24d2580385b1890e7f10356ef4c8f507d",
+ "hkdf": "8451f1238da8577794ecc9b75832cabff44f279e5f8258cbf553c21f9735c19c7974e9a74879b4c59386116bb1a4bb50f149c9a4146b10de312fa679c1343b80"
+ },
+ {
+ "digest": "RSA-SM3",
+ "hash": "e3bca101b496880c3653dad85861d0e784b00a8c18f7574472d156060e9096bf",
+ "signature": null,
+ "pkdf2": "70b3d2ac3b82dd7b8c35db45f99f49e029be2b6f1ef9ce1d9137267b729c06f7099dc7f571f2b05dbe5172118a7ae787cd4836fbf9ddce9aacc933c7c4e5537b",
+ "hkdf": "88b773032a2f131b1aa4ebdb69fdde7c42281b7c689bfe1f5bd43c7e1a6f555f101657c3f83ccd5918b4c6a8df04d0b58ebf77ec2181f8c5e7cfecb6f13fba61"
+ },
+ {
+ "digest": "blake2b512",
+ "hash": "a2764d133a16816b5847a737a786f2ece4c148095c5faa73e24b4cc5d666c3e45ec271504e14dc6127ddfce4e144fb23b91a6f7b04b53d695502290722953b0f",
+ "signature": null,
+ "pkdf2": "ae8782ec9a457cf51606ac8cfc97c4c5f9fe2485714f7be7fddfddf02c7bb9c977ebea731b17ec2a7cf197e91be085dbce87392e53f548ac7c14e28876c9a271",
+ "hkdf": "65c9a327ea321c4e5beab11527862dee68b39349c909652d4e796f88ba5ede82011d6c17996c7f90c71ea1003244b0e845d02e0a852f5e08add5cea53ae21d7f"
+ },
+ {
+ "digest": "blake2s256",
+ "hash": "30d8777f0e178582ec8cd2fcdc18af57c828ee2f89e978df52c8e7af078bd5cf",
+ "signature": null,
+ "pkdf2": "242e2926b524dd35a4684b4300a6e0e219b58ad1513847a3ac731f08696b5491d6b3a14146864fcc1d292c85908fe364267670c9a680bbe8117bf3b2519efee9",
+ "hkdf": "f17e4306bf70cbd74e7d16595eab65178a7d6545ff3a8d78800ea69697e6c360f24bafe2772ff80fb1a4381bb69c3f98c39033f246f86521609a4dda95b7a1d7"
+ },
+ {
+ "digest": "id-rsassa-pkcs1-v1_5-with-sha3-224",
+ "hash": "6a33e22f20f16642697e8bd549ff7b759252ad56c05a1b0acc31dc69",
+ "signature": "2504c7a4735c251aa01644ae56a9f7c891f45e9fb6e25fea1c25074139dcab114e77d64ae7788bcbd8d5d452db60b47e6a0b324b0e3482ff794581da0cbe960a97ba75c1023eab2320fa9022ae715b5aa2fe1186916fb9a1c931d9f28ba8e12a4dd145efff6abfcfb68eca6536655c96cf059df406d5c51d1814b2f61c6bdc10a2b083d29f50a064bc6ffdddf5cb45df2577a7149a430e1314f87427972d8bb4775bd92e99a2298095cb83e60e50f503aab6d9fd41398b55d5dcfa6022049891561e6395a7a3e56a1d92a8667733a68d9b0374952d95e4d5a51b0b22d390cf579bb536e59cea8272b2d5749fa70d48c396b6ba94188ce677beb8f00937640096",
+ "pkdf2": "014d30aa9d1c1d8e3920f4bcc399f37b16d6c346d570d4345229d64ab95e504b1c6b253133c218a2b46f29aa0f9792d7ad60761159cc3550cb9a0914bfdc9951",
+ "hkdf": "b6c671ec02ee7f215dcee9ecade623831658470156f3edab205b7e3a70587f3c538eac8ec92e3a5bf6808b9b939d84e4f8ba5ee3532d7adb152211cc8f79cf9b"
+ },
+ {
+ "digest": "id-rsassa-pkcs1-v1_5-with-sha3-256",
+ "hash": "f345a219da005ebe9c1a1eaad97bbf38a10c8473e41d0af7fb617caa0c6aa722",
+ "signature": "b3b475d03da73b4bf8fefa5f49231dfd8f95605e0c3ea058d4607f1274ddcf4f69b1751df8493df1c5fe31883aff197688de1991885bb9ed4266f7df0db4fc99b33bee32a9237a9c2714e461fefb311923c1e91fe7cbe1830206bb0b3d962bfccdf5c37e8ce9e01f203851e34f22162175f44048002483ff2e3ffc658506a23f358f3192dbba759a8e1f66d3abf934b72295f1b51f8a92c837c76006084b65c0df8e072e43b1122bb15b3043dceb026e2cf311d04d6f4a3506e7e5b8a08fcaa0caeaa18a6397d185e5b5d1bc962f22b80db798a42fa206cd2db53b02bc5e2e69d9566f1ff3fccb4690545ff19424001cf3c0504c53adc0f2ce4354596b8a4d69",
+ "pkdf2": "4ba48814e191c34c9d38f5ccf6c5cf1a61082c2f8b36e99bd8210781af995734f62c6a714ad6639ecb55224d91b2ac7d69030335d2c367d833823814ef9f2213",
+ "hkdf": "e60f1e8214b7907d63d8cfb2bfb083051d3c9a56e4f94aabc1ff3543986aac5d4823db903090af81824964d6ca39da8388495e8838a9c0c407cb3546f44f9a04"
+ },
+ {
+ "digest": "id-rsassa-pkcs1-v1_5-with-sha3-384",
+ "hash": "6ba9ea268965916f5937228dde678c202f9fe756a87d8b1b7362869583a45901fd1a27289d72fc0e3ff48b1b78827d3a",
+ "signature": "256542ac61773cec2261fbc8cde4d6524e7a91f9fefcc08792c7c4b27fb843d099a5fce9819503949ad8fde307a7fc4185754dc5ed3d473da065376e4a9c804265dc4ff858a774d6eb19e663a26339d087a3e96b8f9133becc0ee2b404cfcfca58ffadbd48a5c31dced92f188b40bd179efdf9ae5394d0e02b513958f46adbdf745e8dada0dd97e38bf28bf7ad87aeb6771a40e3fef5f35161d4eeafe7b6ba1c2101388a22e75586fab599cbc070bf4d0fbe8304a7c579a34ce0000c87b33882c2d86ff11dbc218604fa7e7203e4efaa6e9605ae41958c0c2de0b7d76da9a6e606b3c38d29dad55675f9f138b11afc96e71ba5e41924bc5c676db777aed7ea04",
+ "pkdf2": "f609fda1c21cf4e59e7142438f2e04bb29f72010d49546e1c192755c6af3b97903da8483be8356afb865ffc334d23fa2439063c287ec9491618bfb5f791675f4",
+ "hkdf": "818ae5bc92cf582db87d73316e1a0649b457dfcd198db3e4edb1c6b20515dcf14f8758951765d9e2b4f7914a75ea04815e82050a6ca602c1a76f6c9999813955"
+ },
+ {
+ "digest": "id-rsassa-pkcs1-v1_5-with-sha3-512",
+ "hash": "8e47f1185ffd014d238fabd02a1a32defe698cbf38c037a90e3c0a0a32370fb52cbd641250508502295fcabcbf676c09470b27443868c8e5f70e26dc337288af",
+ "signature": "925bd1da0c91caba58c0a407f4f63e9b16f52444c3b71476f4043ee00ef97bb428a396e8a45d75b3204142d2e18886f36b0b0a1c6d25d80b010e4063ffb310741907e3217badadaf53d018100d78eace2e941c0ec2b6f9b47ceee455d55bfb1711b1255ae1fa0d8fb5bf869009c1b558b02fd4cabd83c55a76a1d96bdb4cdbb42f6ad1f36984c39e6c6fe4edc3a771766742ec461d29e8a93704a48323c0c0f9cc066bf1daeb4e83aa3aa7a3c2067495cf320a9e98b7f1db638a23fc135992fcc3bbfb52be115c35b055cdbf4733c30098674ff19f1ef218a4643b0e2ecb7c0597a406b304b67a36eed0300313a65a4af5621ef59a5ffe53e7d6763a83e0014a",
+ "pkdf2": "e1f0b454bf5d729fbb13e534229521a87aee130078555791d83834a8c51fb681ce4dfe02afd5f063082d8abba0b456084c677aeb6f8e0d70305322ec2ea97203",
+ "hkdf": "f27d87f9f6b87718073c8d2ad6bae00b4162cecde350c856252dd611120c433373a0c0d3946a8582bf855bf581439a14ca4f355fcd18881331f4a3b1027e84b2"
+ },
+ {
+ "digest": "md5",
+ "hash": "6cd3556deb0da54bca060b4c39479839",
+ "signature": "45f2e7ac7c0d323c18e9c8554d15e21a8fb72944928e0b7acc2185402448c39af05340391ee9aac64c45a947bc3ed801de8791aaa5788a62e909d7c8d92e63c7f119753219a48c29ea78e371d3a89c0bd64d756b829fa6faaa8fa46bc28228dd4430aca845c02f3b6b835b140247838ac5b96434d1049115785f3f52034e0cc46f6cafc5f2921b9928403aea1edd85f3a99e12324abeeaaaa040b320f8af157c5df7fd7479415771fd116daed933b43eac51b3c274ba9283aaf3f1b6f1f527a0cea76f9a43dca3b9ff03834feed13a0fd488e6750a9d46ddb1ad69ac88090af050458eeafd1e9fa317c4ecc61d90289d5378e6e3693ef6da2e4a4803b6108145",
+ "pkdf2": "3083f052ca2e90daf96a87b8b8c1daa069bff60c73045c9504d3b424807b5410a724ea5ba28b9bccb6bad59c0e181663b07156a59b09cee85ffe223f21ff6db6",
+ "hkdf": "f516674e1b1faf2c1a505041634460d94739e2e39be4e6a097f926f5cc9788c09892efcb407019dc469c4014c8d847cf4c5a6eeefccf8e5266ca3dd02ea57529"
+ },
+ {
+ "digest": "md5-sha1",
+ "hash": "6cd3556deb0da54bca060b4c39479839943a702d06f34599aee1f8da8ef9f7296031d699",
+ "signature": "1b8bddcb86fca178c4318ff04be6956fc92815b54b38d7cd5c0c12be1b3c2b5defc960d9fc162d0f2e8eddeb075cb5b751c89d2e7550d50e1939f89c5c96bd7c4b8ad16fd02f5295f9806f275b0959f9fa226131c6996e64ce5f2595729036967762070033e40c3b7f63c8567158ce78143332a00669a0c4126b80c7ba9bdcf61e03eda99fddb9ea779a4038e87d6615d166e9b88272cb91de68126bbf505764feebd68b526358a0cf46526aea26566907763a5250f9169d1e6e674cc37fe5feb20f2a87b9251383829ad33d5bc1fbf78f87c625703b68a4f30e9a31b248a5d094d712cf5c8ca1394fe9a9d8800b5d90b0f51f4b2e547287239a210504807d8a",
+ "pkdf2": "4d8d010a2ab473080923a782f8d497d2be83c3dd78b3da755754ab098f4b9d629e583f343fabc938ab0cce8bdaa5ad4c515d10fc9c0ce416e5752a9060bb9831",
+ "hkdf": "9265d75fdd9ef3609109d7703c75773d02175d68376422f4078bede7e3ac4f024a6b0e28333e316c276d6bb6f1177f8300490bf78c98f20ba8e6d2f287515b56"
+ },
+ {
+ "digest": "md5WithRSAEncryption",
+ "hash": "6cd3556deb0da54bca060b4c39479839",
+ "signature": "45f2e7ac7c0d323c18e9c8554d15e21a8fb72944928e0b7acc2185402448c39af05340391ee9aac64c45a947bc3ed801de8791aaa5788a62e909d7c8d92e63c7f119753219a48c29ea78e371d3a89c0bd64d756b829fa6faaa8fa46bc28228dd4430aca845c02f3b6b835b140247838ac5b96434d1049115785f3f52034e0cc46f6cafc5f2921b9928403aea1edd85f3a99e12324abeeaaaa040b320f8af157c5df7fd7479415771fd116daed933b43eac51b3c274ba9283aaf3f1b6f1f527a0cea76f9a43dca3b9ff03834feed13a0fd488e6750a9d46ddb1ad69ac88090af050458eeafd1e9fa317c4ecc61d90289d5378e6e3693ef6da2e4a4803b6108145",
+ "pkdf2": "3083f052ca2e90daf96a87b8b8c1daa069bff60c73045c9504d3b424807b5410a724ea5ba28b9bccb6bad59c0e181663b07156a59b09cee85ffe223f21ff6db6",
+ "hkdf": "f516674e1b1faf2c1a505041634460d94739e2e39be4e6a097f926f5cc9788c09892efcb407019dc469c4014c8d847cf4c5a6eeefccf8e5266ca3dd02ea57529"
+ },
+ {
+ "digest": "ripemd",
+ "hash": "58262d1fbdbe4530d8865d3518c6d6e41002610f",
+ "signature": "31b25b680d0df8cb27df71c38fe7931a185c056b98c072a4f4956d6105a44ed53d7e457d366074cc26cd1cd0c226cf0cac509264f42651c208eb73f29f48dc2022009595e4ccf97662cf2840d69987f51118e9854fd10497a9e1dcb2ef390c9d09767f7d801aa2dd3d5c0e51249a195769593696725ba81e9a6c961a4b2c13827c467ccafa76f0ea5a9f43b936f3b35a8c316f116e0ac0d6f56ed8c0189d28ea1dc3a56b97a75c8f5c5cdc1682a76b5d852dd7282371ecb379abf0864eff0c437fca813d0ddc1ce34e8327a604336eeab6d907edf39e0303f0b8a45e0721e15d85c8c329047920b1ec8863bc6c0b172a57a6bb3611edb1f5c4d49aa1089cb5fd",
+ "pkdf2": "2473b58bc86761bd5e8d35153475d44e8ba2dd4a156d6e69d79cbc33244f35bfea27bb3122354d98dbd792c679d8994f10a8eaf7c946e6a65566413a13060386",
+ "hkdf": "c7d8a2fe1ae6d243aef0b989c2483221f0e9c3234719273438dca33b97269435047f441ae104903fafaa051267ab34ba469449511a8e40fc5444a01e03cfe651"
+ },
+ {
+ "digest": "ripemd160",
+ "hash": "58262d1fbdbe4530d8865d3518c6d6e41002610f",
+ "signature": "31b25b680d0df8cb27df71c38fe7931a185c056b98c072a4f4956d6105a44ed53d7e457d366074cc26cd1cd0c226cf0cac509264f42651c208eb73f29f48dc2022009595e4ccf97662cf2840d69987f51118e9854fd10497a9e1dcb2ef390c9d09767f7d801aa2dd3d5c0e51249a195769593696725ba81e9a6c961a4b2c13827c467ccafa76f0ea5a9f43b936f3b35a8c316f116e0ac0d6f56ed8c0189d28ea1dc3a56b97a75c8f5c5cdc1682a76b5d852dd7282371ecb379abf0864eff0c437fca813d0ddc1ce34e8327a604336eeab6d907edf39e0303f0b8a45e0721e15d85c8c329047920b1ec8863bc6c0b172a57a6bb3611edb1f5c4d49aa1089cb5fd",
+ "pkdf2": "2473b58bc86761bd5e8d35153475d44e8ba2dd4a156d6e69d79cbc33244f35bfea27bb3122354d98dbd792c679d8994f10a8eaf7c946e6a65566413a13060386",
+ "hkdf": "c7d8a2fe1ae6d243aef0b989c2483221f0e9c3234719273438dca33b97269435047f441ae104903fafaa051267ab34ba469449511a8e40fc5444a01e03cfe651"
+ },
+ {
+ "digest": "ripemd160WithRSA",
+ "hash": "58262d1fbdbe4530d8865d3518c6d6e41002610f",
+ "signature": "31b25b680d0df8cb27df71c38fe7931a185c056b98c072a4f4956d6105a44ed53d7e457d366074cc26cd1cd0c226cf0cac509264f42651c208eb73f29f48dc2022009595e4ccf97662cf2840d69987f51118e9854fd10497a9e1dcb2ef390c9d09767f7d801aa2dd3d5c0e51249a195769593696725ba81e9a6c961a4b2c13827c467ccafa76f0ea5a9f43b936f3b35a8c316f116e0ac0d6f56ed8c0189d28ea1dc3a56b97a75c8f5c5cdc1682a76b5d852dd7282371ecb379abf0864eff0c437fca813d0ddc1ce34e8327a604336eeab6d907edf39e0303f0b8a45e0721e15d85c8c329047920b1ec8863bc6c0b172a57a6bb3611edb1f5c4d49aa1089cb5fd",
+ "pkdf2": "2473b58bc86761bd5e8d35153475d44e8ba2dd4a156d6e69d79cbc33244f35bfea27bb3122354d98dbd792c679d8994f10a8eaf7c946e6a65566413a13060386",
+ "hkdf": "c7d8a2fe1ae6d243aef0b989c2483221f0e9c3234719273438dca33b97269435047f441ae104903fafaa051267ab34ba469449511a8e40fc5444a01e03cfe651"
+ },
+ {
+ "digest": "rmd160",
+ "hash": "58262d1fbdbe4530d8865d3518c6d6e41002610f",
+ "signature": "31b25b680d0df8cb27df71c38fe7931a185c056b98c072a4f4956d6105a44ed53d7e457d366074cc26cd1cd0c226cf0cac509264f42651c208eb73f29f48dc2022009595e4ccf97662cf2840d69987f51118e9854fd10497a9e1dcb2ef390c9d09767f7d801aa2dd3d5c0e51249a195769593696725ba81e9a6c961a4b2c13827c467ccafa76f0ea5a9f43b936f3b35a8c316f116e0ac0d6f56ed8c0189d28ea1dc3a56b97a75c8f5c5cdc1682a76b5d852dd7282371ecb379abf0864eff0c437fca813d0ddc1ce34e8327a604336eeab6d907edf39e0303f0b8a45e0721e15d85c8c329047920b1ec8863bc6c0b172a57a6bb3611edb1f5c4d49aa1089cb5fd",
+ "pkdf2": "2473b58bc86761bd5e8d35153475d44e8ba2dd4a156d6e69d79cbc33244f35bfea27bb3122354d98dbd792c679d8994f10a8eaf7c946e6a65566413a13060386",
+ "hkdf": "c7d8a2fe1ae6d243aef0b989c2483221f0e9c3234719273438dca33b97269435047f441ae104903fafaa051267ab34ba469449511a8e40fc5444a01e03cfe651"
+ },
+ {
+ "digest": "sha1",
+ "hash": "943a702d06f34599aee1f8da8ef9f7296031d699",
+ "signature": "80174b0678707d38335940a010bd6acc1a6ade2c911251d013875816eb4c5169d9d4cb2ac9f6ce4b29b92f5750f185a273abd7c8a2434a9d1a50df5311999655d2a535c77b79997ed34fe51a863c450251d1b85bbb4dd10da1162e6e74194af606579a8724e55b93bded2d10216bb63cf00e848ceea6cdba78eab4f735ca620b36fdfd19bf15706df860a4c589160ce3c32aa51c27561de82a00cdcca709045cb8622adb6f759eb5e0f2f3f6056ca1b1a91206712ce92f5684d64931bc001bec7d2e8d2469f0818106070698160e9e21404971ea45940797fa3a61a39a25b7c6c75986accd4832db50a25ef3fceca629e104e2f03affd83b94cf074614e11c18",
+ "pkdf2": "e77df42e685bd1fe2e19e374e1dd8470df71182311e048a6a280f36ef24c661e46fe8e8cc763942615934a631ac3aeda24bb9fda71e04f89f0c85f2f762abd98",
+ "hkdf": "936c59e9394b5b1fdc26bd2eec0dc8c8d52fb97198e021805f0ae58c3f8b631d0020002b1ce0df9d890377fcc808166c906f128d06d77d404061d56560f3340d"
+ },
+ {
+ "digest": "sha1WithRSAEncryption",
+ "hash": "943a702d06f34599aee1f8da8ef9f7296031d699",
+ "signature": "80174b0678707d38335940a010bd6acc1a6ade2c911251d013875816eb4c5169d9d4cb2ac9f6ce4b29b92f5750f185a273abd7c8a2434a9d1a50df5311999655d2a535c77b79997ed34fe51a863c450251d1b85bbb4dd10da1162e6e74194af606579a8724e55b93bded2d10216bb63cf00e848ceea6cdba78eab4f735ca620b36fdfd19bf15706df860a4c589160ce3c32aa51c27561de82a00cdcca709045cb8622adb6f759eb5e0f2f3f6056ca1b1a91206712ce92f5684d64931bc001bec7d2e8d2469f0818106070698160e9e21404971ea45940797fa3a61a39a25b7c6c75986accd4832db50a25ef3fceca629e104e2f03affd83b94cf074614e11c18",
+ "pkdf2": "e77df42e685bd1fe2e19e374e1dd8470df71182311e048a6a280f36ef24c661e46fe8e8cc763942615934a631ac3aeda24bb9fda71e04f89f0c85f2f762abd98",
+ "hkdf": "936c59e9394b5b1fdc26bd2eec0dc8c8d52fb97198e021805f0ae58c3f8b631d0020002b1ce0df9d890377fcc808166c906f128d06d77d404061d56560f3340d"
+ },
+ {
+ "digest": "sha224",
+ "hash": "8552d8b7a7dc5476cb9e25dee69a8091290764b7f2a64fe6e78e9568",
+ "signature": "70a8b455d63d2af5b12b0eefcb50ae245dcac054a74fd8a5beccca5ed12fd545e4dcdf2da3455f49e5eaf559772dc885ae24fd9e42790a1e175ec221a22329f2cc67d5c8ad1f9377fa1d713cb0d554f8335325a6080c272c10fb59f5fb7da9b39dcc76a50b49ed5f28d8cdd0499fbf5a19cae4b5b4a4a103201933a0e94e5532c6aaf05fbb060a3be5dcd5addef23b80651c51831ee479142cb1ddac0a37c6251f6eceee55217fcced2462fb7bef3e3aeeda98672598dc6aca6a49fb2df1b3f0ac569b666afeb8ca3f5b1bfa0bcca49f5fe6d3784fba1bb931077633d5a0a731c2bb22a820c8497ac1db888bd542f73ba2358d3a9bc056a7eca2f3a78b437820",
+ "pkdf2": "d3adee1df932bac56eecdba710702025678d6e024d315c925ae274a3796c474219291983a76f2b8bd67aad26fbebcf5bb5088c99b6124ae1b9c7c9b2eb37c8f4",
+ "hkdf": "1c3a0bd11a8c71c010353b075474aa2a6740f5cade0fff895019e08ebdaa68f8dfc4e74a5e013e2e9e0ab6852884311c1dac89432d34b2f762113ebf9a37597a"
+ },
+ {
+ "digest": "sha224WithRSAEncryption",
+ "hash": "8552d8b7a7dc5476cb9e25dee69a8091290764b7f2a64fe6e78e9568",
+ "signature": "70a8b455d63d2af5b12b0eefcb50ae245dcac054a74fd8a5beccca5ed12fd545e4dcdf2da3455f49e5eaf559772dc885ae24fd9e42790a1e175ec221a22329f2cc67d5c8ad1f9377fa1d713cb0d554f8335325a6080c272c10fb59f5fb7da9b39dcc76a50b49ed5f28d8cdd0499fbf5a19cae4b5b4a4a103201933a0e94e5532c6aaf05fbb060a3be5dcd5addef23b80651c51831ee479142cb1ddac0a37c6251f6eceee55217fcced2462fb7bef3e3aeeda98672598dc6aca6a49fb2df1b3f0ac569b666afeb8ca3f5b1bfa0bcca49f5fe6d3784fba1bb931077633d5a0a731c2bb22a820c8497ac1db888bd542f73ba2358d3a9bc056a7eca2f3a78b437820",
+ "pkdf2": "d3adee1df932bac56eecdba710702025678d6e024d315c925ae274a3796c474219291983a76f2b8bd67aad26fbebcf5bb5088c99b6124ae1b9c7c9b2eb37c8f4",
+ "hkdf": "1c3a0bd11a8c71c010353b075474aa2a6740f5cade0fff895019e08ebdaa68f8dfc4e74a5e013e2e9e0ab6852884311c1dac89432d34b2f762113ebf9a37597a"
+ },
+ {
+ "digest": "sha256",
+ "hash": "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3",
+ "signature": "67b67a87fc4a576342fc46167395a255654dddc5036e8a7d323acf862470e0612b90b1abf22166e3d124d4866e82146b5735fb85895355d027efdcb406a8cb87c8f00aea128e74cb95ca8a69cb970e3f02a11a6911253f9fba54ae7b75d7f1f29d51338d43f4ed59a36e3b7e408591cd9feaa818f1b0c6df6155cc89cc95c6686ce82a78fd8d34e82d9047ce936c3a67ac85d2924083610d6db5040409f09a46f97d35248b5451ca51be6cfbc9f94ff630eb8ff95e114a666cc1cc011af03d77f9b24f8add5244a83e0784dbcf785ebcfcd015b876963666b113dc26f0222aa95fdfbe1e64ac6b48780e1ff69b2588ff4bce9b15f9d53abba96b813a3d657cbe",
+ "pkdf2": "a8a2a7dcf7b65c8498ab1fbc62d56fa47255d668c1c3f21c5b236259d1dd8b11859026e737216cceb7a8facb8d27656f2b990db98786f12a8ce68e56a30f0c0b",
+ "hkdf": "a35a5ba99add2c508b9014ca7eb7d461a85989257b29a46a0041361c85b2c48838199873987b5419ede395aa09129bcb5fbd607b8b769e6711e1fea5e0ebcbc0"
+ },
+ {
+ "digest": "sha256WithRSAEncryption",
+ "hash": "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3",
+ "signature": "67b67a87fc4a576342fc46167395a255654dddc5036e8a7d323acf862470e0612b90b1abf22166e3d124d4866e82146b5735fb85895355d027efdcb406a8cb87c8f00aea128e74cb95ca8a69cb970e3f02a11a6911253f9fba54ae7b75d7f1f29d51338d43f4ed59a36e3b7e408591cd9feaa818f1b0c6df6155cc89cc95c6686ce82a78fd8d34e82d9047ce936c3a67ac85d2924083610d6db5040409f09a46f97d35248b5451ca51be6cfbc9f94ff630eb8ff95e114a666cc1cc011af03d77f9b24f8add5244a83e0784dbcf785ebcfcd015b876963666b113dc26f0222aa95fdfbe1e64ac6b48780e1ff69b2588ff4bce9b15f9d53abba96b813a3d657cbe",
+ "pkdf2": "a8a2a7dcf7b65c8498ab1fbc62d56fa47255d668c1c3f21c5b236259d1dd8b11859026e737216cceb7a8facb8d27656f2b990db98786f12a8ce68e56a30f0c0b",
+ "hkdf": "a35a5ba99add2c508b9014ca7eb7d461a85989257b29a46a0041361c85b2c48838199873987b5419ede395aa09129bcb5fbd607b8b769e6711e1fea5e0ebcbc0"
+ },
+ {
+ "digest": "sha3-224",
+ "hash": "6a33e22f20f16642697e8bd549ff7b759252ad56c05a1b0acc31dc69",
+ "signature": "2504c7a4735c251aa01644ae56a9f7c891f45e9fb6e25fea1c25074139dcab114e77d64ae7788bcbd8d5d452db60b47e6a0b324b0e3482ff794581da0cbe960a97ba75c1023eab2320fa9022ae715b5aa2fe1186916fb9a1c931d9f28ba8e12a4dd145efff6abfcfb68eca6536655c96cf059df406d5c51d1814b2f61c6bdc10a2b083d29f50a064bc6ffdddf5cb45df2577a7149a430e1314f87427972d8bb4775bd92e99a2298095cb83e60e50f503aab6d9fd41398b55d5dcfa6022049891561e6395a7a3e56a1d92a8667733a68d9b0374952d95e4d5a51b0b22d390cf579bb536e59cea8272b2d5749fa70d48c396b6ba94188ce677beb8f00937640096",
+ "pkdf2": "014d30aa9d1c1d8e3920f4bcc399f37b16d6c346d570d4345229d64ab95e504b1c6b253133c218a2b46f29aa0f9792d7ad60761159cc3550cb9a0914bfdc9951",
+ "hkdf": "b6c671ec02ee7f215dcee9ecade623831658470156f3edab205b7e3a70587f3c538eac8ec92e3a5bf6808b9b939d84e4f8ba5ee3532d7adb152211cc8f79cf9b"
+ },
+ {
+ "digest": "sha3-256",
+ "hash": "f345a219da005ebe9c1a1eaad97bbf38a10c8473e41d0af7fb617caa0c6aa722",
+ "signature": "b3b475d03da73b4bf8fefa5f49231dfd8f95605e0c3ea058d4607f1274ddcf4f69b1751df8493df1c5fe31883aff197688de1991885bb9ed4266f7df0db4fc99b33bee32a9237a9c2714e461fefb311923c1e91fe7cbe1830206bb0b3d962bfccdf5c37e8ce9e01f203851e34f22162175f44048002483ff2e3ffc658506a23f358f3192dbba759a8e1f66d3abf934b72295f1b51f8a92c837c76006084b65c0df8e072e43b1122bb15b3043dceb026e2cf311d04d6f4a3506e7e5b8a08fcaa0caeaa18a6397d185e5b5d1bc962f22b80db798a42fa206cd2db53b02bc5e2e69d9566f1ff3fccb4690545ff19424001cf3c0504c53adc0f2ce4354596b8a4d69",
+ "pkdf2": "4ba48814e191c34c9d38f5ccf6c5cf1a61082c2f8b36e99bd8210781af995734f62c6a714ad6639ecb55224d91b2ac7d69030335d2c367d833823814ef9f2213",
+ "hkdf": "e60f1e8214b7907d63d8cfb2bfb083051d3c9a56e4f94aabc1ff3543986aac5d4823db903090af81824964d6ca39da8388495e8838a9c0c407cb3546f44f9a04"
+ },
+ {
+ "digest": "sha3-384",
+ "hash": "6ba9ea268965916f5937228dde678c202f9fe756a87d8b1b7362869583a45901fd1a27289d72fc0e3ff48b1b78827d3a",
+ "signature": "256542ac61773cec2261fbc8cde4d6524e7a91f9fefcc08792c7c4b27fb843d099a5fce9819503949ad8fde307a7fc4185754dc5ed3d473da065376e4a9c804265dc4ff858a774d6eb19e663a26339d087a3e96b8f9133becc0ee2b404cfcfca58ffadbd48a5c31dced92f188b40bd179efdf9ae5394d0e02b513958f46adbdf745e8dada0dd97e38bf28bf7ad87aeb6771a40e3fef5f35161d4eeafe7b6ba1c2101388a22e75586fab599cbc070bf4d0fbe8304a7c579a34ce0000c87b33882c2d86ff11dbc218604fa7e7203e4efaa6e9605ae41958c0c2de0b7d76da9a6e606b3c38d29dad55675f9f138b11afc96e71ba5e41924bc5c676db777aed7ea04",
+ "pkdf2": "f609fda1c21cf4e59e7142438f2e04bb29f72010d49546e1c192755c6af3b97903da8483be8356afb865ffc334d23fa2439063c287ec9491618bfb5f791675f4",
+ "hkdf": "818ae5bc92cf582db87d73316e1a0649b457dfcd198db3e4edb1c6b20515dcf14f8758951765d9e2b4f7914a75ea04815e82050a6ca602c1a76f6c9999813955"
+ },
+ {
+ "digest": "sha3-512",
+ "hash": "8e47f1185ffd014d238fabd02a1a32defe698cbf38c037a90e3c0a0a32370fb52cbd641250508502295fcabcbf676c09470b27443868c8e5f70e26dc337288af",
+ "signature": "925bd1da0c91caba58c0a407f4f63e9b16f52444c3b71476f4043ee00ef97bb428a396e8a45d75b3204142d2e18886f36b0b0a1c6d25d80b010e4063ffb310741907e3217badadaf53d018100d78eace2e941c0ec2b6f9b47ceee455d55bfb1711b1255ae1fa0d8fb5bf869009c1b558b02fd4cabd83c55a76a1d96bdb4cdbb42f6ad1f36984c39e6c6fe4edc3a771766742ec461d29e8a93704a48323c0c0f9cc066bf1daeb4e83aa3aa7a3c2067495cf320a9e98b7f1db638a23fc135992fcc3bbfb52be115c35b055cdbf4733c30098674ff19f1ef218a4643b0e2ecb7c0597a406b304b67a36eed0300313a65a4af5621ef59a5ffe53e7d6763a83e0014a",
+ "pkdf2": "e1f0b454bf5d729fbb13e534229521a87aee130078555791d83834a8c51fb681ce4dfe02afd5f063082d8abba0b456084c677aeb6f8e0d70305322ec2ea97203",
+ "hkdf": "f27d87f9f6b87718073c8d2ad6bae00b4162cecde350c856252dd611120c433373a0c0d3946a8582bf855bf581439a14ca4f355fcd18881331f4a3b1027e84b2"
+ },
+ {
+ "digest": "sha384",
+ "hash": "55bc556b0d2fe0fce582ba5fe07baafff035653638c7ac0d5494c2a64c0bea1cc57331c7c12a45cdbca7f4c34a089eeb",
+ "signature": "77d465006b8843cf30c5e93b7d3f63b0daf2df1d693c4e1c0f9c759ec8410c088f331c5bf89bca7218edd1bdf3f2d948c9be9656f44a630748395429a09289acb05be80b0d000bacd7826c33a584dcbcf658839015d07561668e882bad4505c475a04766a7eabb35b15b8b54d6fcf9ebdd25b699f0d88906ba2999de1e8e59cc75969bc819fd514b1002a6667a03c861fafee03cccb9fd926352139dc1a916ba56b36e9e69fd328cb2403b9f747350721261158021df9ab2a75a7c5a3e39b42f3722ea1997a039ecc033f64366974336dbfd3294820400fe623d2993593c51f4398290a51bf05dc452c5991e26e8971be759472635e86b08230d04d05bce88f4",
+ "pkdf2": "b2e2b9e03d9e6f5218b74be7002c8704558feae855272ab3a973ee7deb387c26483f87fb6463bc5768406b398896a29ac2d17bd45afccf369a403ffa396bb455",
+ "hkdf": "54aef7f7256a147e52d67888a4543c6084b4ac46cd7bf919576bf8c4e9dad6b8a1fc9ad9c6f90f2af8e76d8d815ae2226d67a11ccb524a0c0be3cc858f4ddb10"
+ },
+ {
+ "digest": "sha384WithRSAEncryption",
+ "hash": "55bc556b0d2fe0fce582ba5fe07baafff035653638c7ac0d5494c2a64c0bea1cc57331c7c12a45cdbca7f4c34a089eeb",
+ "signature": "77d465006b8843cf30c5e93b7d3f63b0daf2df1d693c4e1c0f9c759ec8410c088f331c5bf89bca7218edd1bdf3f2d948c9be9656f44a630748395429a09289acb05be80b0d000bacd7826c33a584dcbcf658839015d07561668e882bad4505c475a04766a7eabb35b15b8b54d6fcf9ebdd25b699f0d88906ba2999de1e8e59cc75969bc819fd514b1002a6667a03c861fafee03cccb9fd926352139dc1a916ba56b36e9e69fd328cb2403b9f747350721261158021df9ab2a75a7c5a3e39b42f3722ea1997a039ecc033f64366974336dbfd3294820400fe623d2993593c51f4398290a51bf05dc452c5991e26e8971be759472635e86b08230d04d05bce88f4",
+ "pkdf2": "b2e2b9e03d9e6f5218b74be7002c8704558feae855272ab3a973ee7deb387c26483f87fb6463bc5768406b398896a29ac2d17bd45afccf369a403ffa396bb455",
+ "hkdf": "54aef7f7256a147e52d67888a4543c6084b4ac46cd7bf919576bf8c4e9dad6b8a1fc9ad9c6f90f2af8e76d8d815ae2226d67a11ccb524a0c0be3cc858f4ddb10"
+ },
+ {
+ "digest": "sha512",
+ "hash": "c1527cd893c124773d811911970c8fe6e857d6df5dc9226bd8a160614c0cd963a4ddea2b94bb7d36021ef9d865d5cea294a82dd49a0bb269f51f6e7a57f79421",
+ "signature": "50e2973977e1be1218134a1f50732a8f54c4b0dfb836be816c304edce9bef4b1be566a295b05c6c82de00eb915bc61ca4bab073a13061987ca19af280202a4c6c496cf6262655e6a6f1a53f923ca048b4bc21e31282edd239cec8840b2411c1aa2abe5b9bf7de5066f43f6e2e0a0691ac6f2fc71ed679ae644b6d799261ed694dc9e27c81142ffb88883440ee92a6086d7c3d62572eac13480034219a9edbda7e5556f335bbe1a37ef0df26ae3ffe99b968d40a93d9ca9a3c76025409b5da041242afa977a5a0438be946562a48a764dc6d4c924fec82590e01b807d410a432b95ee2e5173d245a565cdecdc321521d6f61e965628013181bc7a9462a450d895",
+ "pkdf2": "284f17da4e32b7b4780b31f94405e115ca7e6ae025b05d8398f421c3a3f36d903a1fae9471674342bec7d51c6f32996df0c843a20105c8451e9cd17ecbddb3ed",
+ "hkdf": "cf181757f66abf44c88cd3d4ad0ed99b82cf47a8a6f870ff1561a12da7af03251590250af7473a1a3c5c5e794f29c44e8f25f69fb7985258161e74b433510262"
+ },
+ {
+ "digest": "sha512-224",
+ "hash": "32620068b859669b45b31008e08b7384649ad2ca3f5163a3a71e5745",
+ "signature": "b5d1ec54de69d29dbc77595fec62bb16019b7cc275ead04338c17ee4b759fcb8443477e1708d45374b786acfeb616c1078d199b2a28d76f46d4b74a498c2bfb2b174632da895cae5558f36101f0596adb40152ac09b49f1726f293237bcf604ab7bf461c7e2dd78c909d7503ec4132722551842f7e8ef54317f4b58784c447fd68067c689c288c8401dc95276356e1396a127eac82a0bd0753cc4c00718e7240d523af95a1cd960885da64172e3325a225557f96e6307340dd45a499ac20af01a2e3e7a4be706a40249c6ce7e24dabdcbd577744c34cf8e182d9a7923c52cd508a0e39125003a0c74ac714f5c892187c6fc7417d552127b3c24c57e484212ab6",
+ "pkdf2": "69e623258a79c04b84aabc9333b17fc8a5ee8d7ebd06dd80236865584ccc98fce3180319f74748f6a6c2b44833425a6ab52e8ab22db62365799f14727102485d",
+ "hkdf": "c155ac0b2833f309322f258625df2c9926570fabbe66eff9713b977291054b57b8cd3280079613d8167a99f259087422cff9756780148bf683c1d5c03e015907"
+ },
+ {
+ "digest": "sha512-224WithRSAEncryption",
+ "hash": "32620068b859669b45b31008e08b7384649ad2ca3f5163a3a71e5745",
+ "signature": "b5d1ec54de69d29dbc77595fec62bb16019b7cc275ead04338c17ee4b759fcb8443477e1708d45374b786acfeb616c1078d199b2a28d76f46d4b74a498c2bfb2b174632da895cae5558f36101f0596adb40152ac09b49f1726f293237bcf604ab7bf461c7e2dd78c909d7503ec4132722551842f7e8ef54317f4b58784c447fd68067c689c288c8401dc95276356e1396a127eac82a0bd0753cc4c00718e7240d523af95a1cd960885da64172e3325a225557f96e6307340dd45a499ac20af01a2e3e7a4be706a40249c6ce7e24dabdcbd577744c34cf8e182d9a7923c52cd508a0e39125003a0c74ac714f5c892187c6fc7417d552127b3c24c57e484212ab6",
+ "pkdf2": "69e623258a79c04b84aabc9333b17fc8a5ee8d7ebd06dd80236865584ccc98fce3180319f74748f6a6c2b44833425a6ab52e8ab22db62365799f14727102485d",
+ "hkdf": "c155ac0b2833f309322f258625df2c9926570fabbe66eff9713b977291054b57b8cd3280079613d8167a99f259087422cff9756780148bf683c1d5c03e015907"
+ },
+ {
+ "digest": "sha512-256",
+ "hash": "330c723f25267587db0b9f493463e017011239169cb57a6db216c63774367115",
+ "signature": "6313742057ecbf4f54476799b018d1e18c2db920ef23386208f1e23e5af30d38edc0d11f1220e2cc0f898cd3e4cd9d4920fed30ff9f725404d4750f230fe9dafdfde95280a8713043359a09d45fbda484c469e61ae4fd615d616e76f6daa27acd3542d823e88f2dfd943b39f38884f9ed4695b8f004b4c67777de63474fe9dbbfeab966113907663f14c7822658aab70dceb7d1a6ed9842085762ab100ee915941295a045b29ef09af19eab58c79d3e5ffcbda61e2be35770c1d3b55156357c3cca806309b1ddc7e52f47e245d1d49237f0aa7156e89c76a17780a62fa552eeb7b623410e387d0a9412d4688725ed8df0a86e8b548ea6bb785ea48b6c0e39332",
+ "pkdf2": "c3d18f17c825a1630bc10695bfd4faa0309e862d010c0b74fb41b6ce5e46853cc435560a1b9cd940254103068aebc1f24d2580385b1890e7f10356ef4c8f507d",
+ "hkdf": "8451f1238da8577794ecc9b75832cabff44f279e5f8258cbf553c21f9735c19c7974e9a74879b4c59386116bb1a4bb50f149c9a4146b10de312fa679c1343b80"
+ },
+ {
+ "digest": "sha512-256WithRSAEncryption",
+ "hash": "330c723f25267587db0b9f493463e017011239169cb57a6db216c63774367115",
+ "signature": "6313742057ecbf4f54476799b018d1e18c2db920ef23386208f1e23e5af30d38edc0d11f1220e2cc0f898cd3e4cd9d4920fed30ff9f725404d4750f230fe9dafdfde95280a8713043359a09d45fbda484c469e61ae4fd615d616e76f6daa27acd3542d823e88f2dfd943b39f38884f9ed4695b8f004b4c67777de63474fe9dbbfeab966113907663f14c7822658aab70dceb7d1a6ed9842085762ab100ee915941295a045b29ef09af19eab58c79d3e5ffcbda61e2be35770c1d3b55156357c3cca806309b1ddc7e52f47e245d1d49237f0aa7156e89c76a17780a62fa552eeb7b623410e387d0a9412d4688725ed8df0a86e8b548ea6bb785ea48b6c0e39332",
+ "pkdf2": "c3d18f17c825a1630bc10695bfd4faa0309e862d010c0b74fb41b6ce5e46853cc435560a1b9cd940254103068aebc1f24d2580385b1890e7f10356ef4c8f507d",
+ "hkdf": "8451f1238da8577794ecc9b75832cabff44f279e5f8258cbf553c21f9735c19c7974e9a74879b4c59386116bb1a4bb50f149c9a4146b10de312fa679c1343b80"
+ },
+ {
+ "digest": "sha512WithRSAEncryption",
+ "hash": "c1527cd893c124773d811911970c8fe6e857d6df5dc9226bd8a160614c0cd963a4ddea2b94bb7d36021ef9d865d5cea294a82dd49a0bb269f51f6e7a57f79421",
+ "signature": "50e2973977e1be1218134a1f50732a8f54c4b0dfb836be816c304edce9bef4b1be566a295b05c6c82de00eb915bc61ca4bab073a13061987ca19af280202a4c6c496cf6262655e6a6f1a53f923ca048b4bc21e31282edd239cec8840b2411c1aa2abe5b9bf7de5066f43f6e2e0a0691ac6f2fc71ed679ae644b6d799261ed694dc9e27c81142ffb88883440ee92a6086d7c3d62572eac13480034219a9edbda7e5556f335bbe1a37ef0df26ae3ffe99b968d40a93d9ca9a3c76025409b5da041242afa977a5a0438be946562a48a764dc6d4c924fec82590e01b807d410a432b95ee2e5173d245a565cdecdc321521d6f61e965628013181bc7a9462a450d895",
+ "pkdf2": "284f17da4e32b7b4780b31f94405e115ca7e6ae025b05d8398f421c3a3f36d903a1fae9471674342bec7d51c6f32996df0c843a20105c8451e9cd17ecbddb3ed",
+ "hkdf": "cf181757f66abf44c88cd3d4ad0ed99b82cf47a8a6f870ff1561a12da7af03251590250af7473a1a3c5c5e794f29c44e8f25f69fb7985258161e74b433510262"
+ },
+ {
+ "digest": "shake128",
+ "hash": "b5ffd113fa127f4d9c7e483cb52264ed",
+ "signature": null,
+ "pkdf2": null,
+ "hkdf": null
+ },
+ {
+ "digest": "shake256",
+ "hash": "cf68a0d388047ed588ad72d3808cf9a3243f04d4901748c705fbf3a27d955542",
+ "signature": null,
+ "pkdf2": null,
+ "hkdf": null
+ },
+ {
+ "digest": "sm3",
+ "hash": "e3bca101b496880c3653dad85861d0e784b00a8c18f7574472d156060e9096bf",
+ "signature": null,
+ "pkdf2": "70b3d2ac3b82dd7b8c35db45f99f49e029be2b6f1ef9ce1d9137267b729c06f7099dc7f571f2b05dbe5172118a7ae787cd4836fbf9ddce9aacc933c7c4e5537b",
+ "hkdf": "88b773032a2f131b1aa4ebdb69fdde7c42281b7c689bfe1f5bd43c7e1a6f555f101657c3f83ccd5918b4c6a8df04d0b58ebf77ec2181f8c5e7cfecb6f13fba61"
+ },
+ {
+ "digest": "sm3WithRSAEncryption",
+ "hash": "e3bca101b496880c3653dad85861d0e784b00a8c18f7574472d156060e9096bf",
+ "signature": null,
+ "pkdf2": "70b3d2ac3b82dd7b8c35db45f99f49e029be2b6f1ef9ce1d9137267b729c06f7099dc7f571f2b05dbe5172118a7ae787cd4836fbf9ddce9aacc933c7c4e5537b",
+ "hkdf": "88b773032a2f131b1aa4ebdb69fdde7c42281b7c689bfe1f5bd43c7e1a6f555f101657c3f83ccd5918b4c6a8df04d0b58ebf77ec2181f8c5e7cfecb6f13fba61"
+ },
+ {
+ "digest": "ssl3-md5",
+ "hash": "6cd3556deb0da54bca060b4c39479839",
+ "signature": "45f2e7ac7c0d323c18e9c8554d15e21a8fb72944928e0b7acc2185402448c39af05340391ee9aac64c45a947bc3ed801de8791aaa5788a62e909d7c8d92e63c7f119753219a48c29ea78e371d3a89c0bd64d756b829fa6faaa8fa46bc28228dd4430aca845c02f3b6b835b140247838ac5b96434d1049115785f3f52034e0cc46f6cafc5f2921b9928403aea1edd85f3a99e12324abeeaaaa040b320f8af157c5df7fd7479415771fd116daed933b43eac51b3c274ba9283aaf3f1b6f1f527a0cea76f9a43dca3b9ff03834feed13a0fd488e6750a9d46ddb1ad69ac88090af050458eeafd1e9fa317c4ecc61d90289d5378e6e3693ef6da2e4a4803b6108145",
+ "pkdf2": "3083f052ca2e90daf96a87b8b8c1daa069bff60c73045c9504d3b424807b5410a724ea5ba28b9bccb6bad59c0e181663b07156a59b09cee85ffe223f21ff6db6",
+ "hkdf": "f516674e1b1faf2c1a505041634460d94739e2e39be4e6a097f926f5cc9788c09892efcb407019dc469c4014c8d847cf4c5a6eeefccf8e5266ca3dd02ea57529"
+ },
+ {
+ "digest": "ssl3-sha1",
+ "hash": "943a702d06f34599aee1f8da8ef9f7296031d699",
+ "signature": "80174b0678707d38335940a010bd6acc1a6ade2c911251d013875816eb4c5169d9d4cb2ac9f6ce4b29b92f5750f185a273abd7c8a2434a9d1a50df5311999655d2a535c77b79997ed34fe51a863c450251d1b85bbb4dd10da1162e6e74194af606579a8724e55b93bded2d10216bb63cf00e848ceea6cdba78eab4f735ca620b36fdfd19bf15706df860a4c589160ce3c32aa51c27561de82a00cdcca709045cb8622adb6f759eb5e0f2f3f6056ca1b1a91206712ce92f5684d64931bc001bec7d2e8d2469f0818106070698160e9e21404971ea45940797fa3a61a39a25b7c6c75986accd4832db50a25ef3fceca629e104e2f03affd83b94cf074614e11c18",
+ "pkdf2": "e77df42e685bd1fe2e19e374e1dd8470df71182311e048a6a280f36ef24c661e46fe8e8cc763942615934a631ac3aeda24bb9fda71e04f89f0c85f2f762abd98",
+ "hkdf": "936c59e9394b5b1fdc26bd2eec0dc8c8d52fb97198e021805f0ae58c3f8b631d0020002b1ce0df9d890377fcc808166c906f128d06d77d404061d56560f3340d"
+ }
+]