crypto: Begin SubtleCrypto implementation (#33628)

* Update IDLs and Bindings conf

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Add AES crate

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Implement DOM interfaces

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* IDL tidy

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Remove deriveKey from inRealms for now until implemented

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Fix CryptoKey rustdoc comments

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Move string constants to top of file

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Use properly rooted CryptoKey

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Code clarity

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Rework NormalizedAlgorithm to not hold a DOMString

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Add Rustdoc for CryptoKey interface

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Move ignore mallocsizeof to rand crate, remove from crypto

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Update cargo lock

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Fix key handling, implement exportKey with JWK TODO

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Add missing spec link

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Use create_buffer_source, remove aes dep from libservo

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Fix crash when running in worker

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Update expectations

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* fmt

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Move CryptoKey and SubtleCrypto behind pref for now

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Update expectations

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Readd timeout expectation

Signed-off-by: Daniel Adams <msub2official@gmail.com>

---------

Signed-off-by: Daniel Adams <msub2official@gmail.com>
This commit is contained in:
Daniel Adams 2024-10-08 03:51:08 +00:00 committed by GitHub
parent 66bc430b24
commit fc0d4d8157
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
82 changed files with 39536 additions and 557 deletions

View file

@ -249,6 +249,11 @@ mod gen {
#[serde(rename = "dom.compositionevent.enabled")]
enabled: bool,
},
crypto: {
subtle: {
enabled: bool,
}
},
custom_elements: {
#[serde(rename = "dom.customelements.enabled")]
enabled: bool,

View file

@ -13,6 +13,8 @@ path = "lib.rs"
[dependencies]
log = { workspace = true }
malloc_size_of = { workspace = true }
malloc_size_of_derive = { workspace = true }
rand = { workspace = true }
rand_core = { workspace = true }
rand_isaac = { workspace = true }

View file

@ -7,6 +7,7 @@ use std::rc::Rc;
use std::sync::Mutex;
use log::trace;
use malloc_size_of_derive::MallocSizeOf;
/// A random number generator which shares one instance of an `OsRng`.
///
/// A problem with `OsRng`, which is inherited by `StdRng` and so
@ -31,7 +32,9 @@ static OS_RNG: Mutex<OsRng> = Mutex::new(OsRng);
const RESEED_THRESHOLD: u64 = 32_768;
// An in-memory RNG that only uses the shared file descriptor for seeding and reseeding.
#[derive(MallocSizeOf)]
pub struct ServoRng {
#[ignore_malloc_size_of = "Defined in rand"]
rng: ReseedingRng<IsaacCore, ServoReseeder>,
}

View file

@ -26,6 +26,7 @@ phf_shared = "0.11"
serde_json = { workspace = true }
[dependencies]
aes = { workspace = true }
accountable-refcell = { workspace = true, optional = true }
app_units = { workspace = true }
arrayvec = { workspace = true }

View file

@ -218,4 +218,8 @@ DOMInterfaces = {
'inRealms': ['RequestSession', 'SupportsSessionMode'],
},
'SubtleCrypto': {
'inRealms': ['GenerateKey', 'ExportKey']
}
}

View file

@ -12,19 +12,20 @@ use uuid::Uuid;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::CryptoBinding::CryptoMethods;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::subtlecrypto::SubtleCrypto;
use crate::script_runtime::JSContext;
// https://developer.mozilla.org/en-US/docs/Web/API/Crypto
#[dom_struct]
pub struct Crypto {
reflector_: Reflector,
#[ignore_malloc_size_of = "Defined in rand"]
#[no_trace]
rng: DomRefCell<ServoRng>,
subtle: MutNullableDom<SubtleCrypto>,
}
impl Crypto {
@ -32,6 +33,7 @@ impl Crypto {
Crypto {
reflector_: Reflector::new(),
rng: DomRefCell::new(ServoRng::default()),
subtle: MutNullableDom::default(),
}
}
@ -41,6 +43,11 @@ impl Crypto {
}
impl CryptoMethods for Crypto {
/// <https://w3c.github.io/webcrypto/#dfn-Crypto-attribute-subtle>
fn Subtle(&self) -> DomRoot<SubtleCrypto> {
self.subtle.or_init(|| SubtleCrypto::new(&self.global()))
}
#[allow(unsafe_code)]
// https://w3c.github.io/webcrypto/#Crypto-method-getRandomValues
fn GetRandomValues(

View file

@ -0,0 +1,140 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::Cell;
use std::ptr::NonNull;
use dom_struct::dom_struct;
use js::jsapi::{JSObject, Value};
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
CryptoKeyMethods, KeyType, KeyUsage,
};
use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{AesKeyAlgorithm, KeyAlgorithm};
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
use crate::js::conversions::ToJSValConvertible;
use crate::script_runtime::JSContext;
/// The underlying cryptographic data this key represents
#[allow(dead_code)]
pub enum Handle {
Aes128(Vec<u8>),
Aes192(Vec<u8>),
Aes256(Vec<u8>),
}
/// <https://w3c.github.io/webcrypto/#cryptokey-interface>
#[dom_struct]
pub struct CryptoKey {
reflector_: Reflector,
key_type: KeyType,
extractable: Cell<bool>,
// This would normally be KeyAlgorithm but we cannot Send DOMString, which
// is a member of Algorithm
algorithm: DomRefCell<String>,
usages: Vec<KeyUsage>,
#[ignore_malloc_size_of = "Defined in external cryptography crates"]
#[no_trace]
handle: Handle,
}
impl CryptoKey {
fn new_inherited(
key_type: KeyType,
extractable: bool,
algorithm: KeyAlgorithm,
usages: Vec<KeyUsage>,
handle: Handle,
) -> CryptoKey {
CryptoKey {
reflector_: Reflector::new(),
key_type,
extractable: Cell::new(extractable),
algorithm: DomRefCell::new(algorithm.name.to_string()),
usages,
handle,
}
}
pub fn new(
global: &GlobalScope,
key_type: KeyType,
extractable: bool,
algorithm: KeyAlgorithm,
usages: Vec<KeyUsage>,
handle: Handle,
) -> DomRoot<CryptoKey> {
reflect_dom_object(
Box::new(CryptoKey::new_inherited(
key_type,
extractable,
algorithm,
usages,
handle,
)),
global,
)
}
pub fn algorithm(&self) -> String {
self.algorithm.borrow().to_string()
}
pub fn handle(&self) -> &Handle {
&self.handle
}
}
impl CryptoKeyMethods for CryptoKey {
/// <https://w3c.github.io/webcrypto/#cryptokey-interface-members>
fn Type(&self) -> KeyType {
self.key_type.clone()
}
/// <https://w3c.github.io/webcrypto/#cryptokey-interface-members>
fn Extractable(&self) -> bool {
self.extractable.get()
}
#[allow(unsafe_code)]
/// <https://w3c.github.io/webcrypto/#cryptokey-interface-members>
fn Algorithm(&self, cx: JSContext) -> NonNull<JSObject> {
let parent = KeyAlgorithm {
name: DOMString::from_string(self.algorithm()),
};
let algorithm = match self.handle() {
Handle::Aes128(_) => AesKeyAlgorithm {
parent,
length: 128,
},
Handle::Aes192(_) => AesKeyAlgorithm {
parent,
length: 192,
},
Handle::Aes256(_) => AesKeyAlgorithm {
parent,
length: 256,
},
};
unsafe {
rooted!(in(*cx) let mut alg: Value);
algorithm.to_jsval(*cx, alg.handle_mut());
NonNull::new(alg.to_object()).unwrap()
}
}
#[allow(unsafe_code)]
/// <https://w3c.github.io/webcrypto/#cryptokey-interface-members>
fn Usages(&self, cx: JSContext) -> NonNull<JSObject> {
unsafe {
rooted!(in(*cx) let mut usages: Value);
self.usages.to_jsval(*cx, usages.handle_mut());
NonNull::new(usages.to_object()).unwrap()
}
}
}

View file

@ -257,6 +257,7 @@ pub mod console;
pub mod constantsourcenode;
mod create;
pub mod crypto;
pub mod cryptokey;
pub mod css;
pub mod cssconditionrule;
pub mod cssfontfacerule;
@ -543,6 +544,7 @@ pub mod stylepropertymapreadonly;
pub mod stylesheet;
pub mod stylesheetlist;
pub mod submitevent;
pub mod subtlecrypto;
pub mod svgelement;
pub mod svggraphicselement;
pub mod svgsvgelement;

View file

@ -0,0 +1,335 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::ptr;
use std::rc::Rc;
use dom_struct::dom_struct;
use js::conversions::ConversionResult;
use js::jsapi::JSObject;
use js::jsval::ObjectValue;
use js::typedarray::ArrayBufferU8;
use servo_rand::{RngCore, ServoRng};
use crate::dom::bindings::buffer_source::create_buffer_source;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
CryptoKeyMethods, KeyType, KeyUsage,
};
use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{
AesKeyGenParams, Algorithm, AlgorithmIdentifier, KeyAlgorithm, KeyFormat, SubtleCryptoMethods,
};
use crate::dom::bindings::error::Error;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::cryptokey::{CryptoKey, Handle};
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::window::Window;
use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::realms::InRealm;
use crate::script_runtime::JSContext;
use crate::task::TaskCanceller;
use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::TaskSource;
// String constants for algorithms/curves
const ALG_AES_CBC: &str = "AES-CBC";
const ALG_AES_CTR: &str = "AES-CTR";
const ALG_AES_GCM: &str = "AES-GCM";
const ALG_AES_KW: &str = "AES-KW";
const ALG_SHA1: &str = "SHA1";
const ALG_SHA256: &str = "SHA256";
const ALG_SHA384: &str = "SHA384";
const ALG_SHA512: &str = "SHA512";
const ALG_HMAC: &str = "HMAC";
const ALG_HKDF: &str = "HKDF";
const ALG_PBKDF2: &str = "PBKDF2";
const ALG_RSASSA_PKCS1: &str = "RSASSA-PKCS1-v1_5";
const ALG_RSA_OAEP: &str = "RSA-OAEP";
const ALG_RSA_PSS: &str = "RSA-PSS";
const ALG_ECDH: &str = "ECDH";
const ALG_ECDSA: &str = "ECDSA";
#[allow(dead_code)]
static SUPPORTED_ALGORITHMS: &[&str] = &[
ALG_AES_CBC,
ALG_AES_CTR,
ALG_AES_GCM,
ALG_AES_KW,
ALG_SHA1,
ALG_SHA256,
ALG_SHA384,
ALG_SHA512,
ALG_HMAC,
ALG_HKDF,
ALG_PBKDF2,
ALG_RSASSA_PKCS1,
ALG_RSA_OAEP,
ALG_RSA_PSS,
ALG_ECDH,
ALG_ECDSA,
];
const NAMED_CURVE_P256: &str = "P-256";
const NAMED_CURVE_P384: &str = "P-384";
const NAMED_CURVE_P521: &str = "P-521";
#[allow(dead_code)]
static SUPPORTED_CURVES: &[&str] = &[NAMED_CURVE_P256, NAMED_CURVE_P384, NAMED_CURVE_P521];
#[dom_struct]
pub struct SubtleCrypto {
reflector_: Reflector,
#[no_trace]
rng: DomRefCell<ServoRng>,
}
impl SubtleCrypto {
fn new_inherited() -> SubtleCrypto {
SubtleCrypto {
reflector_: Reflector::new(),
rng: DomRefCell::new(ServoRng::default()),
}
}
pub(crate) fn new(global: &GlobalScope) -> DomRoot<SubtleCrypto> {
reflect_dom_object(Box::new(SubtleCrypto::new_inherited()), global)
}
fn task_source_with_canceller(&self) -> (DOMManipulationTaskSource, TaskCanceller) {
if let Some(window) = self.global().downcast::<Window>() {
window
.task_manager()
.dom_manipulation_task_source_with_canceller()
} else if let Some(worker_global) = self.global().downcast::<WorkerGlobalScope>() {
let task_source = worker_global.dom_manipulation_task_source();
let canceller = worker_global.task_canceller();
(task_source, canceller)
} else {
unreachable!("Couldn't downcast to Window or WorkerGlobalScope!");
}
}
}
impl SubtleCryptoMethods for SubtleCrypto {
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-generateKey>
fn GenerateKey(
&self,
cx: JSContext,
algorithm: AlgorithmIdentifier,
extractable: bool,
key_usages: Vec<KeyUsage>,
comp: InRealm,
) -> Rc<Promise> {
let normalized_algorithm = normalize_algorithm(cx, algorithm, "generateKey");
let promise = Promise::new_in_current_realm(comp);
if let Err(e) = normalized_algorithm {
promise.reject_error(e);
return promise;
}
let (task_source, canceller) = self.task_source_with_canceller();
let this = Trusted::new(self);
let trusted_promise = TrustedPromise::new(promise.clone());
let alg = normalized_algorithm.clone();
let _ = task_source.queue_with_canceller(
task!(generate_key: move || {
let subtle = this.root();
let promise = trusted_promise.root();
let key = match alg {
Ok(NormalizedAlgorithm::AesKeyGenParams(key_gen_params)) => {
subtle.generate_key_aes_cbc(key_usages, key_gen_params, extractable)
},
_ => Err(Error::NotSupported),
};
match key {
Ok(key) => promise.resolve_native(&key),
Err(e) => promise.reject_error(e),
}
}),
&canceller,
);
promise
}
/// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-exportKey>
#[allow(unsafe_code)]
fn ExportKey(&self, format: KeyFormat, key: &CryptoKey, comp: InRealm) -> Rc<Promise> {
let promise = Promise::new_in_current_realm(comp);
let (task_source, canceller) = self.task_source_with_canceller();
let this = Trusted::new(self);
let trusted_key = Trusted::new(key);
let trusted_promise = TrustedPromise::new(promise.clone());
let _ = task_source.queue_with_canceller(
task!(export_key: move || {
let subtle = this.root();
let promise = trusted_promise.root();
let key = trusted_key.root();
let alg_name = key.algorithm();
if matches!(
alg_name.as_str(), ALG_SHA1 | ALG_SHA256 | ALG_SHA384 | ALG_SHA512 | ALG_HKDF | ALG_PBKDF2
) {
promise.reject_error(Error::NotSupported);
return;
}
if !key.Extractable() {
promise.reject_error(Error::InvalidAccess);
return;
}
let exported_key = match alg_name.as_str() {
ALG_AES_CBC => subtle.export_key_aes_cbc(format, &*key),
_ => Err(Error::NotSupported),
};
match exported_key {
Ok(k) => {
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
create_buffer_source::<ArrayBufferU8>(cx, &k, array_buffer_ptr.handle_mut())
.expect("failed to create buffer source for exported key.");
promise.resolve_native(&array_buffer_ptr.get())
},
Err(e) => promise.reject_error(e),
}
}),
&canceller,
);
promise
}
}
#[derive(Clone)]
pub enum NormalizedAlgorithm {
#[allow(dead_code)]
Algorithm(SubtleAlgorithm),
AesKeyGenParams(SubtleAesKeyGenParams),
}
// These "subtle" structs are proxies for the codegen'd dicts which don't hold a DOMString
// so they can be sent safely when running steps in parallel.
#[derive(Clone)]
pub struct SubtleAlgorithm {
#[allow(dead_code)]
pub name: String,
}
impl From<DOMString> for SubtleAlgorithm {
fn from(name: DOMString) -> Self {
SubtleAlgorithm {
name: name.to_string(),
}
}
}
#[derive(Clone)]
pub struct SubtleAesKeyGenParams {
#[allow(dead_code)]
pub name: String,
pub length: u16,
}
impl From<AesKeyGenParams> for SubtleAesKeyGenParams {
fn from(params: AesKeyGenParams) -> Self {
SubtleAesKeyGenParams {
name: params.parent.name.to_string(),
length: params.length,
}
}
}
/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
#[allow(unsafe_code)]
fn normalize_algorithm(
cx: JSContext,
algorithm: AlgorithmIdentifier,
operation: &str,
) -> Result<NormalizedAlgorithm, Error> {
match algorithm {
AlgorithmIdentifier::String(name) => Ok(NormalizedAlgorithm::Algorithm(name.into())),
AlgorithmIdentifier::Object(obj) => {
rooted!(in(*cx) let value = ObjectValue(unsafe { *obj.get_unsafe() }));
let Ok(ConversionResult::Success(algorithm)) = Algorithm::new(cx, value.handle())
else {
return Err(Error::Syntax);
};
match (algorithm.name.str().to_uppercase().as_str(), operation) {
(ALG_AES_CBC, "generateKey") => {
let params_result =
AesKeyGenParams::new(cx, value.handle()).map_err(|_| Error::Operation)?;
let ConversionResult::Success(params) = params_result else {
return Err(Error::Syntax);
};
Ok(NormalizedAlgorithm::AesKeyGenParams(params.into()))
},
_ => return Err(Error::NotSupported),
}
},
}
}
impl SubtleCrypto {
/// <https://w3c.github.io/webcrypto/#aes-cbc-operations>
fn generate_key_aes_cbc(
&self,
usages: Vec<KeyUsage>,
key_gen_params: SubtleAesKeyGenParams,
extractable: bool,
) -> Result<DomRoot<CryptoKey>, Error> {
if !matches!(key_gen_params.length, 128 | 192 | 256) {
return Err(Error::Operation);
}
if usages.iter().any(|usage| {
!matches!(
usage,
KeyUsage::Encrypt | KeyUsage::Decrypt | KeyUsage::WrapKey | KeyUsage::UnwrapKey
)
}) || usages.is_empty()
{
return Err(Error::Syntax);
}
let mut rand = Vec::new();
rand.resize(key_gen_params.length as usize, 0);
self.rng.borrow_mut().fill_bytes(&mut rand);
let handle = match key_gen_params.length {
128 => Handle::Aes128(rand),
192 => Handle::Aes192(rand),
256 => Handle::Aes256(rand),
_ => return Err(Error::Operation),
};
Ok(CryptoKey::new(
&self.global(),
KeyType::Secret,
extractable,
KeyAlgorithm {
name: DOMString::from(ALG_AES_CBC),
},
usages,
handle,
))
}
/// <https://w3c.github.io/webcrypto/#aes-cbc-operations>
fn export_key_aes_cbc(&self, format: KeyFormat, key: &CryptoKey) -> Result<Vec<u8>, Error> {
match format {
KeyFormat::Raw => match key.handle() {
Handle::Aes128(key) => Ok(key.as_slice().to_vec()),
Handle::Aes192(key) => Ok(key.as_slice().to_vec()),
Handle::Aes256(key) => Ok(key.as_slice().to_vec()),
},
KeyFormat::Jwk => {
// TODO: Support jwk
Err(Error::NotSupported)
},
_ => Err(Error::NotSupported),
}
}
}

View file

@ -17,7 +17,7 @@ WorkerGlobalScope includes GlobalCrypto;
[Exposed=(Window,Worker)]
interface Crypto {
//readonly attribute SubtleCrypto subtle;
[SecureContext] readonly attribute SubtleCrypto subtle;
[Throws]
ArrayBufferView getRandomValues(ArrayBufferView array);

View file

@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// https://w3c.github.io/webcrypto/#cryptokey-interface
enum KeyType { "public", "private", "secret" };
enum KeyUsage { "encrypt", "decrypt", "sign", "verify", "deriveKey", "deriveBits", "wrapKey", "unwrapKey" };
[SecureContext, Exposed=(Window,Worker), Serializable, Pref="dom.crypto.subtle.enabled"]
interface CryptoKey {
readonly attribute KeyType type;
readonly attribute boolean extractable;
readonly attribute object algorithm;
readonly attribute object usages;
};

View file

@ -0,0 +1,87 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// https://w3c.github.io/webcrypto/#subtlecrypto-interface
typedef (object or DOMString) AlgorithmIdentifier;
typedef AlgorithmIdentifier HashAlgorithmIdentifier;
dictionary Algorithm {
required DOMString name;
};
dictionary KeyAlgorithm {
required DOMString name;
};
enum KeyFormat { "raw", "spki", "pkcs8", "jwk" };
[SecureContext,Exposed=(Window,Worker),Pref="dom.crypto.subtle.enabled"]
interface SubtleCrypto {
// Promise<any> encrypt(AlgorithmIdentifier algorithm,
// CryptoKey key,
// BufferSource data);
// Promise<any> decrypt(AlgorithmIdentifier algorithm,
// CryptoKey key,
// BufferSource data);
// Promise<any> sign(AlgorithmIdentifier algorithm,
// CryptoKey key,
// BufferSource data);
// Promise<any> verify(AlgorithmIdentifier algorithm,
// CryptoKey key,
// BufferSource signature,
// BufferSource data);
// Promise<any> digest(AlgorithmIdentifier algorithm,
// BufferSource data);
Promise<any> generateKey(AlgorithmIdentifier algorithm,
boolean extractable,
sequence<KeyUsage> keyUsages );
// Promise<any> deriveKey(AlgorithmIdentifier algorithm,
// CryptoKey baseKey,
// AlgorithmIdentifier derivedKeyType,
// boolean extractable,
// sequence<KeyUsage> keyUsages );
// Promise<ArrayBuffer> deriveBits(AlgorithmIdentifier algorithm,
// CryptoKey baseKey,
// optional unsigned long? length = null);
// Promise<CryptoKey> importKey(KeyFormat format,
// (BufferSource or JsonWebKey) keyData,
// AlgorithmIdentifier algorithm,
// boolean extractable,
// sequence<KeyUsage> keyUsages );
Promise<any> exportKey(KeyFormat format, CryptoKey key);
// Promise<any> wrapKey(KeyFormat format,
// CryptoKey key,
// CryptoKey wrappingKey,
// AlgorithmIdentifier wrapAlgorithm);
// Promise<CryptoKey> unwrapKey(KeyFormat format,
// BufferSource wrappedKey,
// CryptoKey unwrappingKey,
// AlgorithmIdentifier unwrapAlgorithm,
// AlgorithmIdentifier unwrappedKeyAlgorithm,
// boolean extractable,
// sequence<KeyUsage> keyUsages );
};
// AES shared
dictionary AesKeyAlgorithm : KeyAlgorithm {
required unsigned short length;
};
dictionary AesKeyGenParams : Algorithm {
required [EnforceRange] unsigned short length;
};
dictionary AesDerivedKeyParams : Algorithm {
required [EnforceRange] unsigned short length;
};
// AES_CBC
dictionary AesCbcParams : Algorithm {
required BufferSource iv;
};