script/dom/subtlecrypto/
aes_gcm_operation.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use aes::cipher::crypto_common::Key;
6use aes::cipher::typenum::{U12, U13, U14, U15, U16, U32};
7use aes::{Aes128, Aes192, Aes256};
8use aes_gcm::aead::AeadMutInPlace;
9use aes_gcm::{AesGcm, KeyInit};
10use cipher::{ArrayLength, BlockCipher, BlockEncrypt, BlockSizeUser};
11use js::context::JSContext;
12
13use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::KeyUsage;
14use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::KeyFormat;
15use crate::dom::bindings::error::Error;
16use crate::dom::bindings::root::DomRoot;
17use crate::dom::cryptokey::{CryptoKey, Handle};
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::subtlecrypto::aes_common::AesAlgorithm;
20use crate::dom::subtlecrypto::{
21    ExportedKey, SubtleAesDerivedKeyParams, SubtleAesGcmParams, SubtleAesKeyGenParams, aes_common,
22};
23
24/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-encrypt>
25pub(crate) fn encrypt(
26    normalized_algorithm: &SubtleAesGcmParams,
27    key: &CryptoKey,
28    plaintext: &[u8],
29) -> Result<Vec<u8>, Error> {
30    // Step 1. If plaintext has a length greater than 2^39 - 256 bytes, then throw an
31    // OperationError.
32    if plaintext.len() as u64 > (1 << 39) - 256 {
33        return Err(Error::Operation(Some("The plaintext is too long".into())));
34    }
35
36    // Step 2. If the iv member of normalizedAlgorithm has a length greater than 2^64 - 1 bytes,
37    // then throw an OperationError.
38    if normalized_algorithm.iv.len() > u64::MAX as usize {
39        return Err(Error::Operation(Some(
40            "The iv member of normalizedAlgorithm is too long".into(),
41        )));
42    }
43
44    // Step 3. If the additionalData member of normalizedAlgorithm is present and has a length
45    // greater than 2^64 - 1 bytes, then throw an OperationError.
46    if normalized_algorithm
47        .additional_data
48        .as_ref()
49        .is_some_and(|data| data.len() > u64::MAX as usize)
50    {
51        return Err(Error::Operation(Some(
52            "The additional authentication data is too long".into(),
53        )));
54    }
55
56    // Step 4.
57    // If the tagLength member of normalizedAlgorithm is not present:
58    //     Let tagLength be 128.
59    // If the tagLength member of normalizedAlgorithm is one of 32, 64, 96, 104, 112, 120 or 128:
60    //     Let tagLength be equal to the tagLength member of normalizedAlgorithm
61    // Otherwise:
62    //     throw an OperationError.
63    let tag_length = match normalized_algorithm.tag_length {
64        None => 128,
65        Some(tag_length) if matches!(tag_length, 32 | 64 | 96 | 104 | 112 | 120 | 128) => {
66            tag_length
67        },
68        _ => {
69            return Err(Error::Operation(Some(
70                "The tagLength member of normalizedAlgorithm is present, \
71                and not one of 32, 64, 96, 104, 112, 120 or 128"
72                    .to_string(),
73            )));
74        },
75    };
76
77    // Step 5. Let additionalData be the additionalData member of normalizedAlgorithm if present or
78    // an empty byte sequence otherwise.
79    let additional_data = normalized_algorithm
80        .additional_data
81        .as_deref()
82        .unwrap_or_default();
83
84    // Step 6. Let C and T be the outputs that result from performing the Authenticated Encryption
85    // Function described in Section 7.1 of [NIST-SP800-38D] using AES as the block cipher, the iv
86    // member of normalizedAlgorithm as the IV input parameter, additionalData as the A input
87    // parameter, tagLength as the t pre-requisite and plaintext as the input plaintext.
88    // Step 7. Let ciphertext be equal to C | T, where '|' denotes concatenation.
89    //
90    // NOTE: We currently support:
91    // - IV: 96-bit, 128-bit, 256-bit
92    // - Tag length: 32-bit, 64-bit, 96-bit, 104-bit, 112-bit, 120-bit, 128-bit
93    //
94    // NOTE: The crate `aes-gcm` does not directly support 32-bit and 64-bit tag length. Our
95    // workaround is to perform the Authenticated Encryption Function using 96-bit tag length, and
96    // then remove the last 64 bits for 32-bit tag length, and remove last 32 bits for 64-bit tag
97    // length, from the ciphertext.
98    let iv = normalized_algorithm.iv.as_slice();
99    let ciphertext = match key.handle() {
100        Handle::Aes128Key(key) => match (iv.len(), tag_length) {
101            // 96-bit nonce
102            (12, 32) => {
103                let mut ciphertext =
104                    gcm_encrypt::<Aes128, U12, U12>(key, plaintext, iv, additional_data)?;
105                ciphertext.truncate(ciphertext.len() - 8);
106                ciphertext
107            },
108            (12, 64) => {
109                let mut ciphertext =
110                    gcm_encrypt::<Aes128, U12, U12>(key, plaintext, iv, additional_data)?;
111                ciphertext.truncate(ciphertext.len() - 4);
112                ciphertext
113            },
114            (12, 96) => gcm_encrypt::<Aes128, U12, U12>(key, plaintext, iv, additional_data)?,
115            (12, 104) => gcm_encrypt::<Aes128, U12, U13>(key, plaintext, iv, additional_data)?,
116            (12, 112) => gcm_encrypt::<Aes128, U12, U14>(key, plaintext, iv, additional_data)?,
117            (12, 120) => gcm_encrypt::<Aes128, U12, U15>(key, plaintext, iv, additional_data)?,
118            (12, 128) => gcm_encrypt::<Aes128, U12, U16>(key, plaintext, iv, additional_data)?,
119
120            // 128-bit nonce
121            (16, 32) => {
122                let mut ciphertext =
123                    gcm_encrypt::<Aes128, U16, U12>(key, plaintext, iv, additional_data)?;
124                ciphertext.truncate(ciphertext.len() - 8);
125                ciphertext
126            },
127            (16, 64) => {
128                let mut ciphertext =
129                    gcm_encrypt::<Aes128, U16, U12>(key, plaintext, iv, additional_data)?;
130                ciphertext.truncate(ciphertext.len() - 4);
131                ciphertext
132            },
133            (16, 96) => gcm_encrypt::<Aes128, U16, U12>(key, plaintext, iv, additional_data)?,
134            (16, 104) => gcm_encrypt::<Aes128, U16, U13>(key, plaintext, iv, additional_data)?,
135            (16, 112) => gcm_encrypt::<Aes128, U16, U14>(key, plaintext, iv, additional_data)?,
136            (16, 120) => gcm_encrypt::<Aes128, U16, U15>(key, plaintext, iv, additional_data)?,
137            (16, 128) => gcm_encrypt::<Aes128, U16, U16>(key, plaintext, iv, additional_data)?,
138
139            // 256-bit nonce
140            (32, 32) => {
141                let mut ciphertext =
142                    gcm_encrypt::<Aes128, U32, U12>(key, plaintext, iv, additional_data)?;
143                ciphertext.truncate(ciphertext.len() - 8);
144                ciphertext
145            },
146            (32, 64) => {
147                let mut ciphertext =
148                    gcm_encrypt::<Aes128, U32, U12>(key, plaintext, iv, additional_data)?;
149                ciphertext.truncate(ciphertext.len() - 4);
150                ciphertext
151            },
152            (32, 96) => gcm_encrypt::<Aes128, U32, U12>(key, plaintext, iv, additional_data)?,
153            (32, 104) => gcm_encrypt::<Aes128, U32, U13>(key, plaintext, iv, additional_data)?,
154            (32, 112) => gcm_encrypt::<Aes128, U32, U14>(key, plaintext, iv, additional_data)?,
155            (32, 120) => gcm_encrypt::<Aes128, U32, U15>(key, plaintext, iv, additional_data)?,
156            (32, 128) => gcm_encrypt::<Aes128, U32, U16>(key, plaintext, iv, additional_data)?,
157            _ => {
158                return Err(Error::Operation(Some(format!(
159                    "Unsupported iv size ({}-bit) and/or tag length ({}-bit)",
160                    iv.len() * 8,
161                    tag_length
162                ))));
163            },
164        },
165        Handle::Aes192Key(key) => match (iv.len(), tag_length) {
166            // 96-bit nonce
167            (12, 32) => {
168                let mut ciphertext =
169                    gcm_encrypt::<Aes192, U12, U12>(key, plaintext, iv, additional_data)?;
170                ciphertext.truncate(ciphertext.len() - 8);
171                ciphertext
172            },
173            (12, 64) => {
174                let mut ciphertext =
175                    gcm_encrypt::<Aes192, U12, U12>(key, plaintext, iv, additional_data)?;
176                ciphertext.truncate(ciphertext.len() - 4);
177                ciphertext
178            },
179            (12, 96) => gcm_encrypt::<Aes192, U12, U12>(key, plaintext, iv, additional_data)?,
180            (12, 104) => gcm_encrypt::<Aes192, U12, U13>(key, plaintext, iv, additional_data)?,
181            (12, 112) => gcm_encrypt::<Aes192, U12, U14>(key, plaintext, iv, additional_data)?,
182            (12, 120) => gcm_encrypt::<Aes192, U12, U15>(key, plaintext, iv, additional_data)?,
183            (12, 128) => gcm_encrypt::<Aes192, U12, U16>(key, plaintext, iv, additional_data)?,
184
185            // 128-bit nonce
186            (16, 32) => {
187                let mut ciphertext =
188                    gcm_encrypt::<Aes192, U16, U12>(key, plaintext, iv, additional_data)?;
189                ciphertext.truncate(ciphertext.len() - 8);
190                ciphertext
191            },
192            (16, 64) => {
193                let mut ciphertext =
194                    gcm_encrypt::<Aes192, U16, U12>(key, plaintext, iv, additional_data)?;
195                ciphertext.truncate(ciphertext.len() - 4);
196                ciphertext
197            },
198            (16, 96) => gcm_encrypt::<Aes192, U16, U12>(key, plaintext, iv, additional_data)?,
199            (16, 104) => gcm_encrypt::<Aes192, U16, U13>(key, plaintext, iv, additional_data)?,
200            (16, 112) => gcm_encrypt::<Aes192, U16, U14>(key, plaintext, iv, additional_data)?,
201            (16, 120) => gcm_encrypt::<Aes192, U16, U15>(key, plaintext, iv, additional_data)?,
202            (16, 128) => gcm_encrypt::<Aes192, U16, U16>(key, plaintext, iv, additional_data)?,
203
204            // 256-bit nonce
205            (32, 32) => {
206                let mut ciphertext =
207                    gcm_encrypt::<Aes192, U32, U12>(key, plaintext, iv, additional_data)?;
208                ciphertext.truncate(ciphertext.len() - 8);
209                ciphertext
210            },
211            (32, 64) => {
212                let mut ciphertext =
213                    gcm_encrypt::<Aes192, U32, U12>(key, plaintext, iv, additional_data)?;
214                ciphertext.truncate(ciphertext.len() - 4);
215                ciphertext
216            },
217            (32, 96) => gcm_encrypt::<Aes192, U32, U12>(key, plaintext, iv, additional_data)?,
218            (32, 104) => gcm_encrypt::<Aes192, U32, U13>(key, plaintext, iv, additional_data)?,
219            (32, 112) => gcm_encrypt::<Aes192, U32, U14>(key, plaintext, iv, additional_data)?,
220            (32, 120) => gcm_encrypt::<Aes192, U32, U15>(key, plaintext, iv, additional_data)?,
221            (32, 128) => gcm_encrypt::<Aes192, U32, U16>(key, plaintext, iv, additional_data)?,
222            _ => {
223                return Err(Error::Operation(Some(format!(
224                    "Unsupported iv size ({}-bit) and/or tag length ({}-bit)",
225                    iv.len() * 8,
226                    tag_length
227                ))));
228            },
229        },
230        Handle::Aes256Key(key) => match (iv.len(), tag_length) {
231            // 96-bit nonce
232            (12, 32) => {
233                let mut ciphertext =
234                    gcm_encrypt::<Aes256, U12, U12>(key, plaintext, iv, additional_data)?;
235                ciphertext.truncate(ciphertext.len() - 8);
236                ciphertext
237            },
238            (12, 64) => {
239                let mut ciphertext =
240                    gcm_encrypt::<Aes256, U12, U12>(key, plaintext, iv, additional_data)?;
241                ciphertext.truncate(ciphertext.len() - 4);
242                ciphertext
243            },
244            (12, 96) => gcm_encrypt::<Aes256, U12, U12>(key, plaintext, iv, additional_data)?,
245            (12, 104) => gcm_encrypt::<Aes256, U12, U13>(key, plaintext, iv, additional_data)?,
246            (12, 112) => gcm_encrypt::<Aes256, U12, U14>(key, plaintext, iv, additional_data)?,
247            (12, 120) => gcm_encrypt::<Aes256, U12, U15>(key, plaintext, iv, additional_data)?,
248            (12, 128) => gcm_encrypt::<Aes256, U12, U16>(key, plaintext, iv, additional_data)?,
249
250            // 128-bit nonce
251            (16, 32) => {
252                let mut ciphertext =
253                    gcm_encrypt::<Aes256, U16, U12>(key, plaintext, iv, additional_data)?;
254                ciphertext.truncate(ciphertext.len() - 8);
255                ciphertext
256            },
257            (16, 64) => {
258                let mut ciphertext =
259                    gcm_encrypt::<Aes256, U16, U12>(key, plaintext, iv, additional_data)?;
260                ciphertext.truncate(ciphertext.len() - 4);
261                ciphertext
262            },
263            (16, 96) => gcm_encrypt::<Aes256, U16, U12>(key, plaintext, iv, additional_data)?,
264            (16, 104) => gcm_encrypt::<Aes256, U16, U13>(key, plaintext, iv, additional_data)?,
265            (16, 112) => gcm_encrypt::<Aes256, U16, U14>(key, plaintext, iv, additional_data)?,
266            (16, 120) => gcm_encrypt::<Aes256, U16, U15>(key, plaintext, iv, additional_data)?,
267            (16, 128) => gcm_encrypt::<Aes256, U16, U16>(key, plaintext, iv, additional_data)?,
268
269            // 256-bit nonce
270            (32, 32) => {
271                let mut ciphertext =
272                    gcm_encrypt::<Aes256, U32, U12>(key, plaintext, iv, additional_data)?;
273                ciphertext.truncate(ciphertext.len() - 8);
274                ciphertext
275            },
276            (32, 64) => {
277                let mut ciphertext =
278                    gcm_encrypt::<Aes256, U32, U12>(key, plaintext, iv, additional_data)?;
279                ciphertext.truncate(ciphertext.len() - 4);
280                ciphertext
281            },
282            (32, 96) => gcm_encrypt::<Aes256, U32, U12>(key, plaintext, iv, additional_data)?,
283            (32, 104) => gcm_encrypt::<Aes256, U32, U13>(key, plaintext, iv, additional_data)?,
284            (32, 112) => gcm_encrypt::<Aes256, U32, U14>(key, plaintext, iv, additional_data)?,
285            (32, 120) => gcm_encrypt::<Aes256, U32, U15>(key, plaintext, iv, additional_data)?,
286            (32, 128) => gcm_encrypt::<Aes256, U32, U16>(key, plaintext, iv, additional_data)?,
287            _ => {
288                return Err(Error::Operation(Some(format!(
289                    "Unsupported iv size ({}-bit) and/or tag length ({}-bit)",
290                    iv.len() * 8,
291                    tag_length
292                ))));
293            },
294        },
295        _ => {
296            return Err(Error::Operation(Some(
297                "The key handle is not representing an AES key".to_string(),
298            )));
299        },
300    };
301
302    // Step 8. Return ciphertext.
303    Ok(ciphertext)
304}
305
306/// Helper for Step 6 and 7 of <https://w3c.github.io/webcrypto/#aes-gcm-operations-encrypt>
307fn gcm_encrypt<Aes, NonceSize, TagSize>(
308    key: &Key<Aes>,
309    plaintext: &[u8],
310    iv: &[u8],
311    additional_data: &[u8],
312) -> Result<Vec<u8>, Error>
313where
314    Aes: BlockCipher + BlockSizeUser<BlockSize = U16> + BlockEncrypt + KeyInit,
315    NonceSize: ArrayLength<u8>,
316    TagSize: aes_gcm::TagSize,
317{
318    let mut ciphertext = plaintext.to_vec();
319
320    let mut cipher = AesGcm::<Aes, NonceSize, TagSize>::new(key);
321    cipher
322        .encrypt_in_place(iv.into(), additional_data, &mut ciphertext)
323        .map_err(|_| {
324            Error::Operation(Some(
325                "AES-GCM failed to perform the Authenticated Encryption Function".to_string(),
326            ))
327        })?;
328
329    Ok(ciphertext)
330}
331
332/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-decrypt>
333pub(crate) fn decrypt(
334    normalized_algorithm: &SubtleAesGcmParams,
335    key: &CryptoKey,
336    ciphertext: &[u8],
337) -> Result<Vec<u8>, Error> {
338    // Step 1.
339    // If the tagLength member of normalizedAlgorithm is not present:
340    //     Let tagLength be 128.
341    // If the tagLength member of normalizedAlgorithm is one of 32, 64, 96, 104, 112, 120 or 128:
342    //     Let tagLength be equal to the tagLength member of normalizedAlgorithm
343    // Otherwise:
344    //     throw an OperationError.
345    let tag_length = match normalized_algorithm.tag_length {
346        None => 128,
347        Some(tag_length) if matches!(tag_length, 32 | 64 | 96 | 104 | 112 | 120 | 128) => {
348            tag_length
349        },
350        _ => {
351            return Err(Error::Operation(Some(
352                "The tagLength member of normalizedAlgorithm is present, \
353                and not one of 32, 64, 96, 104, 112, 120 or 128"
354                    .to_string(),
355            )));
356        },
357    };
358
359    // Step 2. If ciphertext has a length in bits less than tagLength, then throw an
360    // OperationError.
361    if ciphertext.len() * 8 < tag_length as usize {
362        return Err(Error::Operation(Some(
363            "The ciphertext is shorter than the tag".into(),
364        )));
365    }
366
367    // Step 2. If the iv member of normalizedAlgorithm has a length greater than 2^64 - 1 bytes,
368    // then throw an OperationError.
369    if normalized_algorithm.iv.len() > u64::MAX as usize {
370        return Err(Error::Operation(Some(
371            "The iv member of normalizedAlgorithm is too long".into(),
372        )));
373    }
374
375    // Step 3. If the additionalData member of normalizedAlgorithm is present and has a length
376    // greater than 2^64 - 1 bytes, then throw an OperationError.
377    if normalized_algorithm
378        .additional_data
379        .as_ref()
380        .is_some_and(|data| data.len() > u64::MAX as usize)
381    {
382        return Err(Error::Operation(Some(
383            "The additional authentication data is too long".into(),
384        )));
385    }
386
387    // Step 5. Let tag be the last tagLength bits of ciphertext.
388    // Step 6. Let actualCiphertext be the result of removing the last tagLength bits from
389    // ciphertext.
390    // NOTE: aes_gcm splits the ciphertext for us
391
392    // Step 7. Let additionalData be the additionalData member of normalizedAlgorithm if present or
393    // an empty byte sequence otherwise.
394    let additional_data = normalized_algorithm
395        .additional_data
396        .as_deref()
397        .unwrap_or_default();
398
399    // Step 8. Perform the Authenticated Decryption Function described in Section 7.2 of
400    // [NIST-SP800-38D] using AES as the block cipher, the iv member of normalizedAlgorithm as the
401    // IV input parameter, additionalData as the A input parameter, tagLength as the t
402    // pre-requisite, actualCiphertext as the input ciphertext, C and tag as the authentication
403    // tag, T.
404    //
405    // If the result of the algorithm is the indication of inauthenticity, "FAIL":
406    //     throw an OperationError
407    // Otherwise:
408    //     Let plaintext be the output P of the Authenticated Decryption Function.
409    //
410    // NOTE: We currently support:
411    // - IV: 96-bit, 128-bit, 256-bit
412    // - Tag length: 96-bit, 104-bit, 112-bit, 120-bit, 128-bit
413    //
414    // NOTE: We currently do not support 32-bit and 64-bit tag length in decryption since the crate
415    // `aes-gcm` does not support 32-bit and 64-bit tag length.
416    let iv = normalized_algorithm.iv.as_slice();
417    let plaintext = match key.handle() {
418        Handle::Aes128Key(key) => match (iv.len(), tag_length) {
419            // 96-bit nonce
420            (12, 96) => gcm_decrypt::<Aes128, U12, U12>(key, ciphertext, iv, additional_data)?,
421            (12, 104) => gcm_decrypt::<Aes128, U12, U13>(key, ciphertext, iv, additional_data)?,
422            (12, 112) => gcm_decrypt::<Aes128, U12, U14>(key, ciphertext, iv, additional_data)?,
423            (12, 120) => gcm_decrypt::<Aes128, U12, U15>(key, ciphertext, iv, additional_data)?,
424            (12, 128) => gcm_decrypt::<Aes128, U12, U16>(key, ciphertext, iv, additional_data)?,
425
426            // 128-bit nonce
427            (16, 96) => gcm_decrypt::<Aes128, U16, U12>(key, ciphertext, iv, additional_data)?,
428            (16, 104) => gcm_decrypt::<Aes128, U16, U13>(key, ciphertext, iv, additional_data)?,
429            (16, 112) => gcm_decrypt::<Aes128, U16, U14>(key, ciphertext, iv, additional_data)?,
430            (16, 120) => gcm_decrypt::<Aes128, U16, U15>(key, ciphertext, iv, additional_data)?,
431            (16, 128) => gcm_decrypt::<Aes128, U16, U16>(key, ciphertext, iv, additional_data)?,
432
433            // 256-bit nonce
434            (32, 96) => gcm_decrypt::<Aes128, U32, U12>(key, ciphertext, iv, additional_data)?,
435            (32, 104) => gcm_decrypt::<Aes128, U32, U13>(key, ciphertext, iv, additional_data)?,
436            (32, 112) => gcm_decrypt::<Aes128, U32, U14>(key, ciphertext, iv, additional_data)?,
437            (32, 120) => gcm_decrypt::<Aes128, U32, U15>(key, ciphertext, iv, additional_data)?,
438            (32, 128) => gcm_decrypt::<Aes128, U32, U16>(key, ciphertext, iv, additional_data)?,
439
440            _ => {
441                return Err(Error::Operation(Some(format!(
442                    "Unsupported iv size ({}-bit) and/or tag length ({}-bit)",
443                    iv.len() * 8,
444                    tag_length
445                ))));
446            },
447        },
448        Handle::Aes192Key(key) => match (iv.len(), tag_length) {
449            // 96-bit nonce
450            (12, 96) => gcm_decrypt::<Aes192, U12, U12>(key, ciphertext, iv, additional_data)?,
451            (12, 104) => gcm_decrypt::<Aes192, U12, U13>(key, ciphertext, iv, additional_data)?,
452            (12, 112) => gcm_decrypt::<Aes192, U12, U14>(key, ciphertext, iv, additional_data)?,
453            (12, 120) => gcm_decrypt::<Aes192, U12, U15>(key, ciphertext, iv, additional_data)?,
454            (12, 128) => gcm_decrypt::<Aes192, U12, U16>(key, ciphertext, iv, additional_data)?,
455
456            // 128-bit nonce
457            (16, 96) => gcm_decrypt::<Aes192, U16, U12>(key, ciphertext, iv, additional_data)?,
458            (16, 104) => gcm_decrypt::<Aes192, U16, U13>(key, ciphertext, iv, additional_data)?,
459            (16, 112) => gcm_decrypt::<Aes192, U16, U14>(key, ciphertext, iv, additional_data)?,
460            (16, 120) => gcm_decrypt::<Aes192, U16, U15>(key, ciphertext, iv, additional_data)?,
461            (16, 128) => gcm_decrypt::<Aes192, U16, U16>(key, ciphertext, iv, additional_data)?,
462
463            // 256-bit nonce
464            (32, 96) => gcm_decrypt::<Aes192, U32, U12>(key, ciphertext, iv, additional_data)?,
465            (32, 104) => gcm_decrypt::<Aes192, U32, U13>(key, ciphertext, iv, additional_data)?,
466            (32, 112) => gcm_decrypt::<Aes192, U32, U14>(key, ciphertext, iv, additional_data)?,
467            (32, 120) => gcm_decrypt::<Aes192, U32, U15>(key, ciphertext, iv, additional_data)?,
468            (32, 128) => gcm_decrypt::<Aes192, U32, U16>(key, ciphertext, iv, additional_data)?,
469
470            _ => {
471                return Err(Error::Operation(Some(format!(
472                    "Unsupported iv size ({}-bit) and/or tag length ({}-bit)",
473                    iv.len() * 8,
474                    tag_length
475                ))));
476            },
477        },
478        Handle::Aes256Key(key) => match (iv.len(), tag_length) {
479            // 96-bit nonce
480            (12, 96) => gcm_decrypt::<Aes256, U12, U12>(key, ciphertext, iv, additional_data)?,
481            (12, 104) => gcm_decrypt::<Aes256, U12, U13>(key, ciphertext, iv, additional_data)?,
482            (12, 112) => gcm_decrypt::<Aes256, U12, U14>(key, ciphertext, iv, additional_data)?,
483            (12, 120) => gcm_decrypt::<Aes256, U12, U15>(key, ciphertext, iv, additional_data)?,
484            (12, 128) => gcm_decrypt::<Aes256, U12, U16>(key, ciphertext, iv, additional_data)?,
485
486            // 128-bit nonce
487            (16, 96) => gcm_decrypt::<Aes256, U16, U12>(key, ciphertext, iv, additional_data)?,
488            (16, 104) => gcm_decrypt::<Aes256, U16, U13>(key, ciphertext, iv, additional_data)?,
489            (16, 112) => gcm_decrypt::<Aes256, U16, U14>(key, ciphertext, iv, additional_data)?,
490            (16, 120) => gcm_decrypt::<Aes256, U16, U15>(key, ciphertext, iv, additional_data)?,
491            (16, 128) => gcm_decrypt::<Aes256, U16, U16>(key, ciphertext, iv, additional_data)?,
492
493            // 256-bit nonce
494            (32, 96) => gcm_decrypt::<Aes256, U32, U12>(key, ciphertext, iv, additional_data)?,
495            (32, 104) => gcm_decrypt::<Aes256, U32, U13>(key, ciphertext, iv, additional_data)?,
496            (32, 112) => gcm_decrypt::<Aes256, U32, U14>(key, ciphertext, iv, additional_data)?,
497            (32, 120) => gcm_decrypt::<Aes256, U32, U15>(key, ciphertext, iv, additional_data)?,
498            (32, 128) => gcm_decrypt::<Aes256, U32, U16>(key, ciphertext, iv, additional_data)?,
499
500            _ => {
501                return Err(Error::Operation(Some(format!(
502                    "Unsupported iv size ({}-bit) and/or tag length ({}-bit)",
503                    iv.len() * 8,
504                    tag_length
505                ))));
506            },
507        },
508        _ => {
509            return Err(Error::Operation(Some(
510                "The key handle is not representing an AES key".to_string(),
511            )));
512        },
513    };
514
515    // Step 9. Return plaintext.
516    Ok(plaintext)
517}
518
519/// Helper for Step 8 of <https://w3c.github.io/webcrypto/#aes-gcm-operations-decrypt>
520fn gcm_decrypt<Aes, NonceSize, TagSize>(
521    key: &Key<Aes>,
522    ciphertext: &[u8],
523    iv: &[u8],
524    additional_data: &[u8],
525) -> Result<Vec<u8>, Error>
526where
527    Aes: BlockCipher + BlockSizeUser<BlockSize = U16> + BlockEncrypt + KeyInit,
528    NonceSize: ArrayLength<u8>,
529    TagSize: aes_gcm::TagSize,
530{
531    let mut plaintext = ciphertext.to_vec();
532
533    let mut cipher = AesGcm::<Aes, NonceSize, TagSize>::new(key);
534    cipher
535        .decrypt_in_place(iv.into(), additional_data, &mut plaintext)
536        .map_err(|_| {
537            Error::Operation(Some(
538                "AES-GCM failed to perform the Authenticated Decryption Function".to_string(),
539            ))
540        })?;
541
542    Ok(plaintext)
543}
544
545/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-generate-key>
546pub(crate) fn generate_key(
547    cx: &mut JSContext,
548    global: &GlobalScope,
549    normalized_algorithm: &SubtleAesKeyGenParams,
550    extractable: bool,
551    usages: Vec<KeyUsage>,
552) -> Result<DomRoot<CryptoKey>, Error> {
553    aes_common::generate_key(
554        AesAlgorithm::AesGcm,
555        cx,
556        global,
557        normalized_algorithm,
558        extractable,
559        usages,
560    )
561}
562
563/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-import-key>
564pub(crate) fn import_key(
565    cx: &mut JSContext,
566    global: &GlobalScope,
567    format: KeyFormat,
568    key_data: &[u8],
569    extractable: bool,
570    usages: Vec<KeyUsage>,
571) -> Result<DomRoot<CryptoKey>, Error> {
572    aes_common::import_key(
573        AesAlgorithm::AesGcm,
574        cx,
575        global,
576        format,
577        key_data,
578        extractable,
579        usages,
580    )
581}
582
583/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-export-key>
584pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
585    aes_common::export_key(AesAlgorithm::AesGcm, format, key)
586}
587
588/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-get-key-length>
589pub(crate) fn get_key_length(
590    normalized_derived_key_algorithm: &SubtleAesDerivedKeyParams,
591) -> Result<Option<u32>, Error> {
592    aes_common::get_key_length(normalized_derived_key_algorithm)
593}