2021-01-11 12:13:41 -05:00
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
2020-09-05 20:34:02 -04:00
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 ;
2021-04-28 12:41:50 -04:00
use deno_core ::include_js_files ;
2021-06-06 06:57:10 -04:00
use deno_core ::op_async ;
2021-04-28 12:41:50 -04:00
use deno_core ::op_sync ;
use deno_core ::Extension ;
2020-09-10 09:57:45 -04:00
use deno_core ::OpState ;
2020-04-23 05:51:07 -04:00
use deno_core ::ZeroCopyBuf ;
2021-07-06 08:16:04 -04:00
use serde ::Deserialize ;
2021-09-14 09:21:20 -04:00
use serde ::Serialize ;
2021-07-06 08:16:04 -04:00
use std ::cell ::RefCell ;
2021-09-14 09:21:20 -04:00
use std ::convert ::TryFrom ;
2021-07-06 08:16:04 -04:00
use std ::convert ::TryInto ;
2021-08-26 06:48:07 -04:00
use std ::num ::NonZeroU32 ;
2021-07-06 08:16:04 -04:00
use std ::rc ::Rc ;
2021-10-11 10:37:51 -04:00
use block_modes ::BlockMode ;
2021-07-06 08:16:04 -04:00
use lazy_static ::lazy_static ;
use num_traits ::cast ::FromPrimitive ;
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 ::rand ::SecureRandom ;
use ring ::signature ::EcdsaKeyPair ;
use ring ::signature ::EcdsaSigningAlgorithm ;
2021-09-11 16:49:53 -04:00
use ring ::signature ::EcdsaVerificationAlgorithm ;
use ring ::signature ::KeyPair ;
2021-07-06 08:16:04 -04:00
use rsa ::padding ::PaddingScheme ;
2021-09-14 09:21:20 -04:00
use rsa ::pkcs1 ::der ::Decodable ;
use rsa ::pkcs1 ::der ::Encodable ;
2021-09-13 05:33:28 -04:00
use rsa ::pkcs1 ::FromRsaPrivateKey ;
use rsa ::pkcs1 ::ToRsaPrivateKey ;
use rsa ::pkcs8 ::der ::asn1 ;
2021-10-08 11:29:36 -04:00
use rsa ::pkcs8 ::FromPrivateKey ;
2021-07-06 08:16:04 -04:00
use rsa ::BigUint ;
2021-07-12 08:45:36 -04:00
use rsa ::PublicKey ;
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 ;
use sha2 ::Digest ;
use sha2 ::Sha256 ;
use sha2 ::Sha384 ;
use sha2 ::Sha512 ;
2021-02-26 12:06:26 -05: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-07-06 08:16:04 -04:00
mod key ;
use crate ::key ::Algorithm ;
use crate ::key ::CryptoHash ;
use crate ::key ::CryptoNamedCurve ;
2021-09-11 16:54:03 -04:00
use crate ::key ::HkdfOutput ;
2021-07-06 08:16:04 -04:00
// Allowlist for RSA public exponents.
lazy_static! {
static ref PUB_EXPONENT_1 : BigUint = BigUint ::from_u64 ( 3 ) . unwrap ( ) ;
static ref PUB_EXPONENT_2 : BigUint = BigUint ::from_u64 ( 65537 ) . unwrap ( ) ;
}
2021-09-14 09:21:20 -04:00
const RSA_ENCRYPTION_OID : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.1 " ) ;
const SHA1_RSA_ENCRYPTION_OID : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.5 " ) ;
const SHA256_RSA_ENCRYPTION_OID : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.11 " ) ;
const SHA384_RSA_ENCRYPTION_OID : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.12 " ) ;
const SHA512_RSA_ENCRYPTION_OID : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.13 " ) ;
const RSASSA_PSS_OID : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.10 " ) ;
const ID_SHA1_OID : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.3.14.3.2.26 " ) ;
const ID_SHA256_OID : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 2.16.840.1.101.3.4.2.1 " ) ;
const ID_SHA384_OID : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 2.16.840.1.101.3.4.2.2 " ) ;
const ID_SHA512_OID : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 2.16.840.1.101.3.4.2.3 " ) ;
const ID_MFG1 : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.8 " ) ;
const RSAES_OAEP_OID : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.7 " ) ;
2021-10-02 09:20:53 -04:00
const ID_P_SPECIFIED : rsa ::pkcs8 ::ObjectIdentifier =
rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.9 " ) ;
2021-09-14 09:21:20 -04:00
2021-04-28 12:41:50 -04:00
pub fn init ( maybe_seed : Option < u64 > ) -> Extension {
2021-04-28 18:16:45 -04:00
Extension ::builder ( )
. js ( include_js_files! (
2021-08-11 06:27:05 -04:00
prefix " deno:ext/crypto " ,
2021-07-06 08:16:04 -04:00
" 00_crypto.js " ,
" 01_webidl.js " ,
2021-04-28 18:16:45 -04:00
) )
2021-06-05 08:46:24 -04:00
. ops ( vec! [
(
" op_crypto_get_random_values " ,
op_sync ( op_crypto_get_random_values ) ,
) ,
2021-07-06 08:16:04 -04:00
( " op_crypto_generate_key " , op_async ( op_crypto_generate_key ) ) ,
( " op_crypto_sign_key " , op_async ( op_crypto_sign_key ) ) ,
2021-07-12 08:45:36 -04:00
( " op_crypto_verify_key " , op_async ( op_crypto_verify_key ) ) ,
2021-08-26 06:48:07 -04:00
( " op_crypto_derive_bits " , op_async ( op_crypto_derive_bits ) ) ,
2021-09-14 09:21:20 -04:00
( " op_crypto_import_key " , op_async ( op_crypto_import_key ) ) ,
2021-09-13 05:33:28 -04:00
( " op_crypto_export_key " , op_async ( op_crypto_export_key ) ) ,
2021-08-24 15:59:02 -04:00
( " op_crypto_encrypt_key " , op_async ( op_crypto_encrypt_key ) ) ,
( " op_crypto_decrypt_key " , op_async ( op_crypto_decrypt_key ) ) ,
2021-06-06 06:57:10 -04:00
( " op_crypto_subtle_digest " , op_async ( op_crypto_subtle_digest ) ) ,
2021-06-05 08:46:24 -04:00
( " op_crypto_random_uuid " , op_sync ( op_crypto_random_uuid ) ) ,
] )
2021-04-28 18:16:45 -04:00
. state ( move | state | {
2021-04-28 12:41:50 -04:00
if let Some ( seed ) = maybe_seed {
state . put ( StdRng ::seed_from_u64 ( seed ) ) ;
}
Ok ( ( ) )
2021-04-28 18:16:45 -04:00
} )
. build ( )
2019-10-11 14:41:54 -04:00
}
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 ,
2021-06-05 13:30:20 -04:00
mut zero_copy : ZeroCopyBuf ,
_ : ( ) ,
2021-04-05 12:40:24 -04:00
) -> Result < ( ) , AnyError > {
2021-06-05 13:30:20 -04:00
if zero_copy . len ( ) > 65536 {
return Err (
deno_web ::DomExceptionQuotaExceededError ::new ( & format! ( " The ArrayBufferView's byte length ( {} ) exceeds the number of bytes of entropy available via this API (65536) " , zero_copy . len ( ) ) )
. into ( ) ,
) ;
}
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 {
2021-04-02 09:47:57 -04:00
seeded_rng . fill ( & mut * zero_copy ) ;
2019-08-14 11:03:02 -04:00
} else {
let mut rng = thread_rng ( ) ;
2021-04-02 09:47:57 -04:00
rng . fill ( & mut * zero_copy ) ;
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 = " camelCase " ) ]
pub struct AlgorithmArg {
name : Algorithm ,
modulus_length : Option < u32 > ,
public_exponent : Option < ZeroCopyBuf > ,
named_curve : Option < CryptoNamedCurve > ,
hash : Option < CryptoHash > ,
length : Option < usize > ,
}
pub async fn op_crypto_generate_key (
_state : Rc < RefCell < OpState > > ,
args : AlgorithmArg ,
_ : ( ) ,
) -> Result < ZeroCopyBuf , AnyError > {
let algorithm = args . name ;
let key = match algorithm {
2021-08-24 15:59:02 -04:00
Algorithm ::RsassaPkcs1v15 | Algorithm ::RsaPss | Algorithm ::RsaOaep = > {
2021-07-06 08:16:04 -04:00
let public_exponent = args . public_exponent . ok_or_else ( not_supported ) ? ;
let modulus_length = args . modulus_length . ok_or_else ( not_supported ) ? ;
let exponent = BigUint ::from_bytes_be ( & public_exponent ) ;
if exponent ! = * PUB_EXPONENT_1 & & exponent ! = * PUB_EXPONENT_2 {
return Err ( custom_error (
" DOMExceptionOperationError " ,
" Bad public exponent " ,
) ) ;
}
let mut rng = OsRng ;
2021-08-06 04:10:50 -04:00
let private_key : RsaPrivateKey = tokio ::task ::spawn_blocking (
move | | -> Result < RsaPrivateKey , rsa ::errors ::Error > {
RsaPrivateKey ::new_with_exp (
2021-07-06 08:16:04 -04:00
& mut rng ,
modulus_length as usize ,
& exponent ,
)
} ,
)
. await
. unwrap ( )
. map_err ( | e | custom_error ( " DOMExceptionOperationError " , e . to_string ( ) ) ) ? ;
2021-09-13 05:33:28 -04:00
private_key . to_pkcs1_der ( ) ? . as_ref ( ) . to_vec ( )
2021-07-06 08:16:04 -04:00
}
2021-09-13 05:35:49 -04:00
Algorithm ::Ecdsa | Algorithm ::Ecdh = > {
2021-07-06 08:16:04 -04:00
let curve : & EcdsaSigningAlgorithm =
args . named_curve . ok_or_else ( not_supported ) ? . into ( ) ;
let rng = RingRand ::SystemRandom ::new ( ) ;
let private_key : Vec < u8 > = tokio ::task ::spawn_blocking (
move | | -> Result < Vec < u8 > , ring ::error ::Unspecified > {
let pkcs8 = EcdsaKeyPair ::generate_pkcs8 ( curve , & rng ) ? ;
Ok ( pkcs8 . as_ref ( ) . to_vec ( ) )
} ,
)
. await
. unwrap ( )
. map_err ( | _ | {
custom_error ( " DOMExceptionOperationError " , " Key generation failed " )
} ) ? ;
private_key
}
2021-08-31 05:25:44 -04:00
Algorithm ::AesCtr
| Algorithm ::AesCbc
| Algorithm ::AesGcm
| Algorithm ::AesKw = > {
let length = args . length . ok_or_else ( not_supported ) ? ;
2021-10-06 05:24:41 -04:00
// Caller must guarantee divisibility by 8
let mut key_data = vec! [ 0 u8 ; length / 8 ] ;
2021-08-31 05:25:44 -04:00
let rng = RingRand ::SystemRandom ::new ( ) ;
rng . fill ( & mut key_data ) . map_err ( | _ | {
custom_error ( " DOMExceptionOperationError " , " Key generation failed " )
} ) ? ;
key_data
}
2021-07-06 08:16:04 -04:00
Algorithm ::Hmac = > {
let hash : HmacAlgorithm = args . hash . ok_or_else ( not_supported ) ? . into ( ) ;
let length = if let Some ( length ) = args . length {
if ( length % 8 ) ! = 0 {
return Err ( custom_error (
" DOMExceptionOperationError " ,
" hmac block length must be byte aligned " ,
) ) ;
}
let length = length / 8 ;
if length > ring ::digest ::MAX_BLOCK_LEN {
return Err ( custom_error (
" DOMExceptionOperationError " ,
" hmac block length is too large " ,
) ) ;
}
length
} else {
hash . digest_algorithm ( ) . block_len
} ;
let rng = RingRand ::SystemRandom ::new ( ) ;
let mut key_bytes = [ 0 ; ring ::digest ::MAX_BLOCK_LEN ] ;
let key_bytes = & mut key_bytes [ .. length ] ;
rng . fill ( key_bytes ) . map_err ( | _ | {
custom_error ( " DOMExceptionOperationError " , " Key generation failed " )
} ) ? ;
key_bytes . to_vec ( )
}
_ = > return Err ( not_supported ( ) ) ,
} ;
Ok ( key . into ( ) )
}
#[ 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
}
#[ derive(Deserialize) ]
#[ serde(rename_all = " lowercase " ) ]
pub struct KeyData {
// TODO(littledivy): Kept here to be used to importKey() in future.
#[ allow(dead_code) ]
r#type : KeyFormat ,
data : ZeroCopyBuf ,
}
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct SignArg {
key : KeyData ,
algorithm : Algorithm ,
salt_length : Option < u32 > ,
hash : Option < CryptoHash > ,
named_curve : Option < CryptoNamedCurve > ,
}
pub async fn op_crypto_sign_key (
_state : Rc < RefCell < OpState > > ,
args : SignArg ,
2021-10-05 16:38:27 -04:00
zero_copy : ZeroCopyBuf ,
2021-07-06 08:16:04 -04:00
) -> Result < ZeroCopyBuf , AnyError > {
let data = & * zero_copy ;
let algorithm = args . algorithm ;
let signature = match algorithm {
Algorithm ::RsassaPkcs1v15 = > {
2021-09-13 05:33:28 -04:00
let private_key = RsaPrivateKey ::from_pkcs1_der ( & * args . key . data ) ? ;
2021-07-07 10:33:58 -04:00
let ( padding , hashed ) = match args
2021-07-06 08:16:04 -04:00
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ?
{
2021-07-07 10:33:58 -04:00
CryptoHash ::Sha1 = > {
let mut hasher = Sha1 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::PKCS1v15Sign {
hash : Some ( rsa ::hash ::Hash ::SHA1 ) ,
} ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha256 = > {
let mut hasher = Sha256 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::PKCS1v15Sign {
hash : Some ( rsa ::hash ::Hash ::SHA2_256 ) ,
} ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha384 = > {
let mut hasher = Sha384 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::PKCS1v15Sign {
hash : Some ( rsa ::hash ::Hash ::SHA2_384 ) ,
} ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha512 = > {
let mut hasher = Sha512 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::PKCS1v15Sign {
hash : Some ( rsa ::hash ::Hash ::SHA2_512 ) ,
} ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
2021-07-06 08:16:04 -04:00
} ;
2021-07-07 10:33:58 -04:00
private_key . sign ( padding , & hashed ) ?
2021-07-06 08:16:04 -04:00
}
Algorithm ::RsaPss = > {
2021-09-13 05:33:28 -04:00
let private_key = RsaPrivateKey ::from_pkcs1_der ( & * args . key . data ) ? ;
2021-07-06 08:16:04 -04:00
let salt_len = args
. salt_length
. ok_or_else ( | | type_error ( " Missing argument saltLength " . to_string ( ) ) ) ?
as usize ;
let rng = OsRng ;
let ( padding , digest_in ) = match args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ?
{
CryptoHash ::Sha1 = > {
let mut hasher = Sha1 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::new_pss_with_salt ::< Sha1 , _ > ( rng , salt_len ) ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha256 = > {
let mut hasher = Sha256 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::new_pss_with_salt ::< Sha256 , _ > ( rng , salt_len ) ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha384 = > {
let mut hasher = Sha384 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::new_pss_with_salt ::< Sha384 , _ > ( rng , salt_len ) ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha512 = > {
let mut hasher = Sha512 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::new_pss_with_salt ::< Sha512 , _ > ( rng , salt_len ) ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
} ;
// Sign data based on computed padding and return buffer
private_key . sign ( padding , & digest_in ) ?
}
Algorithm ::Ecdsa = > {
let curve : & EcdsaSigningAlgorithm =
args . named_curve . ok_or_else ( not_supported ) ? . try_into ( ) ? ;
let key_pair = EcdsaKeyPair ::from_pkcs8 ( curve , & * args . key . data ) ? ;
// 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 rng = RingRand ::SystemRandom ::new ( ) ;
2021-07-30 09:03:41 -04:00
let signature = key_pair . sign ( & rng , data ) ? ;
2021-07-06 08:16:04 -04:00
// Signature data as buffer.
signature . as_ref ( ) . to_vec ( )
}
Algorithm ::Hmac = > {
let hash : HmacAlgorithm = args . hash . ok_or_else ( not_supported ) ? . into ( ) ;
let key = HmacKey ::new ( hash , & * args . key . data ) ;
2021-07-30 09:03:41 -04:00
let signature = ring ::hmac ::sign ( & key , data ) ;
2021-07-06 08:16:04 -04:00
signature . as_ref ( ) . to_vec ( )
}
_ = > return Err ( type_error ( " Unsupported algorithm " . to_string ( ) ) ) ,
} ;
Ok ( signature . into ( ) )
}
2021-07-12 08:45:36 -04:00
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct VerifyArg {
key : KeyData ,
algorithm : Algorithm ,
salt_length : Option < u32 > ,
hash : Option < CryptoHash > ,
signature : ZeroCopyBuf ,
2021-09-11 16:49:53 -04:00
named_curve : Option < CryptoNamedCurve > ,
2021-07-12 08:45:36 -04:00
}
pub async fn op_crypto_verify_key (
_state : Rc < RefCell < OpState > > ,
args : VerifyArg ,
2021-10-05 16:38:27 -04:00
zero_copy : ZeroCopyBuf ,
2021-07-12 08:45:36 -04:00
) -> Result < bool , AnyError > {
let data = & * zero_copy ;
let algorithm = args . algorithm ;
let verification = match algorithm {
Algorithm ::RsassaPkcs1v15 = > {
2021-08-06 04:10:50 -04:00
let public_key : RsaPublicKey =
2021-09-13 05:33:28 -04:00
RsaPrivateKey ::from_pkcs1_der ( & * args . key . data ) ? . to_public_key ( ) ;
2021-07-12 08:45:36 -04:00
let ( padding , hashed ) = match args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ?
{
CryptoHash ::Sha1 = > {
let mut hasher = Sha1 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::PKCS1v15Sign {
hash : Some ( rsa ::hash ::Hash ::SHA1 ) ,
} ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha256 = > {
let mut hasher = Sha256 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::PKCS1v15Sign {
hash : Some ( rsa ::hash ::Hash ::SHA2_256 ) ,
} ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha384 = > {
let mut hasher = Sha384 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::PKCS1v15Sign {
hash : Some ( rsa ::hash ::Hash ::SHA2_384 ) ,
} ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha512 = > {
let mut hasher = Sha512 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::PKCS1v15Sign {
hash : Some ( rsa ::hash ::Hash ::SHA2_512 ) ,
} ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
} ;
public_key
. verify ( padding , & hashed , & * args . signature )
. is_ok ( )
}
Algorithm ::RsaPss = > {
let salt_len = args
. salt_length
. ok_or_else ( | | type_error ( " Missing argument saltLength " . to_string ( ) ) ) ?
as usize ;
2021-08-06 04:10:50 -04:00
let public_key : RsaPublicKey =
2021-09-13 05:33:28 -04:00
RsaPrivateKey ::from_pkcs1_der ( & * args . key . data ) ? . to_public_key ( ) ;
2021-07-12 08:45:36 -04:00
let rng = OsRng ;
let ( padding , hashed ) = match args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ?
{
CryptoHash ::Sha1 = > {
let mut hasher = Sha1 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::new_pss_with_salt ::< Sha1 , _ > ( rng , salt_len ) ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha256 = > {
let mut hasher = Sha256 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::new_pss_with_salt ::< Sha256 , _ > ( rng , salt_len ) ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha384 = > {
let mut hasher = Sha384 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::new_pss_with_salt ::< Sha384 , _ > ( rng , salt_len ) ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
CryptoHash ::Sha512 = > {
let mut hasher = Sha512 ::new ( ) ;
hasher . update ( & data ) ;
(
PaddingScheme ::new_pss_with_salt ::< Sha512 , _ > ( rng , salt_len ) ,
hasher . finalize ( ) [ .. ] . to_vec ( ) ,
)
}
} ;
public_key
. verify ( padding , & hashed , & * args . signature )
. is_ok ( )
}
2021-08-04 15:49:27 -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 ( )
}
2021-09-11 16:49:53 -04:00
Algorithm ::Ecdsa = > {
let signing_alg : & EcdsaSigningAlgorithm =
args . named_curve . ok_or_else ( not_supported ) ? . try_into ( ) ? ;
let verify_alg : & EcdsaVerificationAlgorithm =
args . named_curve . ok_or_else ( not_supported ) ? . try_into ( ) ? ;
let private_key = EcdsaKeyPair ::from_pkcs8 ( signing_alg , & * args . key . data ) ? ;
let public_key_bytes = private_key . public_key ( ) . as_ref ( ) ;
let public_key =
ring ::signature ::UnparsedPublicKey ::new ( verify_alg , public_key_bytes ) ;
public_key . verify ( data , & * args . signature ) . is_ok ( )
}
2021-07-12 08:45:36 -04:00
_ = > return Err ( type_error ( " Unsupported algorithm " . to_string ( ) ) ) ,
} ;
Ok ( verification )
}
2021-09-13 05:33:28 -04:00
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct ExportKeyArg {
key : KeyData ,
algorithm : Algorithm ,
format : KeyFormat ,
// RSA-PSS
hash : Option < CryptoHash > ,
}
pub async fn op_crypto_export_key (
_state : Rc < RefCell < OpState > > ,
args : ExportKeyArg ,
2021-10-05 16:38:27 -04:00
_ : ( ) ,
2021-09-13 05:33:28 -04:00
) -> Result < ZeroCopyBuf , AnyError > {
let algorithm = args . algorithm ;
match algorithm {
Algorithm ::RsassaPkcs1v15 = > {
match args . format {
KeyFormat ::Pkcs8 = > {
// private_key is a PKCS#1 DER-encoded private key
let private_key = & args . key . data ;
// the PKCS#8 v1 structure
// PrivateKeyInfo ::= SEQUENCE {
// version Version,
// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
// privateKey PrivateKey,
// attributes [0] IMPLICIT Attributes OPTIONAL }
// version is 0 when publickey is None
let pk_info = rsa ::pkcs8 ::PrivateKeyInfo {
attributes : None ,
public_key : None ,
algorithm : rsa ::pkcs8 ::AlgorithmIdentifier {
// rsaEncryption(1)
oid : rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.1 " ) ,
// parameters field should not be ommited (None).
// It MUST have ASN.1 type NULL as per defined in RFC 3279 Section 2.3.1
parameters : Some ( asn1 ::Any ::from ( asn1 ::Null ) ) ,
} ,
private_key ,
} ;
Ok ( pk_info . to_der ( ) . as_ref ( ) . to_vec ( ) . into ( ) )
}
2021-10-06 05:18:12 -04:00
KeyFormat ::Spki = > {
// public_key is a PKCS#1 DER-encoded public key
let subject_public_key = & args . key . data ;
// the SPKI structure
let key_info = spki ::SubjectPublicKeyInfo {
algorithm : spki ::AlgorithmIdentifier {
// rsaEncryption(1)
oid : spki ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.1 " ) ,
// parameters field should not be ommited (None).
// It MUST have ASN.1 type NULL.
parameters : Some ( asn1 ::Any ::from ( asn1 ::Null ) ) ,
} ,
subject_public_key ,
} ;
// Infallible based on spec because of the way we import and generate keys.
let spki_der = key_info . to_vec ( ) . unwrap ( ) ;
Ok ( spki_der . into ( ) )
}
2021-09-13 05:33:28 -04:00
// TODO(@littledivy): jwk
_ = > unreachable! ( ) ,
}
}
Algorithm ::RsaPss = > {
match args . format {
KeyFormat ::Pkcs8 = > {
// Intentionally unused but required. Not encoded into PKCS#8 (see below).
let _hash = args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ? ;
// private_key is a PKCS#1 DER-encoded private key
let private_key = & args . key . data ;
// version is 0 when publickey is None
let pk_info = rsa ::pkcs8 ::PrivateKeyInfo {
attributes : None ,
public_key : None ,
algorithm : rsa ::pkcs8 ::AlgorithmIdentifier {
// Spec wants the OID to be id-RSASSA-PSS (1.2.840.113549.1.1.10) but ring and RSA do not support it.
// Instead, we use rsaEncryption (1.2.840.113549.1.1.1) as specified in RFC 3447.
// Node, Chromium and Firefox also use rsaEncryption (1.2.840.113549.1.1.1) and do not support id-RSASSA-PSS.
// parameters are set to NULL opposed to what spec wants (see above)
oid : rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.1 " ) ,
// parameters field should not be ommited (None).
// It MUST have ASN.1 type NULL as per defined in RFC 3279 Section 2.3.1
parameters : Some ( asn1 ::Any ::from ( asn1 ::Null ) ) ,
} ,
private_key ,
} ;
Ok ( pk_info . to_der ( ) . as_ref ( ) . to_vec ( ) . into ( ) )
}
2021-10-06 05:18:12 -04:00
KeyFormat ::Spki = > {
// Intentionally unused but required. Not encoded into SPKI (see below).
let _hash = args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ? ;
// public_key is a PKCS#1 DER-encoded public key
let subject_public_key = & args . key . data ;
// the SPKI structure
let key_info = spki ::SubjectPublicKeyInfo {
algorithm : spki ::AlgorithmIdentifier {
// rsaEncryption(1)
oid : spki ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.1 " ) ,
// parameters field should not be ommited (None).
// It MUST have ASN.1 type NULL.
parameters : Some ( asn1 ::Any ::from ( asn1 ::Null ) ) ,
} ,
subject_public_key ,
} ;
// Infallible based on spec because of the way we import and generate keys.
let spki_der = key_info . to_vec ( ) . unwrap ( ) ;
Ok ( spki_der . into ( ) )
}
2021-09-13 05:33:28 -04:00
// TODO(@littledivy): jwk
_ = > unreachable! ( ) ,
}
}
Algorithm ::RsaOaep = > {
match args . format {
KeyFormat ::Pkcs8 = > {
// Intentionally unused but required. Not encoded into PKCS#8 (see below).
let _hash = args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ? ;
// private_key is a PKCS#1 DER-encoded private key
let private_key = & args . key . data ;
// version is 0 when publickey is None
let pk_info = rsa ::pkcs8 ::PrivateKeyInfo {
attributes : None ,
public_key : None ,
algorithm : rsa ::pkcs8 ::AlgorithmIdentifier {
// Spec wants the OID to be id-RSAES-OAEP (1.2.840.113549.1.1.10) but ring and RSA crate do not support it.
// Instead, we use rsaEncryption (1.2.840.113549.1.1.1) as specified in RFC 3447.
// Chromium and Firefox also use rsaEncryption (1.2.840.113549.1.1.1) and do not support id-RSAES-OAEP.
// parameters are set to NULL opposed to what spec wants (see above)
oid : rsa ::pkcs8 ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.1 " ) ,
// parameters field should not be ommited (None).
// It MUST have ASN.1 type NULL as per defined in RFC 3279 Section 2.3.1
parameters : Some ( asn1 ::Any ::from ( asn1 ::Null ) ) ,
} ,
private_key ,
} ;
Ok ( pk_info . to_der ( ) . as_ref ( ) . to_vec ( ) . into ( ) )
}
2021-10-06 05:18:12 -04:00
KeyFormat ::Spki = > {
// Intentionally unused but required. Not encoded into SPKI (see below).
let _hash = args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ? ;
// public_key is a PKCS#1 DER-encoded public key
let subject_public_key = & args . key . data ;
// the SPKI structure
let key_info = spki ::SubjectPublicKeyInfo {
algorithm : spki ::AlgorithmIdentifier {
// rsaEncryption(1)
oid : spki ::ObjectIdentifier ::new ( " 1.2.840.113549.1.1.1 " ) ,
// parameters field should not be ommited (None).
// It MUST have ASN.1 type NULL.
parameters : Some ( asn1 ::Any ::from ( asn1 ::Null ) ) ,
} ,
subject_public_key ,
} ;
// Infallible based on spec because of the way we import and generate keys.
let spki_der = key_info . to_vec ( ) . unwrap ( ) ;
Ok ( spki_der . into ( ) )
}
2021-09-13 05:33:28 -04:00
// TODO(@littledivy): jwk
_ = > unreachable! ( ) ,
}
}
_ = > Err ( type_error ( " Unsupported algorithm " . to_string ( ) ) ) ,
}
}
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
2021-09-11 16:54:03 -04:00
info : Option < ZeroCopyBuf > ,
2021-08-26 06:48:07 -04:00
}
pub async fn op_crypto_derive_bits (
_state : Rc < RefCell < OpState > > ,
args : DeriveKeyArg ,
2021-10-08 11:29:36 -04:00
zero_copy : Option < ZeroCopyBuf > ,
2021-08-26 06:48:07 -04:00
) -> Result < ZeroCopyBuf , AnyError > {
let algorithm = args . algorithm ;
match algorithm {
Algorithm ::Pbkdf2 = > {
2021-10-08 11:29:36 -04:00
let zero_copy = zero_copy . ok_or_else ( not_supported ) ? ;
let salt = & * zero_copy ;
2021-08-26 06:48:07 -04:00
// 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 ( ) )
}
2021-10-08 11:29:36 -04:00
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 " . to_string ( ) ) ) ? ;
match named_curve {
CryptoNamedCurve ::P256 = > {
let secret_key = p256 ::SecretKey ::from_pkcs8_der ( & args . key . data ) ? ;
let public_key =
p256 ::SecretKey ::from_pkcs8_der ( & public_key . data ) ? . public_key ( ) ;
let shared_secret = p256 ::elliptic_curve ::ecdh ::diffie_hellman (
secret_key . to_secret_scalar ( ) ,
public_key . as_affine ( ) ,
) ;
Ok ( shared_secret . as_bytes ( ) . to_vec ( ) . into ( ) )
}
// TODO(@littledivy): support for P384
// https://github.com/RustCrypto/elliptic-curves/issues/240
_ = > Err ( type_error ( " Unsupported namedCurve " . to_string ( ) ) ) ,
}
}
2021-09-11 16:54:03 -04:00
Algorithm ::Hkdf = > {
2021-10-08 11:29:36 -04:00
let zero_copy = zero_copy . ok_or_else ( not_supported ) ? ;
let salt = & * zero_copy ;
2021-09-11 16:54:03 -04:00
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 ) ) ? ;
let mut r = vec! [ 0 u8 ; length ] ;
okm . fill ( & mut r ) ? ;
Ok ( r . into ( ) )
}
2021-08-26 06:48:07 -04:00
_ = > Err ( type_error ( " Unsupported algorithm " . to_string ( ) ) ) ,
}
}
2021-08-24 15:59:02 -04:00
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct EncryptArg {
key : KeyData ,
algorithm : Algorithm ,
2021-10-11 10:37:51 -04:00
// RSA-OAEP
2021-08-24 15:59:02 -04:00
hash : Option < CryptoHash > ,
label : Option < ZeroCopyBuf > ,
2021-10-11 10:37:51 -04:00
// AES-CBC
iv : Option < ZeroCopyBuf > ,
length : Option < usize > ,
2021-08-24 15:59:02 -04:00
}
pub async fn op_crypto_encrypt_key (
_state : Rc < RefCell < OpState > > ,
args : EncryptArg ,
2021-10-05 16:38:27 -04:00
zero_copy : ZeroCopyBuf ,
2021-08-24 15:59:02 -04:00
) -> Result < ZeroCopyBuf , AnyError > {
let data = & * zero_copy ;
let algorithm = args . algorithm ;
match algorithm {
Algorithm ::RsaOaep = > {
let public_key : RsaPublicKey =
2021-09-13 05:33:28 -04:00
RsaPrivateKey ::from_pkcs1_der ( & * args . key . data ) ? . to_public_key ( ) ;
2021-08-24 15:59:02 -04:00
let label = args . label . map ( | l | String ::from_utf8_lossy ( & * l ) . to_string ( ) ) ;
let mut rng = OsRng ;
let padding = match args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ?
{
CryptoHash ::Sha1 = > PaddingScheme ::OAEP {
digest : Box ::new ( Sha1 ::new ( ) ) ,
mgf_digest : Box ::new ( Sha1 ::new ( ) ) ,
label ,
} ,
CryptoHash ::Sha256 = > PaddingScheme ::OAEP {
digest : Box ::new ( Sha256 ::new ( ) ) ,
mgf_digest : Box ::new ( Sha256 ::new ( ) ) ,
label ,
} ,
CryptoHash ::Sha384 = > PaddingScheme ::OAEP {
digest : Box ::new ( Sha384 ::new ( ) ) ,
mgf_digest : Box ::new ( Sha384 ::new ( ) ) ,
label ,
} ,
CryptoHash ::Sha512 = > PaddingScheme ::OAEP {
digest : Box ::new ( Sha512 ::new ( ) ) ,
mgf_digest : Box ::new ( Sha512 ::new ( ) ) ,
label ,
} ,
} ;
Ok (
public_key
. encrypt ( & mut rng , padding , data )
. map_err ( | e | {
custom_error ( " DOMExceptionOperationError " , e . to_string ( ) )
} ) ?
. into ( ) ,
)
}
2021-10-11 10:37:51 -04:00
Algorithm ::AesCbc = > {
let key = & * args . key . data ;
let length = args
. length
. ok_or_else ( | | type_error ( " Missing argument length " . to_string ( ) ) ) ? ;
let iv = args
. iv
. ok_or_else ( | | type_error ( " Missing argument iv " . to_string ( ) ) ) ? ;
// 2-3.
let ciphertext = match length {
128 = > {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes128Cbc =
block_modes ::Cbc < aes ::Aes128 , block_modes ::block_padding ::Pkcs7 > ;
let cipher = Aes128Cbc ::new_from_slices ( key , & iv ) ? ;
cipher . encrypt_vec ( data )
}
192 = > {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes192Cbc =
block_modes ::Cbc < aes ::Aes192 , block_modes ::block_padding ::Pkcs7 > ;
let cipher = Aes192Cbc ::new_from_slices ( key , & iv ) ? ;
cipher . encrypt_vec ( data )
}
256 = > {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes256Cbc =
block_modes ::Cbc < aes ::Aes256 , block_modes ::block_padding ::Pkcs7 > ;
let cipher = Aes256Cbc ::new_from_slices ( key , & iv ) ? ;
cipher . encrypt_vec ( data )
}
_ = > unreachable! ( ) ,
} ;
Ok ( ciphertext . into ( ) )
}
2021-08-24 15:59:02 -04:00
_ = > Err ( type_error ( " Unsupported algorithm " . to_string ( ) ) ) ,
}
}
2021-09-14 09:21:20 -04:00
// The parameters field associated with OID id-RSASSA-PSS
// Defined in RFC 3447, section A.2.3
//
// RSASSA-PSS-params ::= SEQUENCE {
// hashAlgorithm [0] HashAlgorithm DEFAULT sha1,
// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
// saltLength [2] INTEGER DEFAULT 20,
// trailerField [3] TrailerField DEFAULT trailerFieldBC
// }
pub struct PssPrivateKeyParameters < ' a > {
pub hash_algorithm : rsa ::pkcs8 ::AlgorithmIdentifier < ' a > ,
pub mask_gen_algorithm : rsa ::pkcs8 ::AlgorithmIdentifier < ' a > ,
pub salt_length : u32 ,
}
// Context-specific tag number for hashAlgorithm.
const HASH_ALGORITHM_TAG : rsa ::pkcs8 ::der ::TagNumber =
rsa ::pkcs8 ::der ::TagNumber ::new ( 0 ) ;
// Context-specific tag number for maskGenAlgorithm.
const MASK_GEN_ALGORITHM_TAG : rsa ::pkcs8 ::der ::TagNumber =
rsa ::pkcs8 ::der ::TagNumber ::new ( 1 ) ;
// Context-specific tag number for saltLength.
const SALT_LENGTH_TAG : rsa ::pkcs8 ::der ::TagNumber =
rsa ::pkcs8 ::der ::TagNumber ::new ( 2 ) ;
2021-10-02 09:20:53 -04:00
// Context-specific tag number for pSourceAlgorithm
const P_SOURCE_ALGORITHM_TAG : rsa ::pkcs8 ::der ::TagNumber =
rsa ::pkcs8 ::der ::TagNumber ::new ( 2 ) ;
2021-10-01 05:14:16 -04:00
lazy_static! {
// Default HashAlgorithm for RSASSA-PSS-params (sha1)
//
// sha1 HashAlgorithm ::= {
// algorithm id-sha1,
// parameters SHA1Parameters : NULL
// }
//
// SHA1Parameters ::= NULL
static ref SHA1_HASH_ALGORITHM : rsa ::pkcs8 ::AlgorithmIdentifier < 'static > = rsa ::pkcs8 ::AlgorithmIdentifier {
// id-sha1
oid : ID_SHA1_OID ,
// NULL
parameters : Some ( asn1 ::Any ::from ( asn1 ::Null ) ) ,
} ;
// TODO(@littledivy): `pkcs8` should provide AlgorithmIdentifier to Any conversion.
static ref ENCODED_SHA1_HASH_ALGORITHM : Vec < u8 > = SHA1_HASH_ALGORITHM . to_vec ( ) . unwrap ( ) ;
// Default MaskGenAlgrithm for RSASSA-PSS-params (mgf1SHA1)
//
// mgf1SHA1 MaskGenAlgorithm ::= {
// algorithm id-mgf1,
// parameters HashAlgorithm : sha1
// }
static ref MGF1_SHA1_MASK_ALGORITHM : rsa ::pkcs8 ::AlgorithmIdentifier < 'static > = rsa ::pkcs8 ::AlgorithmIdentifier {
// id-mgf1
oid : ID_MFG1 ,
// sha1
parameters : Some ( asn1 ::Any ::from_der ( & ENCODED_SHA1_HASH_ALGORITHM ) . unwrap ( ) ) ,
} ;
2021-10-02 09:20:53 -04:00
// Default PSourceAlgorithm for RSAES-OAEP-params
// The default label is an empty string.
//
// pSpecifiedEmpty PSourceAlgorithm ::= {
// algorithm id-pSpecified,
// parameters EncodingParameters : emptyString
// }
//
// emptyString EncodingParameters ::= ''H
static ref P_SPECIFIED_EMPTY : rsa ::pkcs8 ::AlgorithmIdentifier < 'static > = rsa ::pkcs8 ::AlgorithmIdentifier {
// id-pSpecified
oid : ID_P_SPECIFIED ,
// EncodingParameters
parameters : Some ( asn1 ::Any ::from ( asn1 ::OctetString ::new ( b " " ) . unwrap ( ) ) ) ,
} ;
2021-10-01 05:14:16 -04:00
}
2021-09-14 09:21:20 -04:00
impl < ' a > TryFrom < rsa ::pkcs8 ::der ::asn1 ::Any < ' a > >
for PssPrivateKeyParameters < ' a >
{
type Error = rsa ::pkcs8 ::der ::Error ;
fn try_from (
any : rsa ::pkcs8 ::der ::asn1 ::Any < ' a > ,
) -> rsa ::pkcs8 ::der ::Result < PssPrivateKeyParameters > {
any . sequence ( | decoder | {
let hash_algorithm = decoder
. context_specific ( HASH_ALGORITHM_TAG ) ?
. map ( TryInto ::try_into )
. transpose ( ) ?
2021-10-01 05:14:16 -04:00
. unwrap_or ( * SHA1_HASH_ALGORITHM ) ;
2021-09-14 09:21:20 -04:00
let mask_gen_algorithm = decoder
. context_specific ( MASK_GEN_ALGORITHM_TAG ) ?
. map ( TryInto ::try_into )
. transpose ( ) ?
2021-10-01 05:14:16 -04:00
. unwrap_or ( * MGF1_SHA1_MASK_ALGORITHM ) ;
2021-09-14 09:21:20 -04:00
let salt_length = decoder
. context_specific ( SALT_LENGTH_TAG ) ?
. map ( TryInto ::try_into )
. transpose ( ) ?
. unwrap_or ( 20 ) ;
Ok ( Self {
hash_algorithm ,
mask_gen_algorithm ,
salt_length ,
} )
} )
}
}
// The parameters field associated with OID id-RSAES-OAEP
// Defined in RFC 3447, section A.2.1
//
// RSAES-OAEP-params ::= SEQUENCE {
// hashAlgorithm [0] HashAlgorithm DEFAULT sha1,
// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
// pSourceAlgorithm [2] PSourceAlgorithm DEFAULT pSpecifiedEmpty
// }
pub struct OaepPrivateKeyParameters < ' a > {
pub hash_algorithm : rsa ::pkcs8 ::AlgorithmIdentifier < ' a > ,
pub mask_gen_algorithm : rsa ::pkcs8 ::AlgorithmIdentifier < ' a > ,
pub p_source_algorithm : rsa ::pkcs8 ::AlgorithmIdentifier < ' a > ,
}
impl < ' a > TryFrom < rsa ::pkcs8 ::der ::asn1 ::Any < ' a > >
for OaepPrivateKeyParameters < ' a >
{
type Error = rsa ::pkcs8 ::der ::Error ;
fn try_from (
any : rsa ::pkcs8 ::der ::asn1 ::Any < ' a > ,
) -> rsa ::pkcs8 ::der ::Result < OaepPrivateKeyParameters > {
any . sequence ( | decoder | {
2021-10-02 09:20:53 -04:00
let hash_algorithm = decoder
. context_specific ( HASH_ALGORITHM_TAG ) ?
. map ( TryInto ::try_into )
. transpose ( ) ?
. unwrap_or ( * SHA1_HASH_ALGORITHM ) ;
let mask_gen_algorithm = decoder
. context_specific ( MASK_GEN_ALGORITHM_TAG ) ?
. map ( TryInto ::try_into )
. transpose ( ) ?
. unwrap_or ( * MGF1_SHA1_MASK_ALGORITHM ) ;
let p_source_algorithm = decoder
. context_specific ( P_SOURCE_ALGORITHM_TAG ) ?
. map ( TryInto ::try_into )
. transpose ( ) ?
. unwrap_or ( * P_SPECIFIED_EMPTY ) ;
2021-09-14 09:21:20 -04:00
Ok ( Self {
hash_algorithm ,
mask_gen_algorithm ,
p_source_algorithm ,
} )
} )
}
}
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct ImportKeyArg {
algorithm : Algorithm ,
format : KeyFormat ,
// RSASSA-PKCS1-v1_5
hash : Option < CryptoHash > ,
2021-10-11 11:00:48 -04:00
// ECDSA
named_curve : Option < CryptoNamedCurve > ,
2021-09-14 09:21:20 -04:00
}
#[ derive(Serialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct ImportKeyResult {
data : ZeroCopyBuf ,
// RSASSA-PKCS1-v1_5
public_exponent : Option < ZeroCopyBuf > ,
modulus_length : Option < usize > ,
}
pub async fn op_crypto_import_key (
_state : Rc < RefCell < OpState > > ,
args : ImportKeyArg ,
2021-10-05 16:38:27 -04:00
zero_copy : ZeroCopyBuf ,
2021-09-14 09:21:20 -04:00
) -> Result < ImportKeyResult , AnyError > {
let data = & * zero_copy ;
let algorithm = args . algorithm ;
match algorithm {
2021-10-11 11:00:48 -04:00
Algorithm ::Ecdsa = > {
let curve = args . named_curve . ok_or_else ( | | {
type_error ( " Missing argument named_curve " . to_string ( ) )
} ) ? ;
match curve {
CryptoNamedCurve ::P256 = > {
// 1-2.
let point = p256 ::EncodedPoint ::from_bytes ( data ) ? ;
// 3.
if point . is_identity ( ) {
return Err ( type_error ( " Invalid key data " . to_string ( ) ) ) ;
}
}
CryptoNamedCurve ::P384 = > {
// 1-2.
let point = p384 ::EncodedPoint ::from_bytes ( data ) ? ;
// 3.
if point . is_identity ( ) {
return Err ( type_error ( " Invalid key data " . to_string ( ) ) ) ;
}
}
} ;
Ok ( ImportKeyResult {
data : zero_copy ,
modulus_length : None ,
public_exponent : None ,
} )
}
2021-09-14 09:21:20 -04:00
Algorithm ::RsassaPkcs1v15 = > {
match args . format {
KeyFormat ::Pkcs8 = > {
let hash = args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ? ;
// 2-3.
let pk_info =
rsa ::pkcs8 ::PrivateKeyInfo ::from_der ( data ) . map_err ( | e | {
custom_error ( " DOMExceptionOperationError " , e . to_string ( ) )
} ) ? ;
// 4-5.
let alg = pk_info . algorithm . oid ;
// 6.
let pk_hash = match alg {
// rsaEncryption
RSA_ENCRYPTION_OID = > None ,
// sha1WithRSAEncryption
SHA1_RSA_ENCRYPTION_OID = > Some ( CryptoHash ::Sha1 ) ,
// sha256WithRSAEncryption
SHA256_RSA_ENCRYPTION_OID = > Some ( CryptoHash ::Sha256 ) ,
// sha384WithRSAEncryption
SHA384_RSA_ENCRYPTION_OID = > Some ( CryptoHash ::Sha384 ) ,
// sha512WithRSAEncryption
SHA512_RSA_ENCRYPTION_OID = > Some ( CryptoHash ::Sha512 ) ,
_ = > return Err ( type_error ( " Unsupported algorithm " . to_string ( ) ) ) ,
} ;
// 7.
if let Some ( pk_hash ) = pk_hash {
if pk_hash ! = hash {
2021-09-16 03:58:29 -04:00
return Err ( custom_error (
" DOMExceptionDataError " ,
" Hash mismatch " . to_string ( ) ,
) ) ;
2021-09-14 09:21:20 -04:00
}
}
// 8-9.
let private_key =
rsa ::pkcs1 ::RsaPrivateKey ::from_der ( pk_info . private_key ) . map_err (
| e | custom_error ( " DOMExceptionOperationError " , e . to_string ( ) ) ,
) ? ;
let bytes_consumed = private_key . encoded_len ( ) . map_err ( | e | {
2021-09-16 03:58:29 -04:00
custom_error ( " DOMExceptionDataError " , e . to_string ( ) )
2021-09-14 09:21:20 -04:00
} ) ? ;
if bytes_consumed
! = rsa ::pkcs1 ::der ::Length ::new ( pk_info . private_key . len ( ) as u16 )
{
2021-09-16 03:58:29 -04:00
return Err ( custom_error (
" DOMExceptionDataError " ,
" Some bytes were not consumed " . to_string ( ) ,
) ) ;
2021-09-14 09:21:20 -04:00
}
Ok ( ImportKeyResult {
data : pk_info . private_key . to_vec ( ) . into ( ) ,
public_exponent : Some (
private_key . public_exponent . as_bytes ( ) . to_vec ( ) . into ( ) ,
) ,
modulus_length : Some ( private_key . modulus . as_bytes ( ) . len ( ) * 8 ) ,
} )
}
// TODO(@littledivy): spki
// TODO(@littledivy): jwk
_ = > Err ( type_error ( " Unsupported format " . to_string ( ) ) ) ,
}
}
Algorithm ::RsaPss = > {
match args . format {
KeyFormat ::Pkcs8 = > {
let hash = args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ? ;
// 2-3.
let pk_info =
rsa ::pkcs8 ::PrivateKeyInfo ::from_der ( data ) . map_err ( | e | {
custom_error ( " DOMExceptionOperationError " , e . to_string ( ) )
} ) ? ;
// 4-5.
let alg = pk_info . algorithm . oid ;
// 6.
let pk_hash = match alg {
// rsaEncryption
RSA_ENCRYPTION_OID = > None ,
// id-RSASSA-PSS
RSASSA_PSS_OID = > {
let params = PssPrivateKeyParameters ::try_from (
pk_info . algorithm . parameters . ok_or_else ( | | {
2021-10-01 07:16:11 -04:00
custom_error (
" DOMExceptionNotSupportedError " ,
" Malformed parameters " . to_string ( ) ,
)
2021-09-14 09:21:20 -04:00
} ) ? ,
)
2021-10-01 07:16:11 -04:00
. map_err ( | _ | {
custom_error (
" DOMExceptionNotSupportedError " ,
" Malformed parameters " . to_string ( ) ,
)
} ) ? ;
2021-09-14 09:21:20 -04:00
let hash_alg = params . hash_algorithm ;
let hash = match hash_alg . oid {
// id-sha1
ID_SHA1_OID = > Some ( CryptoHash ::Sha1 ) ,
// id-sha256
ID_SHA256_OID = > Some ( CryptoHash ::Sha256 ) ,
// id-sha384
ID_SHA384_OID = > Some ( CryptoHash ::Sha384 ) ,
// id-sha256
ID_SHA512_OID = > Some ( CryptoHash ::Sha512 ) ,
_ = > {
2021-09-16 03:58:29 -04:00
return Err ( custom_error (
" DOMExceptionDataError " ,
2021-09-14 09:21:20 -04:00
" Unsupported hash algorithm " . to_string ( ) ,
) )
}
} ;
if params . mask_gen_algorithm . oid ! = ID_MFG1 {
2021-10-01 07:16:11 -04:00
return Err ( custom_error (
" DOMExceptionNotSupportedError " ,
2021-09-14 09:21:20 -04:00
" Unsupported hash algorithm " . to_string ( ) ,
) ) ;
}
hash
}
2021-09-16 03:58:29 -04:00
_ = > {
return Err ( custom_error (
" DOMExceptionDataError " ,
" Unsupported algorithm " . to_string ( ) ,
) )
}
2021-09-14 09:21:20 -04:00
} ;
// 7.
if let Some ( pk_hash ) = pk_hash {
if pk_hash ! = hash {
2021-09-16 03:58:29 -04:00
return Err ( custom_error (
" DOMExceptionDataError " ,
" Hash mismatch " . to_string ( ) ,
) ) ;
2021-09-14 09:21:20 -04:00
}
}
// 8-9.
let private_key =
rsa ::pkcs1 ::RsaPrivateKey ::from_der ( pk_info . private_key ) . map_err (
| e | custom_error ( " DOMExceptionOperationError " , e . to_string ( ) ) ,
) ? ;
2021-09-16 03:58:29 -04:00
let bytes_consumed = private_key
. encoded_len ( )
. map_err ( | e | custom_error ( " DataError " , e . to_string ( ) ) ) ? ;
2021-09-14 09:21:20 -04:00
if bytes_consumed
! = rsa ::pkcs1 ::der ::Length ::new ( pk_info . private_key . len ( ) as u16 )
{
2021-09-16 03:58:29 -04:00
return Err ( custom_error (
" DOMExceptionDataError " ,
" Some bytes were not consumed " . to_string ( ) ,
) ) ;
2021-09-14 09:21:20 -04:00
}
Ok ( ImportKeyResult {
data : pk_info . private_key . to_vec ( ) . into ( ) ,
public_exponent : Some (
private_key . public_exponent . as_bytes ( ) . to_vec ( ) . into ( ) ,
) ,
modulus_length : Some ( private_key . modulus . as_bytes ( ) . len ( ) * 8 ) ,
} )
}
// TODO(@littledivy): spki
// TODO(@littledivy): jwk
_ = > Err ( type_error ( " Unsupported format " . to_string ( ) ) ) ,
}
}
Algorithm ::RsaOaep = > {
match args . format {
KeyFormat ::Pkcs8 = > {
let hash = args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ? ;
// 2-3.
let pk_info =
rsa ::pkcs8 ::PrivateKeyInfo ::from_der ( data ) . map_err ( | e | {
custom_error ( " DOMExceptionOperationError " , e . to_string ( ) )
} ) ? ;
// 4-5.
let alg = pk_info . algorithm . oid ;
// 6.
let pk_hash = match alg {
// rsaEncryption
RSA_ENCRYPTION_OID = > None ,
// id-RSAES-OAEP
RSAES_OAEP_OID = > {
let params = OaepPrivateKeyParameters ::try_from (
pk_info . algorithm . parameters . ok_or_else ( | | {
2021-10-01 07:16:11 -04:00
custom_error (
" DOMExceptionNotSupportedError " ,
" Malformed parameters " . to_string ( ) ,
)
2021-09-14 09:21:20 -04:00
} ) ? ,
)
2021-10-01 07:16:11 -04:00
. map_err ( | _ | {
custom_error (
" DOMExceptionNotSupportedError " ,
" Malformed parameters " . to_string ( ) ,
)
} ) ? ;
2021-09-14 09:21:20 -04:00
let hash_alg = params . hash_algorithm ;
let hash = match hash_alg . oid {
// id-sha1
ID_SHA1_OID = > Some ( CryptoHash ::Sha1 ) ,
// id-sha256
ID_SHA256_OID = > Some ( CryptoHash ::Sha256 ) ,
// id-sha384
ID_SHA384_OID = > Some ( CryptoHash ::Sha384 ) ,
// id-sha256
ID_SHA512_OID = > Some ( CryptoHash ::Sha512 ) ,
_ = > {
2021-09-16 03:58:29 -04:00
return Err ( custom_error (
" DOMExceptionDataError " ,
2021-09-14 09:21:20 -04:00
" Unsupported hash algorithm " . to_string ( ) ,
) )
}
} ;
if params . mask_gen_algorithm . oid ! = ID_MFG1 {
2021-10-01 07:16:11 -04:00
return Err ( custom_error (
" DOMExceptionNotSupportedError " ,
2021-09-14 09:21:20 -04:00
" Unsupported hash algorithm " . to_string ( ) ,
) ) ;
}
hash
}
2021-09-16 03:58:29 -04:00
_ = > {
return Err ( custom_error (
" DOMExceptionDataError " ,
" Unsupported algorithm " . to_string ( ) ,
) )
}
2021-09-14 09:21:20 -04:00
} ;
// 7.
if let Some ( pk_hash ) = pk_hash {
if pk_hash ! = hash {
2021-09-16 03:58:29 -04:00
return Err ( custom_error (
" DOMExceptionDataError " ,
" Hash mismatch " . to_string ( ) ,
) ) ;
2021-09-14 09:21:20 -04:00
}
}
// 8-9.
let private_key =
rsa ::pkcs1 ::RsaPrivateKey ::from_der ( pk_info . private_key ) . map_err (
| e | custom_error ( " DOMExceptionOperationError " , e . to_string ( ) ) ,
) ? ;
let bytes_consumed = private_key . encoded_len ( ) . map_err ( | e | {
2021-09-16 03:58:29 -04:00
custom_error ( " DOMExceptionDataError " , e . to_string ( ) )
2021-09-14 09:21:20 -04:00
} ) ? ;
if bytes_consumed
! = rsa ::pkcs1 ::der ::Length ::new ( pk_info . private_key . len ( ) as u16 )
{
2021-09-16 03:58:29 -04:00
return Err ( custom_error (
" DOMExceptionDataError " ,
" Some bytes were not consumed " . to_string ( ) ,
) ) ;
2021-09-14 09:21:20 -04:00
}
Ok ( ImportKeyResult {
data : pk_info . private_key . to_vec ( ) . into ( ) ,
public_exponent : Some (
private_key . public_exponent . as_bytes ( ) . to_vec ( ) . into ( ) ,
) ,
modulus_length : Some ( private_key . modulus . as_bytes ( ) . len ( ) * 8 ) ,
} )
}
// TODO(@littledivy): spki
// TODO(@littledivy): jwk
_ = > Err ( type_error ( " Unsupported format " . to_string ( ) ) ) ,
}
}
_ = > Err ( type_error ( " Unsupported algorithm " . to_string ( ) ) ) ,
}
}
2021-08-24 15:59:02 -04:00
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct DecryptArg {
key : KeyData ,
algorithm : Algorithm ,
2021-10-11 10:37:51 -04:00
// RSA-OAEP
2021-08-24 15:59:02 -04:00
hash : Option < CryptoHash > ,
label : Option < ZeroCopyBuf > ,
2021-10-11 10:37:51 -04:00
// AES-CBC
iv : Option < ZeroCopyBuf > ,
length : Option < usize > ,
2021-08-24 15:59:02 -04:00
}
pub async fn op_crypto_decrypt_key (
_state : Rc < RefCell < OpState > > ,
args : DecryptArg ,
2021-10-05 16:38:27 -04:00
zero_copy : ZeroCopyBuf ,
2021-08-24 15:59:02 -04:00
) -> Result < ZeroCopyBuf , AnyError > {
let data = & * zero_copy ;
let algorithm = args . algorithm ;
match algorithm {
Algorithm ::RsaOaep = > {
let private_key : RsaPrivateKey =
2021-09-13 05:33:28 -04:00
RsaPrivateKey ::from_pkcs1_der ( & * args . key . data ) ? ;
2021-08-24 15:59:02 -04:00
let label = args . label . map ( | l | String ::from_utf8_lossy ( & * l ) . to_string ( ) ) ;
let padding = match args
. hash
. ok_or_else ( | | type_error ( " Missing argument hash " . to_string ( ) ) ) ?
{
CryptoHash ::Sha1 = > PaddingScheme ::OAEP {
digest : Box ::new ( Sha1 ::new ( ) ) ,
mgf_digest : Box ::new ( Sha1 ::new ( ) ) ,
label ,
} ,
CryptoHash ::Sha256 = > PaddingScheme ::OAEP {
digest : Box ::new ( Sha256 ::new ( ) ) ,
mgf_digest : Box ::new ( Sha256 ::new ( ) ) ,
label ,
} ,
CryptoHash ::Sha384 = > PaddingScheme ::OAEP {
digest : Box ::new ( Sha384 ::new ( ) ) ,
mgf_digest : Box ::new ( Sha384 ::new ( ) ) ,
label ,
} ,
CryptoHash ::Sha512 = > PaddingScheme ::OAEP {
digest : Box ::new ( Sha512 ::new ( ) ) ,
mgf_digest : Box ::new ( Sha512 ::new ( ) ) ,
label ,
} ,
} ;
Ok (
private_key
. decrypt ( padding , data )
. map_err ( | e | {
custom_error ( " DOMExceptionOperationError " , e . to_string ( ) )
} ) ?
. into ( ) ,
)
}
2021-10-11 10:37:51 -04:00
Algorithm ::AesCbc = > {
let key = & * args . key . data ;
let length = args
. length
. ok_or_else ( | | type_error ( " Missing argument length " . to_string ( ) ) ) ? ;
let iv = args
. iv
. ok_or_else ( | | type_error ( " Missing argument iv " . to_string ( ) ) ) ? ;
// 2.
let plaintext = match length {
128 = > {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes128Cbc =
block_modes ::Cbc < aes ::Aes128 , block_modes ::block_padding ::Pkcs7 > ;
let cipher = Aes128Cbc ::new_from_slices ( key , & iv ) ? ;
cipher . decrypt_vec ( data ) ?
}
192 = > {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes192Cbc =
block_modes ::Cbc < aes ::Aes192 , block_modes ::block_padding ::Pkcs7 > ;
let cipher = Aes192Cbc ::new_from_slices ( key , & iv ) ? ;
cipher . decrypt_vec ( data ) ?
}
256 = > {
// Section 10.3 Step 2 of RFC 2315 https://www.rfc-editor.org/rfc/rfc2315
type Aes256Cbc =
block_modes ::Cbc < aes ::Aes256 , block_modes ::block_padding ::Pkcs7 > ;
let cipher = Aes256Cbc ::new_from_slices ( key , & iv ) ? ;
cipher . decrypt_vec ( data ) ?
}
_ = > unreachable! ( ) ,
} ;
// 6.
Ok ( plaintext . into ( ) )
}
2021-08-24 15:59:02 -04:00
_ = > Err ( type_error ( " Unsupported algorithm " . to_string ( ) ) ) ,
}
}
2021-06-05 08:46:24 -04:00
pub fn op_crypto_random_uuid (
state : & mut OpState ,
2021-06-05 13:30:20 -04:00
_ : ( ) ,
_ : ( ) ,
2021-06-05 08:46:24 -04:00
) -> Result < String , AnyError > {
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 ) ;
uuid ::Builder ::from_bytes ( bytes )
. set_version ( uuid ::Version ::Random )
. build ( )
} else {
uuid ::Uuid ::new_v4 ( )
} ;
Ok ( uuid . to_string ( ) )
}
2021-06-06 06:57:10 -04:00
pub async fn op_crypto_subtle_digest (
_state : Rc < RefCell < OpState > > ,
2021-07-07 14:34:02 -04:00
algorithm : CryptoHash ,
2021-10-05 16:38:27 -04:00
data : ZeroCopyBuf ,
2021-06-06 06:57:10 -04:00
) -> Result < ZeroCopyBuf , AnyError > {
let output = tokio ::task ::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 )
}
2021-02-26 12:06:26 -05:00
pub fn get_declaration ( ) -> PathBuf {
PathBuf ::from ( env! ( " CARGO_MANIFEST_DIR " ) ) . join ( " lib.deno_crypto.d.ts " )
}