2024-01-01 14:58:21 -05:00
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2020-09-05 20:34:02 -04:00
2022-01-10 23:44:47 -05:00
use aes_kw ::KekAes128 ;
use aes_kw ::KekAes192 ;
use aes_kw ::KekAes256 ;
2023-10-26 12:39:04 -04:00
use base64 ::prelude ::BASE64_URL_SAFE_NO_PAD ;
use base64 ::Engine ;
2021-07-06 08:16:04 -04:00
use deno_core ::error ::custom_error ;
use deno_core ::error ::not_supported ;
use deno_core ::error ::type_error ;
2020-09-14 12:48:57 -04:00
use deno_core ::error ::AnyError ;
2023-09-13 11:54:19 -04:00
use deno_core ::op2 ;
2023-06-22 17:37:56 -04:00
use deno_core ::ToJsBuffer ;
2022-03-14 13:44:15 -04:00
2023-08-23 19:03:05 -04:00
use deno_core ::unsync ::spawn_blocking ;
2023-06-22 17:37:56 -04:00
use deno_core ::JsBuffer ;
2020-09-10 09:57:45 -04:00
use deno_core ::OpState ;
2021-07-06 08:16:04 -04:00
use serde ::Deserialize ;
2022-01-10 23:44:47 -05:00
use shared ::operation_error ;
2021-07-06 08:16:04 -04:00
2021-12-16 11:28:43 -05:00
use p256 ::elliptic_curve ::sec1 ::FromEncodedPoint ;
2022-06-20 07:23:57 -04:00
use p256 ::pkcs8 ::DecodePrivateKey ;
2021-07-06 08:16:04 -04:00
use rand ::rngs ::OsRng ;
2020-09-18 14:39:47 -04:00
use rand ::rngs ::StdRng ;
2019-08-14 11:03:02 -04:00
use rand ::thread_rng ;
use rand ::Rng ;
2021-04-28 12:41:50 -04:00
use rand ::SeedableRng ;
2021-06-06 06:57:10 -04:00
use ring ::digest ;
2021-09-11 16:54:03 -04:00
use ring ::hkdf ;
2021-07-06 08:16:04 -04:00
use ring ::hmac ::Algorithm as HmacAlgorithm ;
use ring ::hmac ::Key as HmacKey ;
2021-08-26 06:48:07 -04:00
use ring ::pbkdf2 ;
2021-07-06 08:16:04 -04:00
use ring ::rand as RingRand ;
use ring ::signature ::EcdsaKeyPair ;
use ring ::signature ::EcdsaSigningAlgorithm ;
2021-09-11 16:49:53 -04:00
use ring ::signature ::EcdsaVerificationAlgorithm ;
use ring ::signature ::KeyPair ;
2022-06-20 07:23:57 -04:00
use rsa ::pkcs1 ::DecodeRsaPrivateKey ;
use rsa ::pkcs1 ::DecodeRsaPublicKey ;
2023-10-30 11:25:12 -04:00
use rsa ::signature ::SignatureEncoding ;
use rsa ::signature ::Signer ;
use rsa ::signature ::Verifier ;
use rsa ::traits ::SignatureScheme ;
use rsa ::Pss ;
2021-08-06 04:10:50 -04:00
use rsa ::RsaPrivateKey ;
use rsa ::RsaPublicKey ;
2021-07-06 08:16:04 -04:00
use sha1 ::Sha1 ;
2023-10-30 11:25:12 -04:00
use sha2 ::Digest ;
2021-07-06 08:16:04 -04:00
use sha2 ::Sha256 ;
use sha2 ::Sha384 ;
use sha2 ::Sha512 ;
2022-06-20 07:23:57 -04:00
use std ::num ::NonZeroU32 ;
2022-03-16 20:25:44 -04:00
use std ::path ::PathBuf ;
2019-08-14 11:03:02 -04:00
2020-11-13 16:01:57 -05:00
pub use rand ; // Re-export rand
2021-12-20 10:07:36 -05:00
mod decrypt ;
2022-09-27 08:13:42 -04:00
mod ed25519 ;
2021-12-15 16:18:26 -05:00
mod encrypt ;
2021-12-13 07:22:03 -05:00
mod export_key ;
2021-12-13 12:45:08 -05:00
mod generate_key ;
2021-12-10 09:06:03 -05:00
mod import_key ;
2021-07-06 08:16:04 -04:00
mod key ;
2021-12-10 09:06:03 -05:00
mod shared ;
2022-09-27 08:13:42 -04:00
mod x25519 ;
2024-10-07 07:04:40 -04:00
mod x448 ;
2021-07-06 08:16:04 -04:00
2021-12-20 10:07:36 -05:00
pub use crate ::decrypt ::op_crypto_decrypt ;
2021-12-15 16:18:26 -05:00
pub use crate ::encrypt ::op_crypto_encrypt ;
2021-12-13 12:45:08 -05:00
pub use crate ::export_key ::op_crypto_export_key ;
pub use crate ::generate_key ::op_crypto_generate_key ;
pub use crate ::import_key ::op_crypto_import_key ;
2021-07-06 08:16:04 -04:00
use crate ::key ::Algorithm ;
use crate ::key ::CryptoHash ;
use crate ::key ::CryptoNamedCurve ;
2021-09-11 16:54:03 -04:00
use crate ::key ::HkdfOutput ;
2023-06-22 17:37:56 -04:00
use crate ::shared ::V8RawKeyData ;
2021-07-06 08:16:04 -04:00
2023-03-17 14:22:15 -04:00
deno_core ::extension! ( deno_crypto ,
deps = [ deno_webidl , deno_web ] ,
ops = [
op_crypto_get_random_values ,
op_crypto_generate_key ,
op_crypto_sign_key ,
op_crypto_verify_key ,
op_crypto_derive_bits ,
op_crypto_import_key ,
op_crypto_export_key ,
op_crypto_encrypt ,
op_crypto_decrypt ,
op_crypto_subtle_digest ,
op_crypto_random_uuid ,
op_crypto_wrap_key ,
op_crypto_unwrap_key ,
op_crypto_base64url_decode ,
op_crypto_base64url_encode ,
2023-05-08 17:07:45 -04:00
x25519 ::op_crypto_generate_x25519_keypair ,
x25519 ::op_crypto_derive_bits_x25519 ,
x25519 ::op_crypto_import_spki_x25519 ,
x25519 ::op_crypto_import_pkcs8_x25519 ,
2024-10-07 07:04:40 -04:00
x25519 ::op_crypto_export_spki_x25519 ,
x25519 ::op_crypto_export_pkcs8_x25519 ,
x448 ::op_crypto_generate_x448_keypair ,
x448 ::op_crypto_derive_bits_x448 ,
x448 ::op_crypto_import_spki_x448 ,
x448 ::op_crypto_import_pkcs8_x448 ,
x448 ::op_crypto_export_spki_x448 ,
x448 ::op_crypto_export_pkcs8_x448 ,
2023-05-08 17:07:45 -04:00
ed25519 ::op_crypto_generate_ed25519_keypair ,
ed25519 ::op_crypto_import_spki_ed25519 ,
ed25519 ::op_crypto_import_pkcs8_ed25519 ,
ed25519 ::op_crypto_sign_ed25519 ,
ed25519 ::op_crypto_verify_ed25519 ,
ed25519 ::op_crypto_export_spki_ed25519 ,
ed25519 ::op_crypto_export_pkcs8_ed25519 ,
ed25519 ::op_crypto_jwk_x_ed25519 ,
2023-03-17 14:22:15 -04:00
] ,
2023-05-09 06:37:13 -04:00
esm = [ " 00_crypto.js " ] ,
2023-03-17 18:15:27 -04:00
options = {
2023-03-17 14:22:15 -04:00
maybe_seed : Option < u64 > ,
} ,
2023-03-17 18:15:27 -04:00
state = | state , options | {
if let Some ( seed ) = options . maybe_seed {
2023-03-17 14:22:15 -04:00
state . put ( StdRng ::seed_from_u64 ( seed ) ) ;
}
} ,
) ;
2019-10-11 14:41:54 -04:00
2023-09-13 11:54:19 -04:00
#[ op2 ]
#[ serde ]
2023-06-05 08:52:02 -04:00
pub fn op_crypto_base64url_decode (
2023-09-13 11:54:19 -04:00
#[ string ] data : String ,
2023-06-22 17:37:56 -04:00
) -> Result < ToJsBuffer , AnyError > {
2023-10-26 12:39:04 -04:00
let data : Vec < u8 > = BASE64_URL_SAFE_NO_PAD . decode ( data ) ? ;
2023-06-05 08:52:02 -04:00
Ok ( data . into ( ) )
2022-09-27 08:13:42 -04:00
}
2023-09-13 11:54:19 -04:00
#[ op2 ]
#[ string ]
pub fn op_crypto_base64url_encode ( #[ buffer ] data : JsBuffer ) -> String {
2023-10-26 12:39:04 -04:00
let data : String = BASE64_URL_SAFE_NO_PAD . encode ( data ) ;
2022-10-04 02:06:25 -04:00
data
}
2023-09-13 11:54:19 -04:00
#[ op2(fast) ]
2021-01-14 19:24:38 -05:00
pub fn op_crypto_get_random_values (
2020-09-10 09:57:45 -04:00
state : & mut OpState ,
2023-09-13 11:54:19 -04:00
#[ buffer ] out : & mut [ u8 ] ,
2021-04-05 12:40:24 -04:00
) -> Result < ( ) , AnyError > {
2022-10-09 06:08:38 -04:00
if out . len ( ) > 65536 {
2024-10-17 15:05:38 -04:00
return Err ( custom_error ( " DOMExceptionQuotaExceededError " , format! ( " The ArrayBufferView's byte length ( {} ) exceeds the number of bytes of entropy available via this API (65536) " , out . len ( ) ) ) ) ;
2021-06-05 13:30:20 -04:00
}
2020-09-18 14:39:47 -04:00
let maybe_seeded_rng = state . try_borrow_mut ::< StdRng > ( ) ;
if let Some ( seeded_rng ) = maybe_seeded_rng {
2022-10-09 06:08:38 -04:00
seeded_rng . fill ( out ) ;
2019-08-14 11:03:02 -04:00
} else {
let mut rng = thread_rng ( ) ;
2022-10-09 06:08:38 -04:00
rng . fill ( out ) ;
2019-08-14 11:03:02 -04:00
}
2021-04-05 12:40:24 -04:00
Ok ( ( ) )
2019-08-14 11:03:02 -04:00
}
2021-02-26 12:06:26 -05:00
2021-07-06 08:16:04 -04:00
#[ derive(Deserialize) ]
#[ serde(rename_all = " lowercase " ) ]
pub enum KeyFormat {
Raw ,
Pkcs8 ,
2021-10-06 05:18:12 -04:00
Spki ,
2021-07-06 08:16:04 -04:00
}
2021-12-09 14:32:55 -05:00
#[ derive(Deserialize) ]
#[ serde(rename_all = " lowercase " ) ]
pub enum KeyType {
Secret ,
Private ,
Public ,
}
2021-07-06 08:16:04 -04:00
#[ derive(Deserialize) ]
#[ serde(rename_all = " lowercase " ) ]
pub struct KeyData {
2021-12-09 14:32:55 -05:00
r#type : KeyType ,
2023-06-22 17:37:56 -04:00
data : JsBuffer ,
2021-07-06 08:16:04 -04:00
}
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct SignArg {
key : KeyData ,
algorithm : Algorithm ,
salt_length : Option < u32 > ,
hash : Option < CryptoHash > ,
named_curve : Option < CryptoNamedCurve > ,
}
2023-09-13 11:54:19 -04:00
#[ op2(async) ]
#[ serde ]
2021-07-06 08:16:04 -04:00
pub async fn op_crypto_sign_key (
2023-09-13 11:54:19 -04:00
#[ serde ] args : SignArg ,
#[ buffer ] zero_copy : JsBuffer ,
2023-06-22 17:37:56 -04:00
) -> Result < ToJsBuffer , AnyError > {
2024-03-11 23:48:00 -04:00
deno_core ::unsync ::spawn_blocking ( move | | {
let data = & * zero_copy ;
let algorithm = args . algorithm ;
let signature = match algorithm {
Algorithm ::RsassaPkcs1v15 = > {
use rsa ::pkcs1v15 ::SigningKey ;
let private_key = RsaPrivateKey ::from_pkcs1_der ( & args . key . data ) ? ;
match args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ?
{
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 )
}
2021-07-07 10:33:58 -04:00
}
2024-03-11 23:48:00 -04:00
. to_vec ( )
2023-01-18 10:18:41 -05:00
}
2024-03-11 23:48:00 -04:00
Algorithm ::RsaPss = > {
let private_key = RsaPrivateKey ::from_pkcs1_der ( & args . key . data ) ? ;
let salt_len = args . salt_length . ok_or_else ( | | {
type_error ( " Missing argument saltLength " . to_string ( ) )
} ) ? as usize ;
let mut rng = OsRng ;
match args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ?
{
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 ) ?
}
2021-07-06 08:16:04 -04:00
}
2024-03-11 23:48:00 -04:00
. to_vec ( )
2023-01-18 10:18:41 -05:00
}
2024-03-11 23:48:00 -04:00
Algorithm ::Ecdsa = > {
let curve : & EcdsaSigningAlgorithm =
args . named_curve . ok_or_else ( not_supported ) ? . into ( ) ;
let rng = RingRand ::SystemRandom ::new ( ) ;
let key_pair = EcdsaKeyPair ::from_pkcs8 ( curve , & args . key . data , & rng ) ? ;
// We only support P256-SHA256 & P384-SHA384. These are recommended signature pairs.
// https://briansmith.org/rustdoc/ring/signature/index.html#statics
if let Some ( hash ) = args . hash {
match hash {
CryptoHash ::Sha256 | CryptoHash ::Sha384 = > ( ) ,
_ = > return Err ( type_error ( " Unsupported algorithm " ) ) ,
}
} ;
let signature = key_pair . sign ( & rng , data ) ? ;
// Signature data as buffer.
signature . as_ref ( ) . to_vec ( )
}
Algorithm ::Hmac = > {
let hash : HmacAlgorithm = args . hash . ok_or_else ( not_supported ) ? . into ( ) ;
2021-07-06 08:16:04 -04:00
2024-03-11 23:48:00 -04:00
let key = HmacKey ::new ( hash , & args . key . data ) ;
2021-07-06 08:16:04 -04:00
2024-03-11 23:48:00 -04:00
let signature = ring ::hmac ::sign ( & key , data ) ;
signature . as_ref ( ) . to_vec ( )
}
_ = > return Err ( type_error ( " Unsupported algorithm " . to_string ( ) ) ) ,
} ;
2021-07-06 08:16:04 -04:00
2024-03-11 23:48:00 -04:00
Ok ( signature . into ( ) )
} )
. await ?
2021-07-06 08:16:04 -04:00
}
2021-07-12 08:45:36 -04:00
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct VerifyArg {
key : KeyData ,
algorithm : Algorithm ,
2023-10-30 11:25:12 -04:00
salt_length : Option < u32 > ,
2021-07-12 08:45:36 -04:00
hash : Option < CryptoHash > ,
2023-06-22 17:37:56 -04:00
signature : JsBuffer ,
2021-09-11 16:49:53 -04:00
named_curve : Option < CryptoNamedCurve > ,
2021-07-12 08:45:36 -04:00
}
2023-09-13 11:54:19 -04:00
#[ op2(async) ]
2021-07-12 08:45:36 -04:00
pub async fn op_crypto_verify_key (
2023-09-13 11:54:19 -04:00
#[ serde ] args : VerifyArg ,
#[ buffer ] zero_copy : JsBuffer ,
2021-07-12 08:45:36 -04:00
) -> Result < bool , AnyError > {
2024-03-11 23:48:00 -04:00
deno_core ::unsync ::spawn_blocking ( move | | {
let data = & * zero_copy ;
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 ( args . key ) ? ;
let signature : Signature = args . signature . as_ref ( ) . try_into ( ) ? ;
match args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ?
{
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 ( )
}
2021-07-12 08:45:36 -04:00
}
2023-01-18 10:18:41 -05:00
}
2024-03-11 23:48:00 -04:00
Algorithm ::RsaPss = > {
let public_key = read_rsa_public_key ( args . key ) ? ;
let signature = args . signature . as_ref ( ) ;
let salt_len = args . salt_length . ok_or_else ( | | {
type_error ( " Missing argument saltLength " . to_string ( ) )
} ) ? as usize ;
match args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ?
{
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 ( )
}
2021-07-12 08:45:36 -04:00
}
2023-01-18 10:18:41 -05:00
}
2024-03-11 23:48:00 -04:00
Algorithm ::Hmac = > {
let hash : HmacAlgorithm = args . hash . ok_or_else ( not_supported ) ? . into ( ) ;
let key = HmacKey ::new ( hash , & args . key . data ) ;
ring ::hmac ::verify ( & key , data , & args . signature ) . is_ok ( )
}
Algorithm ::Ecdsa = > {
let signing_alg : & EcdsaSigningAlgorithm =
args . named_curve . ok_or_else ( not_supported ) ? . into ( ) ;
let verify_alg : & EcdsaVerificationAlgorithm =
args . named_curve . ok_or_else ( not_supported ) ? . into ( ) ;
let private_key ;
let public_key_bytes = match args . key . r#type {
KeyType ::Private = > {
let rng = RingRand ::SystemRandom ::new ( ) ;
private_key =
EcdsaKeyPair ::from_pkcs8 ( signing_alg , & args . key . data , & rng ) ? ;
private_key . public_key ( ) . as_ref ( )
}
KeyType ::Public = > & * args . key . data ,
_ = > return Err ( type_error ( " Invalid Key format " . to_string ( ) ) ) ,
} ;
let public_key =
ring ::signature ::UnparsedPublicKey ::new ( verify_alg , public_key_bytes ) ;
public_key . verify ( data , & args . signature ) . is_ok ( )
}
_ = > return Err ( type_error ( " Unsupported algorithm " . to_string ( ) ) ) ,
} ;
2021-07-12 08:45:36 -04:00
2024-03-11 23:48:00 -04:00
Ok ( verification )
} )
. await ?
2021-07-12 08:45:36 -04:00
}
2021-08-26 06:48:07 -04:00
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct DeriveKeyArg {
key : KeyData ,
algorithm : Algorithm ,
hash : Option < CryptoHash > ,
length : usize ,
iterations : Option < u32 > ,
2021-10-08 11:29:36 -04:00
// ECDH
public_key : Option < KeyData > ,
named_curve : Option < CryptoNamedCurve > ,
// HKDF
2023-06-22 17:37:56 -04:00
info : Option < JsBuffer > ,
2021-08-26 06:48:07 -04:00
}
2023-09-21 10:08:23 -04:00
#[ op2(async) ]
#[ serde ]
2021-08-26 06:48:07 -04:00
pub async fn op_crypto_derive_bits (
2023-09-21 10:08:23 -04:00
#[ serde ] args : DeriveKeyArg ,
#[ buffer ] zero_copy : Option < JsBuffer > ,
2023-06-22 17:37:56 -04:00
) -> Result < ToJsBuffer , AnyError > {
2024-03-11 23:48:00 -04:00
deno_core ::unsync ::spawn_blocking ( move | | {
let algorithm = args . algorithm ;
match algorithm {
Algorithm ::Pbkdf2 = > {
let zero_copy = zero_copy . ok_or_else ( not_supported ) ? ;
let salt = & * zero_copy ;
// The caller must validate these cases.
assert! ( args . length > 0 ) ;
assert! ( args . length % 8 = = 0 ) ;
let algorithm = match args . hash . ok_or_else ( 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 ,
} ;
// This will never panic. We have already checked length earlier.
let iterations =
NonZeroU32 ::new ( args . iterations . ok_or_else ( not_supported ) ? ) . unwrap ( ) ;
let secret = args . key . data ;
let mut out = vec! [ 0 ; args . length / 8 ] ;
pbkdf2 ::derive ( algorithm , iterations , salt , & secret , & mut out ) ;
Ok ( out . into ( ) )
}
Algorithm ::Ecdh = > {
let named_curve = args . named_curve . ok_or_else ( | | {
type_error ( " Missing argument namedCurve " . to_string ( ) )
} ) ? ;
let public_key = args
. public_key
. ok_or_else ( | | type_error ( " Missing argument publicKey " ) ) ? ;
match named_curve {
CryptoNamedCurve ::P256 = > {
let secret_key = p256 ::SecretKey ::from_pkcs8_der ( & args . key . data )
. map_err ( | _ | {
type_error ( " Unexpected error decoding private key " )
} ) ? ;
let public_key = match public_key . r#type {
KeyType ::Private = > {
p256 ::SecretKey ::from_pkcs8_der ( & public_key . data )
. map_err ( | _ | {
type_error ( " Unexpected error decoding private key " )
} ) ?
. public_key ( )
2021-12-16 11:28:43 -05:00
}
2024-03-11 23:48:00 -04:00
KeyType ::Public = > {
let point = p256 ::EncodedPoint ::from_bytes ( public_key . data )
. map_err ( | _ | {
type_error ( " Unexpected error decoding private key " )
} ) ? ;
let pk = p256 ::PublicKey ::from_encoded_point ( & point ) ;
// pk is a constant time Option.
if pk . is_some ( ) . into ( ) {
pk . unwrap ( )
} else {
return Err ( type_error (
" Unexpected error decoding private key " ,
) ) ;
}
2022-07-23 13:04:37 -04:00
}
2024-03-11 23:48:00 -04:00
_ = > unreachable! ( ) ,
} ;
let shared_secret = p256 ::elliptic_curve ::ecdh ::diffie_hellman (
secret_key . to_nonzero_scalar ( ) ,
public_key . as_affine ( ) ,
) ;
// raw serialized x-coordinate of the computed point
Ok ( shared_secret . raw_secret_bytes ( ) . to_vec ( ) . into ( ) )
}
CryptoNamedCurve ::P384 = > {
let secret_key = p384 ::SecretKey ::from_pkcs8_der ( & args . key . data )
. map_err ( | _ | {
type_error ( " Unexpected error decoding private key " )
} ) ? ;
let public_key = match public_key . r#type {
KeyType ::Private = > {
p384 ::SecretKey ::from_pkcs8_der ( & public_key . data )
. map_err ( | _ | {
type_error ( " Unexpected error decoding private key " )
} ) ?
. public_key ( )
}
KeyType ::Public = > {
let point = p384 ::EncodedPoint ::from_bytes ( public_key . data )
. map_err ( | _ | {
type_error ( " Unexpected error decoding private key " )
} ) ? ;
let pk = p384 ::PublicKey ::from_encoded_point ( & point ) ;
// pk is a constant time Option.
if pk . is_some ( ) . into ( ) {
pk . unwrap ( )
} else {
return Err ( type_error (
" Unexpected error decoding private key " ,
) ) ;
}
}
_ = > unreachable! ( ) ,
} ;
2022-07-23 13:04:37 -04:00
2024-03-11 23:48:00 -04:00
let shared_secret = p384 ::elliptic_curve ::ecdh ::diffie_hellman (
secret_key . to_nonzero_scalar ( ) ,
public_key . as_affine ( ) ,
) ;
2022-07-23 13:04:37 -04:00
2024-03-11 23:48:00 -04:00
// raw serialized x-coordinate of the computed point
Ok ( shared_secret . raw_secret_bytes ( ) . to_vec ( ) . into ( ) )
}
2022-07-23 13:04:37 -04:00
}
2021-10-08 11:29:36 -04:00
}
2024-03-11 23:48:00 -04:00
Algorithm ::Hkdf = > {
let zero_copy = zero_copy . ok_or_else ( not_supported ) ? ;
let salt = & * zero_copy ;
let algorithm = match args . hash . ok_or_else ( 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 ,
} ;
let info = args
. info
. ok_or_else ( | | type_error ( " Missing argument info " . to_string ( ) ) ) ? ;
// IKM
let secret = args . key . data ;
// L
let length = args . length / 8 ;
let salt = hkdf ::Salt ::new ( algorithm , salt ) ;
let prk = salt . extract ( & secret ) ;
let info = & [ & * info ] ;
let okm = prk . expand ( info , HkdfOutput ( length ) ) . map_err ( | _e | {
custom_error (
" DOMExceptionOperationError " ,
" The length provided for HKDF is too large " ,
)
} ) ? ;
let mut r = vec! [ 0 u8 ; length ] ;
okm . fill ( & mut r ) ? ;
Ok ( r . into ( ) )
}
_ = > Err ( type_error ( " Unsupported algorithm " . to_string ( ) ) ) ,
2021-10-08 11:29:36 -04:00
}
2024-03-11 23:48:00 -04:00
} )
. await ?
2021-08-26 06:48:07 -04:00
}
2021-12-09 14:32:55 -05:00
fn read_rsa_public_key ( key_data : KeyData ) -> Result < RsaPublicKey , AnyError > {
let public_key = match key_data . r#type {
KeyType ::Private = > {
2022-11-17 20:59:10 -05:00
RsaPrivateKey ::from_pkcs1_der ( & key_data . data ) ? . to_public_key ( )
2021-12-09 14:32:55 -05:00
}
2022-11-17 20:59:10 -05:00
KeyType ::Public = > RsaPublicKey ::from_pkcs1_der ( & key_data . data ) ? ,
2021-12-09 14:32:55 -05:00
KeyType ::Secret = > unreachable! ( " unexpected KeyType::Secret " ) ,
} ;
Ok ( public_key )
}
2023-09-13 11:54:19 -04:00
#[ op2 ]
#[ string ]
2022-03-14 18:38:53 -04:00
pub fn op_crypto_random_uuid ( state : & mut OpState ) -> Result < String , AnyError > {
2021-06-05 08:46:24 -04:00
let maybe_seeded_rng = state . try_borrow_mut ::< StdRng > ( ) ;
let uuid = if let Some ( seeded_rng ) = maybe_seeded_rng {
let mut bytes = [ 0 u8 ; 16 ] ;
seeded_rng . fill ( & mut bytes ) ;
2024-07-12 01:20:32 -04:00
fast_uuid_v4 ( & mut bytes )
2021-06-05 08:46:24 -04:00
} else {
2024-07-12 01:20:32 -04:00
let mut rng = thread_rng ( ) ;
let mut bytes = [ 0 u8 ; 16 ] ;
rng . fill ( & mut bytes ) ;
fast_uuid_v4 ( & mut bytes )
2021-06-05 08:46:24 -04:00
} ;
2024-07-12 01:20:32 -04:00
Ok ( uuid )
2021-06-05 08:46:24 -04:00
}
2023-09-13 11:54:19 -04:00
#[ op2(async) ]
#[ serde ]
2021-06-06 06:57:10 -04:00
pub async fn op_crypto_subtle_digest (
2023-09-13 11:54:19 -04:00
#[ serde ] algorithm : CryptoHash ,
#[ buffer ] data : JsBuffer ,
2023-06-22 17:37:56 -04:00
) -> Result < ToJsBuffer , AnyError > {
2023-05-14 17:40:01 -04:00
let output = spawn_blocking ( move | | {
2021-10-05 16:38:27 -04:00
digest ::digest ( algorithm . into ( ) , & data )
2021-07-07 14:34:02 -04:00
. as_ref ( )
. to_vec ( )
. into ( )
2021-06-06 06:57:10 -04:00
} )
. await ? ;
Ok ( output )
}
2022-01-10 23:44:47 -05:00
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct WrapUnwrapKeyArg {
2023-06-22 17:37:56 -04:00
key : V8RawKeyData ,
2022-01-10 23:44:47 -05:00
algorithm : Algorithm ,
}
2023-09-13 11:54:19 -04:00
#[ op2 ]
#[ serde ]
2022-01-10 23:44:47 -05:00
pub fn op_crypto_wrap_key (
2023-09-13 11:54:19 -04:00
#[ serde ] args : WrapUnwrapKeyArg ,
#[ buffer ] data : JsBuffer ,
2023-06-22 17:37:56 -04:00
) -> Result < ToJsBuffer , AnyError > {
2022-01-10 23:44:47 -05:00
let algorithm = args . algorithm ;
match algorithm {
Algorithm ::AesKw = > {
let key = args . key . as_secret_key ( ) ? ;
if data . len ( ) % 8 ! = 0 {
return Err ( type_error ( " Data must be multiple of 8 bytes " ) ) ;
}
let wrapped_key = match key . len ( ) {
16 = > KekAes128 ::new ( key . into ( ) ) . wrap_vec ( & data ) ,
24 = > KekAes192 ::new ( key . into ( ) ) . wrap_vec ( & data ) ,
32 = > KekAes256 ::new ( key . into ( ) ) . wrap_vec ( & data ) ,
_ = > return Err ( type_error ( " Invalid key length " ) ) ,
}
. map_err ( | _ | operation_error ( " encryption error " ) ) ? ;
Ok ( wrapped_key . into ( ) )
}
_ = > Err ( type_error ( " Unsupported algorithm " ) ) ,
}
}
2023-09-13 11:54:19 -04:00
#[ op2 ]
#[ serde ]
2022-01-10 23:44:47 -05:00
pub fn op_crypto_unwrap_key (
2023-09-13 11:54:19 -04:00
#[ serde ] args : WrapUnwrapKeyArg ,
#[ buffer ] data : JsBuffer ,
2023-06-22 17:37:56 -04:00
) -> Result < ToJsBuffer , AnyError > {
2022-01-10 23:44:47 -05:00
let algorithm = args . algorithm ;
match algorithm {
Algorithm ::AesKw = > {
let key = args . key . as_secret_key ( ) ? ;
if data . len ( ) % 8 ! = 0 {
return Err ( type_error ( " Data must be multiple of 8 bytes " ) ) ;
}
let unwrapped_key = match key . len ( ) {
16 = > KekAes128 ::new ( key . into ( ) ) . unwrap_vec ( & data ) ,
24 = > KekAes192 ::new ( key . into ( ) ) . unwrap_vec ( & data ) ,
32 = > KekAes256 ::new ( key . into ( ) ) . unwrap_vec ( & data ) ,
_ = > return Err ( type_error ( " Invalid key length " ) ) ,
}
. map_err ( | _ | {
operation_error ( " decryption error - integrity check failed " )
} ) ? ;
Ok ( unwrapped_key . into ( ) )
}
_ = > Err ( type_error ( " Unsupported algorithm " ) ) ,
}
}
2022-03-16 20:25:44 -04:00
pub fn get_declaration ( ) -> PathBuf {
PathBuf ::from ( env! ( " CARGO_MANIFEST_DIR " ) ) . join ( " lib.deno_crypto.d.ts " )
}
2024-07-12 01:20:32 -04:00
const HEX_CHARS : & [ u8 ; 16 ] = b " 0123456789abcdef " ;
fn fast_uuid_v4 ( bytes : & mut [ u8 ; 16 ] ) -> String {
// Set UUID version to 4 and variant to 1.
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 ] ,
] ;
// Safety: the buffer is all valid UTF-8.
unsafe { String ::from_utf8_unchecked ( buf . to_vec ( ) ) }
}
#[ test ]
fn test_fast_uuid_v4_correctness ( ) {
let mut rng = thread_rng ( ) ;
let mut bytes = [ 0 u8 ; 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 ) ;
}