aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
authorSimon Wülker <simon.wuelker@arcor.de>2024-11-19 13:42:37 +0100
committerGitHub <noreply@github.com>2024-11-19 12:42:37 +0000
commit83f8e888189cc265e73d6a3849f7b8c71c080181 (patch)
tree80535c774a67ce136a03edff95aa4f98a91b294a /components/script/dom
parent5113147f801bc6ef1f1da7d181599f13b76c0a0d (diff)
downloadservo-83f8e888189cc265e73d6a3849f7b8c71c080181.tar.gz
servo-83f8e888189cc265e73d6a3849f7b8c71c080181.zip
Implement AES-GCM support for subtlecrypto (#34269)
* Support normalizing AES-GCM for encryption Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Implement "encrypt" operation for AES-GCM Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Allow importing AES-GCM keys Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Implement AES-GCM decryption Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Allow normalizing AES-GCM for "generate key" Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Update WPT expectations Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * fmt Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Fix clippy errors Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Remove silly checks Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Support AES-GCM 128-bit encryption with 128 bit IV Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Support AES-GCM with wrapKey/unwrapKey Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Update WPT expectations (again) Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/subtlecrypto.rs358
-rw-r--r--components/script/dom/webidls/SubtleCrypto.webidl7
2 files changed, 343 insertions, 22 deletions
diff --git a/components/script/dom/subtlecrypto.rs b/components/script/dom/subtlecrypto.rs
index 9ff82f02945..e3638d34b04 100644
--- a/components/script/dom/subtlecrypto.rs
+++ b/components/script/dom/subtlecrypto.rs
@@ -10,8 +10,10 @@ use aes::cipher::block_padding::Pkcs7;
use aes::cipher::generic_array::GenericArray;
use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, StreamCipher};
use aes::{Aes128, Aes192, Aes256};
+use aes_gcm::{AeadInPlace, AesGcm, KeyInit};
use aes_kw::{KekAes128, KekAes192, KekAes256};
use base64::prelude::*;
+use cipher::consts::{U12, U16, U32};
use dom_struct::dom_struct;
use js::conversions::ConversionResult;
use js::jsapi::{JSObject, JS_NewObject};
@@ -28,9 +30,10 @@ use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
CryptoKeyMethods, KeyType, KeyUsage,
};
use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{
- AesCbcParams, AesCtrParams, AesDerivedKeyParams, AesKeyAlgorithm, AesKeyGenParams, Algorithm,
- AlgorithmIdentifier, HkdfParams, HmacImportParams, HmacKeyAlgorithm, HmacKeyGenParams,
- JsonWebKey, KeyAlgorithm, KeyFormat, Pbkdf2Params, SubtleCryptoMethods,
+ AesCbcParams, AesCtrParams, AesDerivedKeyParams, AesGcmParams, AesKeyAlgorithm,
+ AesKeyGenParams, Algorithm, AlgorithmIdentifier, HkdfParams, HmacImportParams,
+ HmacKeyAlgorithm, HmacKeyGenParams, JsonWebKey, KeyAlgorithm, KeyFormat, Pbkdf2Params,
+ SubtleCryptoMethods,
};
use crate::dom::bindings::codegen::UnionTypes::{
ArrayBufferViewOrArrayBuffer, ArrayBufferViewOrArrayBufferOrJsonWebKey,
@@ -108,6 +111,14 @@ type Aes128Ctr = ctr::Ctr64BE<Aes128>;
type Aes192Ctr = ctr::Ctr64BE<Aes192>;
type Aes256Ctr = ctr::Ctr64BE<Aes256>;
+type Aes128Gcm96Iv = AesGcm<Aes128, U12>;
+type Aes128Gcm128Iv = AesGcm<Aes128, U16>;
+type Aes192Gcm96Iv = AesGcm<Aes192, U12>;
+type Aes256Gcm96Iv = AesGcm<Aes256, U12>;
+type Aes128Gcm256Iv = AesGcm<Aes128, U32>;
+type Aes192Gcm256Iv = AesGcm<Aes192, U32>;
+type Aes256Gcm256Iv = AesGcm<Aes256, U32>;
+
#[dom_struct]
pub struct SubtleCrypto {
reflector_: Reflector,
@@ -838,7 +849,7 @@ impl SubtleCryptoMethods for SubtleCrypto {
return;
}
let exported_key = match alg_name.as_str() {
- ALG_AES_CBC | ALG_AES_CTR | ALG_AES_KW => subtle.export_key_aes(format, &key),
+ ALG_AES_CBC | ALG_AES_CTR | ALG_AES_KW | ALG_AES_GCM => subtle.export_key_aes(format, &key),
_ => Err(Error::NotSupported),
};
match exported_key {
@@ -965,6 +976,11 @@ impl SubtleCryptoMethods for SubtleCrypto {
&params, &wrapping_key, &bytes, cx, array_buffer_ptr.handle_mut()
)
},
+ KeyWrapAlgorithm::AesGcm(params) => {
+ subtle.encrypt_aes_gcm(
+ &params, &wrapping_key, &bytes, cx, array_buffer_ptr.handle_mut()
+ )
+ },
};
match result {
@@ -1047,6 +1063,11 @@ impl SubtleCryptoMethods for SubtleCrypto {
&params, &unwrapping_key, &wrapped_key_bytes, cx, array_buffer_ptr.handle_mut()
)
},
+ KeyWrapAlgorithm::AesGcm(params) => {
+ subtle.decrypt_aes_gcm(
+ &params, &unwrapping_key, &wrapped_key_bytes, cx, array_buffer_ptr.handle_mut()
+ )
+ },
};
let bytes = match result {
@@ -1140,6 +1161,34 @@ impl From<RootedTraceableBox<AesCtrParams>> for SubtleAesCtrParams {
}
#[derive(Clone, Debug)]
+pub struct SubtleAesGcmParams {
+ pub name: String,
+ pub iv: Vec<u8>,
+ pub additional_data: Option<Vec<u8>>,
+ pub tag_length: Option<u8>,
+}
+
+impl From<RootedTraceableBox<AesGcmParams>> for SubtleAesGcmParams {
+ fn from(params: RootedTraceableBox<AesGcmParams>) -> Self {
+ let iv = match &params.iv {
+ ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
+ ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
+ };
+ let additional_data = params.additionalData.as_ref().map(|data| match data {
+ ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
+ ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
+ });
+
+ SubtleAesGcmParams {
+ name: params.parent.name.to_string(),
+ iv,
+ additional_data,
+ tag_length: params.tagLength,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
pub struct SubtleAesKeyGenParams {
pub name: String,
pub length: u16,
@@ -1313,6 +1362,7 @@ enum ImportKeyAlgorithm {
AesCbc,
AesCtr,
AesKw,
+ AesGcm,
Hmac(SubtleHmacImportParams),
Pbkdf2,
Hkdf,
@@ -1329,9 +1379,11 @@ enum DeriveBitsAlgorithm {
/// A normalized algorithm returned by [`normalize_algorithm`] with operation `"encrypt"` or `"decrypt"`
///
/// [`normalize_algorithm`]: https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm
+#[allow(clippy::enum_variant_names)]
enum EncryptionAlgorithm {
AesCbc(SubtleAesCbcParams),
AesCtr(SubtleAesCtrParams),
+ AesGcm(SubtleAesGcmParams),
}
/// A normalized algorithm returned by [`normalize_algorithm`] with operation `"sign"` or `"verify"`
@@ -1357,6 +1409,7 @@ enum KeyWrapAlgorithm {
AesKw,
AesCbc(SubtleAesCbcParams),
AesCtr(SubtleAesCtrParams),
+ AesGcm(SubtleAesGcmParams),
}
macro_rules! value_from_js_object {
@@ -1381,7 +1434,8 @@ fn normalize_algorithm_for_get_key_length(
let name = algorithm.name.str();
let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) ||
- name.eq_ignore_ascii_case(ALG_AES_CTR)
+ name.eq_ignore_ascii_case(ALG_AES_CTR) ||
+ name.eq_ignore_ascii_case(ALG_AES_GCM)
{
let params = value_from_js_object!(AesDerivedKeyParams, cx, value);
GetKeyLengthAlgorithm::Aes(params.length)
@@ -1454,6 +1508,7 @@ fn normalize_algorithm_for_import_key(
ALG_AES_CBC => ImportKeyAlgorithm::AesCbc,
ALG_AES_CTR => ImportKeyAlgorithm::AesCtr,
ALG_AES_KW => ImportKeyAlgorithm::AesKw,
+ ALG_AES_GCM => ImportKeyAlgorithm::AesGcm,
ALG_PBKDF2 => ImportKeyAlgorithm::Pbkdf2,
ALG_HKDF => ImportKeyAlgorithm::Hkdf,
_ => return Err(Error::NotSupported),
@@ -1510,6 +1565,9 @@ fn normalize_algorithm_for_encrypt_or_decrypt(
} else if name.eq_ignore_ascii_case(ALG_AES_CTR) {
let params = value_from_js_object!(AesCtrParams, cx, value);
EncryptionAlgorithm::AesCtr(params.into())
+ } else if name.eq_ignore_ascii_case(ALG_AES_GCM) {
+ let params = value_from_js_object!(AesGcmParams, cx, value);
+ EncryptionAlgorithm::AesGcm(params.into())
} else {
return Err(Error::NotSupported);
};
@@ -1557,7 +1615,8 @@ fn normalize_algorithm_for_generate_key(
let name = algorithm.name.str();
let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) ||
name.eq_ignore_ascii_case(ALG_AES_CTR) ||
- name.eq_ignore_ascii_case(ALG_AES_KW)
+ name.eq_ignore_ascii_case(ALG_AES_KW) ||
+ name.eq_ignore_ascii_case(ALG_AES_GCM)
{
let params = value_from_js_object!(AesKeyGenParams, cx, value);
KeyGenerationAlgorithm::Aes(params.into())
@@ -1603,6 +1662,13 @@ fn normalize_algorithm_for_key_wrap(
rooted!(in(*cx) let value = ObjectValue(obj.get()));
KeyWrapAlgorithm::AesCtr(value_from_js_object!(AesCtrParams, cx, value).into())
},
+ ALG_AES_GCM => {
+ let AlgorithmIdentifier::Object(obj) = algorithm else {
+ return Err(Error::Syntax);
+ };
+ rooted!(in(*cx) let value = ObjectValue(obj.get()));
+ KeyWrapAlgorithm::AesGcm(value_from_js_object!(AesGcmParams, cx, value).into())
+ },
_ => return Err(Error::NotSupported),
};
@@ -1730,6 +1796,250 @@ impl SubtleCrypto {
Ok(ciphertext)
}
+ /// <https://w3c.github.io/webcrypto/#aes-gcm-operations>
+ fn encrypt_aes_gcm(
+ &self,
+ params: &SubtleAesGcmParams,
+ key: &CryptoKey,
+ plaintext: &[u8],
+ cx: JSContext,
+ handle: MutableHandleObject,
+ ) -> Result<Vec<u8>, Error> {
+ // Step 1. If plaintext has a length greater than 2^39 - 256 bytes, then throw an OperationError.
+ if plaintext.len() as u64 > (2 << 39) - 256 {
+ return Err(Error::Operation);
+ }
+
+ // Step 2. If the iv member of normalizedAlgorithm has a length greater than 2^64 - 1 bytes,
+ // then throw an OperationError.
+ // NOTE: servo does not currently support 128-bit platforms, so this can never happen
+
+ // Step 3. If the additionalData member of normalizedAlgorithm is present and has a length greater than 2^64 - 1
+ // bytes, then throw an OperationError.
+ if params
+ .additional_data
+ .as_ref()
+ .is_some_and(|data| data.len() > u64::MAX as usize)
+ {
+ return Err(Error::Operation);
+ }
+
+ // Step 4.
+ let tag_length = match params.tag_length {
+ // If the tagLength member of normalizedAlgorithm is not present:
+ None => {
+ // Let tagLength be 128.
+ 128
+ },
+ // If the tagLength member of normalizedAlgorithm is one of 32, 64, 96, 104, 112, 120 or 128:
+ Some(length) if matches!(length, 32 | 64 | 96 | 104 | 112 | 120 | 128) => {
+ // Let tagLength be equal to the tagLength member of normalizedAlgorithm
+ length
+ },
+ // Otherwise:
+ _ => {
+ // throw an OperationError.
+ return Err(Error::Operation);
+ },
+ };
+
+ // Step 5. Let additionalData be the contents of the additionalData member of normalizedAlgorithm if present
+ // or the empty octet string otherwise.
+ let additional_data = params.additional_data.as_deref().unwrap_or_default();
+
+ // Step 6. Let C and T be the outputs that result from performing the Authenticated Encryption Function
+ // described in Section 7.1 of [NIST-SP800-38D] using AES as the block cipher, the contents of the iv member
+ // of normalizedAlgorithm as the IV input parameter, the contents of additionalData as the A input parameter,
+ // tagLength as the t pre-requisite and the contents of plaintext as the input plaintext.
+ let key_length = key.handle().as_bytes().len();
+ let iv_length = params.iv.len();
+ let mut ciphertext = plaintext.to_vec();
+ let key_bytes = key.handle().as_bytes();
+ let tag = match (key_length, iv_length) {
+ (16, 12) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes128Gcm96Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
+ },
+ (16, 16) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes128Gcm128Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
+ },
+ (20, 12) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes192Gcm96Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
+ },
+ (32, 12) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes256Gcm96Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
+ },
+ (16, 32) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes128Gcm256Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
+ },
+ (20, 32) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes192Gcm256Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
+ },
+ (32, 32) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes256Gcm256Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
+ },
+ _ => {
+ log::warn!(
+ "Missing AES-GCM encryption implementation with {key_length}-byte key and {iv_length}-byte IV"
+ );
+ return Err(Error::NotSupported);
+ },
+ };
+
+ // Step 7. Let ciphertext be equal to C | T, where '|' denotes concatenation.
+ ciphertext.extend_from_slice(&tag.unwrap()[..tag_length as usize / 8]);
+
+ // Step 8. Return the result of creating an ArrayBuffer containing ciphertext.
+ create_buffer_source::<ArrayBufferU8>(cx, &ciphertext, handle)
+ .expect("failed to create buffer source for encrypted ciphertext");
+
+ Ok(ciphertext)
+ }
+
+ /// <https://w3c.github.io/webcrypto/#aes-gcm-operations>
+ fn decrypt_aes_gcm(
+ &self,
+ params: &SubtleAesGcmParams,
+ key: &CryptoKey,
+ ciphertext: &[u8],
+ cx: JSContext,
+ handle: MutableHandleObject,
+ ) -> Result<Vec<u8>, Error> {
+ // Step 1.
+ // FIXME: aes_gcm uses a fixed tag length
+ let tag_length = match params.tag_length {
+ // If the tagLength member of normalizedAlgorithm is not present:
+ None => {
+ // Let tagLength be 128.
+ 128
+ },
+ // If the tagLength member of normalizedAlgorithm is one of 32, 64, 96, 104, 112, 120 or 128:
+ Some(length) if matches!(length, 32 | 64 | 96 | 104 | 112 | 120 | 128) => {
+ // Let tagLength be equal to the tagLength member of normalizedAlgorithm
+ length as usize
+ },
+ // Otherwise:
+ _ => {
+ // throw an OperationError.
+ return Err(Error::Operation);
+ },
+ };
+
+ // Step 2. If ciphertext has a length less than tagLength bits, then throw an OperationError.
+ if ciphertext.len() < tag_length / 8 {
+ return Err(Error::Operation);
+ }
+
+ // Step 3. If the iv member of normalizedAlgorithm has a length greater than 2^64 - 1 bytes,
+ // then throw an OperationError.
+ // NOTE: servo does not currently support 128-bit platforms, so this can never happen
+
+ // Step 4. If the additionalData member of normalizedAlgorithm is present and has a length greater than 2^64 - 1
+ // bytes, then throw an OperationError.
+ // NOTE: servo does not currently support 128-bit platforms, so this can never happen
+
+ // Step 5. Let tag be the last tagLength bits of ciphertext.
+ // Step 6. Let actualCiphertext be the result of removing the last tagLength bits from ciphertext.
+ // NOTE: aes_gcm splits the ciphertext for us
+
+ // Step 7. Let additionalData be the contents of the additionalData member of normalizedAlgorithm if present or
+ // the empty octet string otherwise.
+ let additional_data = params.additional_data.as_deref().unwrap_or_default();
+
+ // Step 8. Perform the Authenticated Decryption Function described in Section 7.2 of [NIST-SP800-38D] using AES
+ // as the block cipher, the contents of the iv member of normalizedAlgorithm as the IV input parameter, the
+ // contents of additionalData as the A input parameter, tagLength as the t pre-requisite, the contents of
+ // actualCiphertext as the input ciphertext, C and the contents of tag as the authentication tag, T.
+ let mut plaintext = ciphertext.to_vec();
+ let key_length = key.handle().as_bytes().len();
+ let iv_length = params.iv.len();
+ let key_bytes = key.handle().as_bytes();
+ let result = match (key_length, iv_length) {
+ (16, 12) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes128Gcm96Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .decrypt_in_place(nonce, additional_data, &mut plaintext)
+ },
+ (16, 16) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes128Gcm128Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .decrypt_in_place(nonce, additional_data, &mut plaintext)
+ },
+ (20, 12) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes192Gcm96Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .decrypt_in_place(nonce, additional_data, &mut plaintext)
+ },
+ (32, 12) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes256Gcm96Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .decrypt_in_place(nonce, additional_data, &mut plaintext)
+ },
+ (16, 32) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes128Gcm256Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .decrypt_in_place(nonce, additional_data, &mut plaintext)
+ },
+ (20, 32) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes192Gcm256Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .decrypt_in_place(nonce, additional_data, &mut plaintext)
+ },
+ (32, 32) => {
+ let nonce = GenericArray::from_slice(&params.iv);
+ <Aes256Gcm256Iv>::new_from_slice(key_bytes)
+ .expect("key length did not match")
+ .decrypt_in_place(nonce, additional_data, &mut plaintext)
+ },
+ _ => {
+ log::warn!(
+ "Missing AES-GCM decryption implementation with {key_length}-byte key and {iv_length}-byte IV"
+ );
+ return Err(Error::NotSupported);
+ },
+ };
+
+ // If the result of the algorithm is the indication of inauthenticity, "FAIL":
+ if result.is_err() {
+ // throw an OperationError
+ return Err(Error::Operation);
+ }
+ // Otherwise:
+ // Let plaintext be the output P of the Authenticated Decryption Function.
+
+ // Step 9. Return the result of creating an ArrayBuffer containing plaintext.
+ create_buffer_source::<ArrayBufferU8>(cx, &plaintext, handle)
+ .expect("failed to create buffer source for decrypted plaintext");
+
+ Ok(plaintext)
+ }
+
/// <https://w3c.github.io/webcrypto/#aes-cbc-operations>
/// <https://w3c.github.io/webcrypto/#aes-ctr-operations>
/// <https://w3c.github.io/webcrypto/#aes-kw-operations>
@@ -1750,7 +2060,7 @@ impl SubtleCrypto {
};
match key_gen_params.name.as_str() {
- ALG_AES_CBC | ALG_AES_CTR => {
+ ALG_AES_CBC | ALG_AES_CTR | ALG_AES_GCM => {
if usages.iter().any(|usage| {
!matches!(
usage,
@@ -1780,6 +2090,7 @@ impl SubtleCrypto {
ALG_AES_CBC => DOMString::from(ALG_AES_CBC),
ALG_AES_CTR => DOMString::from(ALG_AES_CTR),
ALG_AES_KW => DOMString::from(ALG_AES_KW),
+ ALG_AES_GCM => DOMString::from(ALG_AES_GCM),
_ => return Err(Error::NotSupported),
};
@@ -2303,6 +2614,7 @@ fn data_to_jwk_params(alg: &str, size: &str, key: &[u8]) -> (DOMString, DOMStrin
ALG_AES_CBC => DOMString::from(format!("A{}CBC", size)),
ALG_AES_CTR => DOMString::from(format!("A{}CTR", size)),
ALG_AES_KW => DOMString::from(format!("A{}KW", size)),
+ ALG_AES_GCM => DOMString::from(format!("A{}GCM", size)),
_ => unreachable!(),
};
let data = base64::engine::general_purpose::STANDARD_NO_PAD.encode(key);
@@ -2529,6 +2841,9 @@ impl ImportKeyAlgorithm {
Self::AesKw => {
subtle.import_key_aes(format, secret, extractable, key_usages, ALG_AES_KW)
},
+ Self::AesGcm => {
+ subtle.import_key_aes(format, secret, extractable, key_usages, ALG_AES_GCM)
+ },
Self::Hmac(params) => {
subtle.import_key_hmac(params, format, secret, extractable, key_usages)
},
@@ -2551,8 +2866,9 @@ impl EncryptionAlgorithm {
/// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
fn name(&self) -> &str {
match self {
- Self::AesCbc(key_gen_params) => &key_gen_params.name,
- Self::AesCtr(key_gen_params) => &key_gen_params.name,
+ Self::AesCbc(params) => &params.name,
+ Self::AesCtr(params) => &params.name,
+ Self::AesGcm(params) => &params.name,
}
}
@@ -2566,12 +2882,9 @@ impl EncryptionAlgorithm {
result: MutableHandleObject,
) -> Result<Vec<u8>, Error> {
match self {
- Self::AesCbc(key_gen_params) => {
- subtle.encrypt_aes_cbc(key_gen_params, key, data, cx, result)
- },
- Self::AesCtr(key_gen_params) => {
- subtle.encrypt_decrypt_aes_ctr(key_gen_params, key, data, cx, result)
- },
+ Self::AesCbc(params) => subtle.encrypt_aes_cbc(params, key, data, cx, result),
+ Self::AesCtr(params) => subtle.encrypt_decrypt_aes_ctr(params, key, data, cx, result),
+ Self::AesGcm(params) => subtle.encrypt_aes_gcm(params, key, data, cx, result),
}
}
@@ -2585,12 +2898,9 @@ impl EncryptionAlgorithm {
result: MutableHandleObject,
) -> Result<Vec<u8>, Error> {
match self {
- Self::AesCbc(key_gen_params) => {
- subtle.decrypt_aes_cbc(key_gen_params, key, data, cx, result)
- },
- Self::AesCtr(key_gen_params) => {
- subtle.encrypt_decrypt_aes_ctr(key_gen_params, key, data, cx, result)
- },
+ Self::AesCbc(params) => subtle.decrypt_aes_cbc(params, key, data, cx, result),
+ Self::AesCtr(params) => subtle.encrypt_decrypt_aes_ctr(params, key, data, cx, result),
+ Self::AesGcm(params) => subtle.decrypt_aes_gcm(params, key, data, cx, result),
}
}
}
@@ -2684,6 +2994,7 @@ impl KeyWrapAlgorithm {
Self::AesKw => ALG_AES_KW,
Self::AesCbc(key_gen_params) => &key_gen_params.name,
Self::AesCtr(key_gen_params) => &key_gen_params.name,
+ Self::AesGcm(_) => ALG_AES_GCM,
}
}
}
@@ -2704,7 +3015,10 @@ fn parse_jwk(bytes: &[u8], alg: ImportKeyAlgorithm, extractable: bool) -> Result
}
match alg {
- ImportKeyAlgorithm::AesCbc | ImportKeyAlgorithm::AesCtr | ImportKeyAlgorithm::AesKw => {
+ ImportKeyAlgorithm::AesCbc |
+ ImportKeyAlgorithm::AesCtr |
+ ImportKeyAlgorithm::AesKw |
+ ImportKeyAlgorithm::AesGcm => {
if kty != "oct" {
return Err(Error::Data);
}
diff --git a/components/script/dom/webidls/SubtleCrypto.webidl b/components/script/dom/webidls/SubtleCrypto.webidl
index f966bf11b91..be01cebf589 100644
--- a/components/script/dom/webidls/SubtleCrypto.webidl
+++ b/components/script/dom/webidls/SubtleCrypto.webidl
@@ -92,6 +92,13 @@ dictionary AesCtrParams : Algorithm {
required [EnforceRange] octet length;
};
+// https://w3c.github.io/webcrypto/#aes-gcm-params
+dictionary AesGcmParams : Algorithm {
+ required BufferSource iv;
+ BufferSource additionalData;
+ [EnforceRange] octet tagLength;
+};
+
// https://w3c.github.io/webcrypto/#dfn-HmacImportParams
dictionary HmacImportParams : Algorithm {
required HashAlgorithmIdentifier hash;