use std::num::NonZeroU32;
use aws_lc_rs::hkdf;
use aws_lc_rs::hmac::Algorithm as HmacAlgorithm;
use aws_lc_rs::hmac::Key as HmacKey;
use aws_lc_rs::pbkdf2;
use deno_core::convert::Uint8Array;
use deno_error::JsErrorBox;
use p256::ecdsa::Signature as P256Signature;
use p256::ecdsa::SigningKey as P256SigningKey;
use p256::ecdsa::VerifyingKey as P256VerifyingKey;
use p256::elliptic_curve::sec1::FromEncodedPoint;
use p256::pkcs8::DecodePrivateKey;
use p384::ecdsa::Signature as P384Signature;
use p384::ecdsa::SigningKey as P384SigningKey;
use p384::ecdsa::VerifyingKey as P384VerifyingKey;
use p521::ecdsa::Signature as P521Signature;
use p521::ecdsa::SigningKey as P521SigningKey;
use p521::ecdsa::VerifyingKey as P521VerifyingKey;
pub use rand;
use rand::SeedableRng;
use rand::rngs::OsRng;
use rand::rngs::StdRng;
use rsa::Pss;
use rsa::RsaPrivateKey;
use rsa::RsaPublicKey;
use rsa::pkcs1::DecodeRsaPrivateKey;
use rsa::pkcs1::DecodeRsaPublicKey;
use rsa::signature::SignatureEncoding;
use rsa::signature::Signer;
use rsa::signature::Verifier;
use rsa::traits::SignatureScheme;
use serde::Deserialize;
use sha1::Sha1;
use sha2::Digest;
use sha2::Sha256;
use sha2::Sha384;
use sha2::Sha512;
use sha3::Sha3_256;
use sha3::Sha3_384;
use sha3::Sha3_512;
use signature::hazmat::PrehashSigner;
use signature::hazmat::PrehashVerifier;
mod algorithm;
mod crypto;
mod crypto_key;
mod decrypt;
mod digest;
mod ed25519;
mod encrypt;
mod export_key;
mod generate_key;
mod import_key;
mod key;
mod key_store;
mod make_key;
mod mldsa;
mod mlkem;
mod node_interop;
mod shared;
mod slhdsa;
mod subtle_crypto;
mod subtle_decrypt;
mod subtle_derive_bits;
mod subtle_derive_key;
mod subtle_encapsulate;
mod subtle_encapsulate_key;
mod subtle_encrypt;
mod subtle_export_key;
mod subtle_generate_key;
mod subtle_get_public_key;
mod subtle_import_key;
mod subtle_key;
mod subtle_sign;
mod subtle_verify;
mod subtle_wrap_key;
mod x25519;
mod x448;
pub use crate::decrypt::DecryptError;
pub use crate::ed25519::Ed25519Error;
pub use crate::encrypt::EncryptError;
pub use crate::export_key::ExportKeyError;
pub use crate::generate_key::GenerateKeyError;
pub use crate::import_key::ImportKeyError;
use crate::key::Algorithm;
use crate::key::CryptoHash;
use crate::key::CryptoNamedCurve;
use crate::key::HkdfOutput;
pub use crate::mldsa::MlDsaError;
pub use crate::mlkem::MlKemError;
pub use crate::shared::RawKeyData;
pub use crate::shared::SharedError;
pub use crate::x448::X448Error;
pub use crate::x25519::X25519Error;
deno_core::extension!(deno_crypto,
deps = [ deno_webidl, deno_web ],
objects = [
crypto::Crypto,
subtle_crypto::SubtleCrypto,
crypto_key::CryptoKey,
],
lazy_loaded_js = [ "00_crypto.js" ],
options = {
maybe_seed: Option<u64>,
},
state = |state, options| {
if let Some(seed) = options.maybe_seed {
state.put(StdRng::seed_from_u64(seed));
}
},
);
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CryptoError {
#[class(inherit)]
#[error(transparent)]
General(
#[from]
#[inherit]
SharedError,
),
#[class(inherit)]
#[error(transparent)]
JoinError(
#[from]
#[inherit]
tokio::task::JoinError,
),
#[class(generic)]
#[error(transparent)]
Der(#[from] rsa::pkcs1::der::Error),
#[class(type)]
#[error("Missing argument hash")]
MissingArgumentHash,
#[class(type)]
#[error("Missing argument saltLength")]
MissingArgumentSaltLength,
#[class(type)]
#[error("unsupported algorithm")]
UnsupportedAlgorithm,
#[class(generic)]
#[error(transparent)]
KeyRejected(#[from] aws_lc_rs::error::KeyRejected),
#[class(generic)]
#[error(transparent)]
RSA(#[from] rsa::Error),
#[class(generic)]
#[error(transparent)]
Pkcs1(#[from] rsa::pkcs1::Error),
#[class(generic)]
#[error(transparent)]
Unspecified(#[from] aws_lc_rs::error::Unspecified),
#[class(type)]
#[error("Invalid key format")]
InvalidKeyFormat,
#[class(generic)]
#[error(transparent)]
P256Ecdsa(#[from] p256::ecdsa::Error),
#[class(type)]
#[error("Unexpected error decoding private key")]
DecodePrivateKey,
#[class(type)]
#[error("Missing argument publicKey")]
MissingArgumentPublicKey,
#[class(type)]
#[error("Missing argument namedCurve")]
MissingArgumentNamedCurve,
#[class(type)]
#[error("Missing argument info")]
MissingArgumentInfo,
#[class("DOMExceptionOperationError")]
#[error("The length provided for HKDF is too large")]
HKDFLengthTooLarge,
#[class(generic)]
#[error(transparent)]
Base64Decode(#[from] base64::DecodeError),
#[class(type)]
#[error("Data must be multiple of 8 bytes")]
DataInvalidSize,
#[class(type)]
#[error("Invalid key length")]
InvalidKeyLength,
#[class("DOMExceptionOperationError")]
#[error("encryption error")]
EncryptionError,
#[class("DOMExceptionOperationError")]
#[error("decryption error - integrity check failed")]
DecryptionError,
#[class("DOMExceptionOperationError")]
#[error("Invalid XOF parameters")]
InvalidXofParameters,
#[class("DOMExceptionQuotaExceededError")]
#[error(
"The ArrayBufferView's byte length ({0}) exceeds the number of bytes of entropy available via this API (65536)"
)]
ArrayBufferViewLengthExceeded(usize),
#[class("DOMExceptionTypeMismatchError")]
#[error("The provided value is not an integer-type TypedArray")]
TypedArrayNotInteger,
#[class("DOMExceptionNotSupportedError")]
#[error("Algorithm '{0}' is not supported")]
UnsupportedDigestAlgorithm(String),
#[class(inherit)]
#[error(transparent)]
Other(
#[from]
#[inherit]
JsErrorBox,
),
}
#[derive(Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum KeyFormat {
Raw,
Pkcs8,
Spki,
}
#[derive(Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum KeyType {
Secret,
Private,
Public,
}
pub struct KeyData {
r#type: KeyType,
data: Box<[u8]>,
}
impl From<&RawKeyData> for KeyData {
fn from(raw: &RawKeyData) -> Self {
let (r#type, data) = match raw {
RawKeyData::Secret(d) => (KeyType::Secret, d),
RawKeyData::Private(d) => (KeyType::Private, d),
RawKeyData::Public(d) => (KeyType::Public, d),
RawKeyData::Raw(d) => (KeyType::Secret, d),
RawKeyData::SeededPrivate { .. } => unreachable!(),
};
KeyData {
r#type,
data: data.as_ref().into(),
}
}
}
#[derive(deno_core::FromV8)]
pub struct SignArg {
#[from_v8(serde)]
algorithm: Algorithm,
salt_length: Option<u32>,
#[from_v8(serde)]
hash: Option<CryptoHash>,
#[from_v8(serde)]
named_curve: Option<CryptoNamedCurve>,
}
impl SignArg {
pub(crate) fn new(
algorithm: Algorithm,
salt_length: Option<u32>,
hash: Option<CryptoHash>,
named_curve: Option<CryptoNamedCurve>,
) -> Self {
Self {
algorithm,
salt_length,
hash,
named_curve,
}
}
}
pub(crate) fn sign_key_sync(
key: KeyData,
args: SignArg,
data: &[u8],
) -> Result<Vec<u8>, CryptoError> {
{
let algorithm = args.algorithm;
let signature = match algorithm {
Algorithm::RsassaPkcs1v15 => {
use rsa::pkcs1v15::SigningKey;
let private_key = RsaPrivateKey::from_pkcs1_der(&key.data)?;
match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? {
CryptoHash::Sha1 => {
let signing_key = SigningKey::<Sha1>::new(private_key);
signing_key.sign(data)
}
CryptoHash::Sha256 => {
let signing_key = SigningKey::<Sha256>::new(private_key);
signing_key.sign(data)
}
CryptoHash::Sha384 => {
let signing_key = SigningKey::<Sha384>::new(private_key);
signing_key.sign(data)
}
CryptoHash::Sha512 => {
let signing_key = SigningKey::<Sha512>::new(private_key);
signing_key.sign(data)
}
_ => return Err(CryptoError::UnsupportedAlgorithm),
}
.to_vec()
}
Algorithm::RsaPss => {
let private_key = RsaPrivateKey::from_pkcs1_der(&key.data)?;
let salt_len = args
.salt_length
.ok_or_else(|| CryptoError::MissingArgumentSaltLength)?
as usize;
let mut rng = OsRng;
match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? {
CryptoHash::Sha1 => {
let signing_key = Pss::new_with_salt::<Sha1>(salt_len);
let hashed = Sha1::digest(data);
signing_key.sign(Some(&mut rng), &private_key, &hashed)?
}
CryptoHash::Sha256 => {
let signing_key = Pss::new_with_salt::<Sha256>(salt_len);
let hashed = Sha256::digest(data);
signing_key.sign(Some(&mut rng), &private_key, &hashed)?
}
CryptoHash::Sha384 => {
let signing_key = Pss::new_with_salt::<Sha384>(salt_len);
let hashed = Sha384::digest(data);
signing_key.sign(Some(&mut rng), &private_key, &hashed)?
}
CryptoHash::Sha512 => {
let signing_key = Pss::new_with_salt::<Sha512>(salt_len);
let hashed = Sha512::digest(data);
signing_key.sign(Some(&mut rng), &private_key, &hashed)?
}
_ => return Err(CryptoError::UnsupportedAlgorithm),
}
.to_vec()
}
Algorithm::Ecdsa => {
let hash = args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)?;
let named_curve =
args.named_curve.ok_or_else(JsErrorBox::not_supported)?;
match named_curve {
CryptoNamedCurve::P256 => {
let secret_key = p256::SecretKey::from_pkcs8_der(&key.data)
.map_err(|_| CryptoError::InvalidKeyFormat)?;
let signing_key = P256SigningKey::from(secret_key);
let prehash = match hash {
CryptoHash::Sha1 => sha1::Sha1::digest(data).to_vec(),
CryptoHash::Sha256 => sha2::Sha256::digest(data).to_vec(),
CryptoHash::Sha384 => sha2::Sha384::digest(data).to_vec(),
CryptoHash::Sha512 => sha2::Sha512::digest(data).to_vec(),
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
let signature: P256Signature =
signing_key.sign_prehash(&prehash)?;
signature.to_bytes().to_vec()
}
CryptoNamedCurve::P384 => {
let secret_key = p384::SecretKey::from_pkcs8_der(&key.data)
.map_err(|_| CryptoError::InvalidKeyFormat)?;
let signing_key = P384SigningKey::from(secret_key);
let prehash = match hash {
CryptoHash::Sha1 => sha1::Sha1::digest(data).to_vec(),
CryptoHash::Sha256 => sha2::Sha256::digest(data).to_vec(),
CryptoHash::Sha384 => sha2::Sha384::digest(data).to_vec(),
CryptoHash::Sha512 => sha2::Sha512::digest(data).to_vec(),
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
let signature: P384Signature =
signing_key.sign_prehash(&prehash)?;
signature.to_bytes().to_vec()
}
CryptoNamedCurve::P521 => {
let secret_key = p521::SecretKey::from_pkcs8_der(&key.data)
.map_err(|_| CryptoError::InvalidKeyFormat)?;
let signing_key =
P521SigningKey::from_bytes(&secret_key.to_bytes())
.map_err(|_| CryptoError::InvalidKeyFormat)?;
let prehash = match hash {
CryptoHash::Sha1 => sha1::Sha1::digest(data).to_vec(),
CryptoHash::Sha256 => sha2::Sha256::digest(data).to_vec(),
CryptoHash::Sha384 => sha2::Sha384::digest(data).to_vec(),
CryptoHash::Sha512 => sha2::Sha512::digest(data).to_vec(),
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
let prehash = if prehash.len() < 33 {
let mut padded = vec![0u8; 33 - prehash.len()];
padded.extend_from_slice(&prehash);
padded
} else {
prehash
};
let signature: P521Signature =
signing_key.sign_prehash(&prehash)?;
signature.to_bytes().to_vec()
}
}
}
Algorithm::Hmac => {
let hash = args.hash.ok_or_else(JsErrorBox::not_supported)?;
match hash {
CryptoHash::Sha3_256 => {
hmac_sign::<hmac::Hmac<Sha3_256>>(&key.data, data)?
}
CryptoHash::Sha3_384 => {
hmac_sign::<hmac::Hmac<Sha3_384>>(&key.data, data)?
}
CryptoHash::Sha3_512 => {
hmac_sign::<hmac::Hmac<Sha3_512>>(&key.data, data)?
}
_ => {
let hash: HmacAlgorithm = hash.into();
let key = HmacKey::new(hash, &key.data);
let signature = aws_lc_rs::hmac::sign(&key, data);
signature.as_ref().to_vec()
}
}
}
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
Ok(signature)
}
}
fn hmac_sign<M: hmac::Mac + hmac::digest::KeyInit>(
key: &[u8],
data: &[u8],
) -> Result<Vec<u8>, CryptoError> {
let mut mac = <M as hmac::Mac>::new_from_slice(key)
.map_err(|_| CryptoError::InvalidKeyLength)?;
mac.update(data);
Ok(mac.finalize().into_bytes().to_vec())
}
fn hmac_verify<M: hmac::Mac + hmac::digest::KeyInit>(
key: &[u8],
data: &[u8],
signature: &[u8],
) -> Result<bool, CryptoError> {
let mut mac = <M as hmac::Mac>::new_from_slice(key)
.map_err(|_| CryptoError::InvalidKeyLength)?;
mac.update(data);
Ok(mac.verify_slice(signature).is_ok())
}
#[derive(deno_core::FromV8)]
pub struct VerifyArg {
#[from_v8(serde)]
algorithm: Algorithm,
salt_length: Option<u32>,
#[from_v8(serde)]
hash: Option<CryptoHash>,
signature: Uint8Array,
#[from_v8(serde)]
named_curve: Option<CryptoNamedCurve>,
}
impl VerifyArg {
pub(crate) fn new(
algorithm: Algorithm,
salt_length: Option<u32>,
hash: Option<CryptoHash>,
signature: Vec<u8>,
named_curve: Option<CryptoNamedCurve>,
) -> Self {
Self {
algorithm,
salt_length,
hash,
signature: signature.into(),
named_curve,
}
}
}
pub(crate) fn verify_key_sync(
key: KeyData,
args: VerifyArg,
data: &[u8],
) -> Result<bool, CryptoError> {
{
let algorithm = args.algorithm;
let verification = match algorithm {
Algorithm::RsassaPkcs1v15 => {
use rsa::pkcs1v15::Signature;
use rsa::pkcs1v15::VerifyingKey;
let public_key = read_rsa_public_key(key)?;
let signature: Signature = (&*args.signature).try_into()?;
match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? {
CryptoHash::Sha1 => {
let verifying_key = VerifyingKey::<Sha1>::new(public_key);
verifying_key.verify(data, &signature).is_ok()
}
CryptoHash::Sha256 => {
let verifying_key = VerifyingKey::<Sha256>::new(public_key);
verifying_key.verify(data, &signature).is_ok()
}
CryptoHash::Sha384 => {
let verifying_key = VerifyingKey::<Sha384>::new(public_key);
verifying_key.verify(data, &signature).is_ok()
}
CryptoHash::Sha512 => {
let verifying_key = VerifyingKey::<Sha512>::new(public_key);
verifying_key.verify(data, &signature).is_ok()
}
_ => return Err(CryptoError::UnsupportedAlgorithm),
}
}
Algorithm::RsaPss => {
let public_key = read_rsa_public_key(key)?;
let signature = args.signature.as_ref();
let salt_len = args
.salt_length
.ok_or_else(|| CryptoError::MissingArgumentSaltLength)?
as usize;
match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? {
CryptoHash::Sha1 => {
let pss = Pss::new_with_salt::<Sha1>(salt_len);
let hashed = Sha1::digest(data);
pss.verify(&public_key, &hashed, signature).is_ok()
}
CryptoHash::Sha256 => {
let pss = Pss::new_with_salt::<Sha256>(salt_len);
let hashed = Sha256::digest(data);
pss.verify(&public_key, &hashed, signature).is_ok()
}
CryptoHash::Sha384 => {
let pss = Pss::new_with_salt::<Sha384>(salt_len);
let hashed = Sha384::digest(data);
pss.verify(&public_key, &hashed, signature).is_ok()
}
CryptoHash::Sha512 => {
let pss = Pss::new_with_salt::<Sha512>(salt_len);
let hashed = Sha512::digest(data);
pss.verify(&public_key, &hashed, signature).is_ok()
}
_ => return Err(CryptoError::UnsupportedAlgorithm),
}
}
Algorithm::Hmac => {
let hash = args.hash.ok_or_else(JsErrorBox::not_supported)?;
match hash {
CryptoHash::Sha3_256 => hmac_verify::<hmac::Hmac<Sha3_256>>(
&key.data,
data,
&args.signature,
)?,
CryptoHash::Sha3_384 => hmac_verify::<hmac::Hmac<Sha3_384>>(
&key.data,
data,
&args.signature,
)?,
CryptoHash::Sha3_512 => hmac_verify::<hmac::Hmac<Sha3_512>>(
&key.data,
data,
&args.signature,
)?,
_ => {
let hash: HmacAlgorithm = hash.into();
let key = HmacKey::new(hash, &key.data);
aws_lc_rs::hmac::verify(&key, data, &args.signature).is_ok()
}
}
}
Algorithm::Ecdsa => {
let hash = args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)?;
let named_curve =
args.named_curve.ok_or_else(JsErrorBox::not_supported)?;
match named_curve {
CryptoNamedCurve::P256 => {
let verifying_key = match key.r#type {
KeyType::Public => P256VerifyingKey::from_sec1_bytes(&key.data)
.map_err(|_| CryptoError::InvalidKeyFormat)?,
KeyType::Private => {
let secret_key = p256::SecretKey::from_pkcs8_der(&key.data)
.map_err(|_| CryptoError::InvalidKeyFormat)?;
let signing_key = P256SigningKey::from(secret_key);
*signing_key.verifying_key()
}
_ => return Err(CryptoError::InvalidKeyFormat),
};
match P256Signature::from_slice(&args.signature) {
Ok(signature) => {
let prehash = match hash {
CryptoHash::Sha1 => sha1::Sha1::digest(data).to_vec(),
CryptoHash::Sha256 => sha2::Sha256::digest(data).to_vec(),
CryptoHash::Sha384 => sha2::Sha384::digest(data).to_vec(),
CryptoHash::Sha512 => sha2::Sha512::digest(data).to_vec(),
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
verifying_key.verify_prehash(&prehash, &signature).is_ok()
}
_ => false,
}
}
CryptoNamedCurve::P384 => {
let verifying_key = match key.r#type {
KeyType::Public => P384VerifyingKey::from_sec1_bytes(&key.data)
.map_err(|_| CryptoError::InvalidKeyFormat)?,
KeyType::Private => {
let secret_key = p384::SecretKey::from_pkcs8_der(&key.data)
.map_err(|_| CryptoError::InvalidKeyFormat)?;
let signing_key = P384SigningKey::from(secret_key);
*signing_key.verifying_key()
}
_ => return Err(CryptoError::InvalidKeyFormat),
};
match P384Signature::from_slice(&args.signature) {
Ok(signature) => {
let prehash = match hash {
CryptoHash::Sha1 => sha1::Sha1::digest(data).to_vec(),
CryptoHash::Sha256 => sha2::Sha256::digest(data).to_vec(),
CryptoHash::Sha384 => sha2::Sha384::digest(data).to_vec(),
CryptoHash::Sha512 => sha2::Sha512::digest(data).to_vec(),
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
verifying_key.verify_prehash(&prehash, &signature).is_ok()
}
_ => false,
}
}
CryptoNamedCurve::P521 => {
let verifying_key = match key.r#type {
KeyType::Public => P521VerifyingKey::from_sec1_bytes(&key.data)
.map_err(|_| CryptoError::InvalidKeyFormat)?,
KeyType::Private => {
let secret_key = p521::SecretKey::from_pkcs8_der(&key.data)
.map_err(|_| CryptoError::InvalidKeyFormat)?;
let inner_signing_key =
ecdsa::SigningKey::<p521::NistP521>::from(secret_key);
P521VerifyingKey::from(*inner_signing_key.verifying_key())
}
_ => return Err(CryptoError::InvalidKeyFormat),
};
match P521Signature::from_slice(&args.signature) {
Ok(signature) => {
let prehash = match hash {
CryptoHash::Sha1 => sha1::Sha1::digest(data).to_vec(),
CryptoHash::Sha256 => sha2::Sha256::digest(data).to_vec(),
CryptoHash::Sha384 => sha2::Sha384::digest(data).to_vec(),
CryptoHash::Sha512 => sha2::Sha512::digest(data).to_vec(),
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
let prehash = if prehash.len() < 33 {
let mut padded = vec![0u8; 33 - prehash.len()];
padded.extend_from_slice(&prehash);
padded
} else {
prehash
};
verifying_key.verify_prehash(&prehash, &signature).is_ok()
}
_ => false,
}
}
}
}
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
Ok(verification)
}
}
#[allow(
clippy::too_many_arguments,
reason = "internal sync dispatch lifted out of op_crypto_derive_bits; \
the per-algorithm DeriveKeyArg fields are unpacked rather than \
reintroduced as a struct just for this lint"
)]
pub(crate) fn derive_bits_sync(
key: KeyData,
public_key: Option<KeyData>,
algorithm: Algorithm,
hash: Option<CryptoHash>,
length: usize,
iterations: Option<u32>,
named_curve: Option<CryptoNamedCurve>,
info: Option<Vec<u8>>,
salt: Option<Vec<u8>>,
) -> Result<Vec<u8>, CryptoError> {
match algorithm {
Algorithm::Pbkdf2 => {
let salt = salt.ok_or_else(JsErrorBox::not_supported)?;
assert!(length > 0);
assert!(length.is_multiple_of(8));
let algorithm = match hash.ok_or_else(JsErrorBox::not_supported)? {
CryptoHash::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1,
CryptoHash::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256,
CryptoHash::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384,
CryptoHash::Sha512 => pbkdf2::PBKDF2_HMAC_SHA512,
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
let iterations =
NonZeroU32::new(iterations.ok_or_else(JsErrorBox::not_supported)?)
.unwrap();
let secret = key.data;
let mut out = vec![0; length / 8];
pbkdf2::derive(algorithm, iterations, &salt, &secret, &mut out);
Ok(out)
}
Algorithm::Ecdh => {
let named_curve =
named_curve.ok_or(CryptoError::MissingArgumentNamedCurve)?;
let public_key =
public_key.ok_or(CryptoError::MissingArgumentPublicKey)?;
match named_curve {
CryptoNamedCurve::P256 => {
let secret_key = p256::SecretKey::from_pkcs8_der(&key.data)
.map_err(|_| CryptoError::DecodePrivateKey)?;
let public_key = match public_key.r#type {
KeyType::Private => {
p256::SecretKey::from_pkcs8_der(&public_key.data)
.map_err(|_| CryptoError::DecodePrivateKey)?
.public_key()
}
KeyType::Public => {
let point = p256::EncodedPoint::from_bytes(public_key.data)
.map_err(|_| CryptoError::DecodePrivateKey)?;
let pk = p256::PublicKey::from_encoded_point(&point);
if pk.is_some().into() {
pk.unwrap()
} else {
return Err(CryptoError::DecodePrivateKey);
}
}
_ => unreachable!(),
};
let shared_secret = p256::elliptic_curve::ecdh::diffie_hellman(
secret_key.to_nonzero_scalar(),
public_key.as_affine(),
);
Ok(shared_secret.raw_secret_bytes().to_vec())
}
CryptoNamedCurve::P384 => {
let secret_key = p384::SecretKey::from_pkcs8_der(&key.data)
.map_err(|_| CryptoError::DecodePrivateKey)?;
let public_key = match public_key.r#type {
KeyType::Private => {
p384::SecretKey::from_pkcs8_der(&public_key.data)
.map_err(|_| CryptoError::DecodePrivateKey)?
.public_key()
}
KeyType::Public => {
let point = p384::EncodedPoint::from_bytes(public_key.data)
.map_err(|_| CryptoError::DecodePrivateKey)?;
let pk = p384::PublicKey::from_encoded_point(&point);
if pk.is_some().into() {
pk.unwrap()
} else {
return Err(CryptoError::DecodePrivateKey);
}
}
_ => unreachable!(),
};
let shared_secret = p384::elliptic_curve::ecdh::diffie_hellman(
secret_key.to_nonzero_scalar(),
public_key.as_affine(),
);
Ok(shared_secret.raw_secret_bytes().to_vec())
}
CryptoNamedCurve::P521 => {
let secret_key = p521::SecretKey::from_pkcs8_der(&key.data)
.map_err(|_| CryptoError::DecodePrivateKey)?;
let public_key = match public_key.r#type {
KeyType::Private => {
p521::SecretKey::from_pkcs8_der(&public_key.data)
.map_err(|_| CryptoError::DecodePrivateKey)?
.public_key()
}
KeyType::Public => {
let point = p521::EncodedPoint::from_bytes(public_key.data)
.map_err(|_| CryptoError::DecodePrivateKey)?;
let pk = p521::PublicKey::from_encoded_point(&point);
if pk.is_some().into() {
pk.unwrap()
} else {
return Err(CryptoError::DecodePrivateKey);
}
}
_ => unreachable!(),
};
let shared_secret = p521::elliptic_curve::ecdh::diffie_hellman(
secret_key.to_nonzero_scalar(),
public_key.as_affine(),
);
Ok(shared_secret.raw_secret_bytes().to_vec())
}
}
}
Algorithm::Hkdf => {
let salt = salt.ok_or_else(JsErrorBox::not_supported)?;
let algorithm = match hash.ok_or_else(JsErrorBox::not_supported)? {
CryptoHash::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY,
CryptoHash::Sha256 => hkdf::HKDF_SHA256,
CryptoHash::Sha384 => hkdf::HKDF_SHA384,
CryptoHash::Sha512 => hkdf::HKDF_SHA512,
_ => return Err(CryptoError::UnsupportedAlgorithm),
};
let info = info.ok_or(CryptoError::MissingArgumentInfo)?;
let secret = key.data;
let length = length / 8;
let salt = hkdf::Salt::new(algorithm, &salt);
let prk = salt.extract(&secret);
let info_slice: &[&[u8]] = &[&info];
let okm = prk
.expand(info_slice, HkdfOutput(length))
.map_err(|_e| CryptoError::HKDFLengthTooLarge)?;
let mut r = vec![0u8; length];
okm.fill(&mut r)?;
Ok(r)
}
_ => Err(CryptoError::UnsupportedAlgorithm),
}
}
fn read_rsa_public_key(key_data: KeyData) -> Result<RsaPublicKey, CryptoError> {
let public_key = match key_data.r#type {
KeyType::Private => {
RsaPrivateKey::from_pkcs1_der(&key_data.data)?.to_public_key()
}
KeyType::Public => RsaPublicKey::from_pkcs1_der(&key_data.data)?,
KeyType::Secret => unreachable!("unexpected KeyType::Secret"),
};
Ok(public_key)
}
const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
pub(crate) fn fast_uuid_v4(bytes: &mut [u8; 16]) -> String {
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
let buf = [
HEX_CHARS[(bytes[0] >> 4) as usize],
HEX_CHARS[(bytes[0] & 0x0f) as usize],
HEX_CHARS[(bytes[1] >> 4) as usize],
HEX_CHARS[(bytes[1] & 0x0f) as usize],
HEX_CHARS[(bytes[2] >> 4) as usize],
HEX_CHARS[(bytes[2] & 0x0f) as usize],
HEX_CHARS[(bytes[3] >> 4) as usize],
HEX_CHARS[(bytes[3] & 0x0f) as usize],
b'-',
HEX_CHARS[(bytes[4] >> 4) as usize],
HEX_CHARS[(bytes[4] & 0x0f) as usize],
HEX_CHARS[(bytes[5] >> 4) as usize],
HEX_CHARS[(bytes[5] & 0x0f) as usize],
b'-',
HEX_CHARS[(bytes[6] >> 4) as usize],
HEX_CHARS[(bytes[6] & 0x0f) as usize],
HEX_CHARS[(bytes[7] >> 4) as usize],
HEX_CHARS[(bytes[7] & 0x0f) as usize],
b'-',
HEX_CHARS[(bytes[8] >> 4) as usize],
HEX_CHARS[(bytes[8] & 0x0f) as usize],
HEX_CHARS[(bytes[9] >> 4) as usize],
HEX_CHARS[(bytes[9] & 0x0f) as usize],
b'-',
HEX_CHARS[(bytes[10] >> 4) as usize],
HEX_CHARS[(bytes[10] & 0x0f) as usize],
HEX_CHARS[(bytes[11] >> 4) as usize],
HEX_CHARS[(bytes[11] & 0x0f) as usize],
HEX_CHARS[(bytes[12] >> 4) as usize],
HEX_CHARS[(bytes[12] & 0x0f) as usize],
HEX_CHARS[(bytes[13] >> 4) as usize],
HEX_CHARS[(bytes[13] & 0x0f) as usize],
HEX_CHARS[(bytes[14] >> 4) as usize],
HEX_CHARS[(bytes[14] & 0x0f) as usize],
HEX_CHARS[(bytes[15] >> 4) as usize],
HEX_CHARS[(bytes[15] & 0x0f) as usize],
];
unsafe { String::from_utf8_unchecked(buf.to_vec()) }
}
#[test]
fn test_fast_uuid_v4_correctness() {
use rand::Rng;
let mut rng = rand::thread_rng();
let mut bytes = [0u8; 16];
rng.fill(&mut bytes);
let uuid = fast_uuid_v4(&mut bytes.clone());
let uuid_lib = uuid::Builder::from_bytes(bytes)
.set_variant(uuid::Variant::RFC4122)
.set_version(uuid::Version::Random)
.as_uuid()
.to_string();
assert_eq!(uuid, uuid_lib);
}