Skip to main content

script/dom/webcrypto/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::{Aes128, Aes192, Aes256};
6use aes_gcm::aead::common::BlockSizeUser;
7use aes_gcm::aead::common::array::ArraySize;
8use aes_gcm::aead::common::typenum::{U4, U8, U12, U13, U14, U15, U16, U32};
9use aes_gcm::aes::cipher::BlockCipherEncrypt;
10use aes_gcm::{AeadInOut, AesGcm, Key, KeyInit, TagSize as SealedTagSize};
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 only support IV with length 96-bit, 128-bit, or 256-bit.
91    let iv = normalized_algorithm.iv.as_slice();
92    let ciphertext = match key.handle() {
93        Handle::Aes128Key(key) => match (iv.len(), tag_length) {
94            // 96-bit nonce
95            (12, 32) => gcm_encrypt::<Aes128, U12, U4>(key, plaintext, iv, additional_data)?,
96            (12, 64) => gcm_encrypt::<Aes128, U12, U8>(key, plaintext, iv, additional_data)?,
97            (12, 96) => gcm_encrypt::<Aes128, U12, U12>(key, plaintext, iv, additional_data)?,
98            (12, 104) => gcm_encrypt::<Aes128, U12, U13>(key, plaintext, iv, additional_data)?,
99            (12, 112) => gcm_encrypt::<Aes128, U12, U14>(key, plaintext, iv, additional_data)?,
100            (12, 120) => gcm_encrypt::<Aes128, U12, U15>(key, plaintext, iv, additional_data)?,
101            (12, 128) => gcm_encrypt::<Aes128, U12, U16>(key, plaintext, iv, additional_data)?,
102
103            // 128-bit nonce
104            (16, 32) => gcm_encrypt::<Aes128, U16, U4>(key, plaintext, iv, additional_data)?,
105            (16, 64) => gcm_encrypt::<Aes128, U16, U8>(key, plaintext, iv, additional_data)?,
106            (16, 96) => gcm_encrypt::<Aes128, U16, U12>(key, plaintext, iv, additional_data)?,
107            (16, 104) => gcm_encrypt::<Aes128, U16, U13>(key, plaintext, iv, additional_data)?,
108            (16, 112) => gcm_encrypt::<Aes128, U16, U14>(key, plaintext, iv, additional_data)?,
109            (16, 120) => gcm_encrypt::<Aes128, U16, U15>(key, plaintext, iv, additional_data)?,
110            (16, 128) => gcm_encrypt::<Aes128, U16, U16>(key, plaintext, iv, additional_data)?,
111
112            // 256-bit nonce
113            (32, 32) => gcm_encrypt::<Aes128, U32, U4>(key, plaintext, iv, additional_data)?,
114            (32, 64) => gcm_encrypt::<Aes128, U32, U8>(key, plaintext, iv, additional_data)?,
115            (32, 96) => gcm_encrypt::<Aes128, U32, U12>(key, plaintext, iv, additional_data)?,
116            (32, 104) => gcm_encrypt::<Aes128, U32, U13>(key, plaintext, iv, additional_data)?,
117            (32, 112) => gcm_encrypt::<Aes128, U32, U14>(key, plaintext, iv, additional_data)?,
118            (32, 120) => gcm_encrypt::<Aes128, U32, U15>(key, plaintext, iv, additional_data)?,
119            (32, 128) => gcm_encrypt::<Aes128, U32, U16>(key, plaintext, iv, additional_data)?,
120
121            _ => {
122                return Err(Error::Operation(Some(format!(
123                    "Unsupported iv size: {} bytes",
124                    iv.len() * 8,
125                ))));
126            },
127        },
128        Handle::Aes192Key(key) => match (iv.len(), tag_length) {
129            // 96-bit nonce
130            (12, 32) => gcm_encrypt::<Aes192, U12, U4>(key, plaintext, iv, additional_data)?,
131            (12, 64) => gcm_encrypt::<Aes192, U12, U8>(key, plaintext, iv, additional_data)?,
132            (12, 96) => gcm_encrypt::<Aes192, U12, U12>(key, plaintext, iv, additional_data)?,
133            (12, 104) => gcm_encrypt::<Aes192, U12, U13>(key, plaintext, iv, additional_data)?,
134            (12, 112) => gcm_encrypt::<Aes192, U12, U14>(key, plaintext, iv, additional_data)?,
135            (12, 120) => gcm_encrypt::<Aes192, U12, U15>(key, plaintext, iv, additional_data)?,
136            (12, 128) => gcm_encrypt::<Aes192, U12, U16>(key, plaintext, iv, additional_data)?,
137
138            // 128-bit nonce
139            (16, 32) => gcm_encrypt::<Aes192, U16, U4>(key, plaintext, iv, additional_data)?,
140            (16, 64) => gcm_encrypt::<Aes192, U16, U8>(key, plaintext, iv, additional_data)?,
141            (16, 96) => gcm_encrypt::<Aes192, U16, U12>(key, plaintext, iv, additional_data)?,
142            (16, 104) => gcm_encrypt::<Aes192, U16, U13>(key, plaintext, iv, additional_data)?,
143            (16, 112) => gcm_encrypt::<Aes192, U16, U14>(key, plaintext, iv, additional_data)?,
144            (16, 120) => gcm_encrypt::<Aes192, U16, U15>(key, plaintext, iv, additional_data)?,
145            (16, 128) => gcm_encrypt::<Aes192, U16, U16>(key, plaintext, iv, additional_data)?,
146
147            // 256-bit nonce
148            (32, 32) => gcm_encrypt::<Aes192, U32, U4>(key, plaintext, iv, additional_data)?,
149            (32, 64) => gcm_encrypt::<Aes192, U32, U8>(key, plaintext, iv, additional_data)?,
150            (32, 96) => gcm_encrypt::<Aes192, U32, U12>(key, plaintext, iv, additional_data)?,
151            (32, 104) => gcm_encrypt::<Aes192, U32, U13>(key, plaintext, iv, additional_data)?,
152            (32, 112) => gcm_encrypt::<Aes192, U32, U14>(key, plaintext, iv, additional_data)?,
153            (32, 120) => gcm_encrypt::<Aes192, U32, U15>(key, plaintext, iv, additional_data)?,
154            (32, 128) => gcm_encrypt::<Aes192, U32, U16>(key, plaintext, iv, additional_data)?,
155
156            _ => {
157                return Err(Error::Operation(Some(format!(
158                    "Unsupported iv size: {} bytes",
159                    iv.len() * 8,
160                ))));
161            },
162        },
163        Handle::Aes256Key(key) => match (iv.len(), tag_length) {
164            // 96-bit nonce
165            (12, 32) => gcm_encrypt::<Aes256, U12, U4>(key, plaintext, iv, additional_data)?,
166            (12, 64) => gcm_encrypt::<Aes256, U12, U8>(key, plaintext, iv, additional_data)?,
167            (12, 96) => gcm_encrypt::<Aes256, U12, U12>(key, plaintext, iv, additional_data)?,
168            (12, 104) => gcm_encrypt::<Aes256, U12, U13>(key, plaintext, iv, additional_data)?,
169            (12, 112) => gcm_encrypt::<Aes256, U12, U14>(key, plaintext, iv, additional_data)?,
170            (12, 120) => gcm_encrypt::<Aes256, U12, U15>(key, plaintext, iv, additional_data)?,
171            (12, 128) => gcm_encrypt::<Aes256, U12, U16>(key, plaintext, iv, additional_data)?,
172
173            // 128-bit nonce
174            (16, 32) => gcm_encrypt::<Aes256, U16, U4>(key, plaintext, iv, additional_data)?,
175            (16, 64) => gcm_encrypt::<Aes256, U16, U8>(key, plaintext, iv, additional_data)?,
176            (16, 96) => gcm_encrypt::<Aes256, U16, U12>(key, plaintext, iv, additional_data)?,
177            (16, 104) => gcm_encrypt::<Aes256, U16, U13>(key, plaintext, iv, additional_data)?,
178            (16, 112) => gcm_encrypt::<Aes256, U16, U14>(key, plaintext, iv, additional_data)?,
179            (16, 120) => gcm_encrypt::<Aes256, U16, U15>(key, plaintext, iv, additional_data)?,
180            (16, 128) => gcm_encrypt::<Aes256, U16, U16>(key, plaintext, iv, additional_data)?,
181
182            // 256-bit nonce
183            (32, 32) => gcm_encrypt::<Aes256, U32, U4>(key, plaintext, iv, additional_data)?,
184            (32, 64) => gcm_encrypt::<Aes256, U32, U8>(key, plaintext, iv, additional_data)?,
185            (32, 96) => gcm_encrypt::<Aes256, U32, U12>(key, plaintext, iv, additional_data)?,
186            (32, 104) => gcm_encrypt::<Aes256, U32, U13>(key, plaintext, iv, additional_data)?,
187            (32, 112) => gcm_encrypt::<Aes256, U32, U14>(key, plaintext, iv, additional_data)?,
188            (32, 120) => gcm_encrypt::<Aes256, U32, U15>(key, plaintext, iv, additional_data)?,
189            (32, 128) => gcm_encrypt::<Aes256, U32, U16>(key, plaintext, iv, additional_data)?,
190
191            _ => {
192                return Err(Error::Operation(Some(format!(
193                    "Unsupported iv size: {} bytes",
194                    iv.len() * 8,
195                ))));
196            },
197        },
198        _ => {
199            return Err(Error::Operation(Some(
200                "The key handle is not representing an AES key".to_string(),
201            )));
202        },
203    };
204
205    // Step 8. Return ciphertext.
206    Ok(ciphertext)
207}
208
209/// Helper for Step 6 and 7 of <https://w3c.github.io/webcrypto/#aes-gcm-operations-encrypt>
210fn gcm_encrypt<Aes, NonceSize, TagSize>(
211    key: &Key<Aes>,
212    plaintext: &[u8],
213    iv: &[u8],
214    additional_data: &[u8],
215) -> Result<Vec<u8>, Error>
216where
217    Aes: BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt + KeyInit,
218    NonceSize: ArraySize,
219    TagSize: SealedTagSize,
220{
221    let nonce = iv
222        .try_into()
223        .map_err(|_| Error::Operation(Some("Invalid AES-GCM IV".into())))?;
224    let mut ciphertext = plaintext.to_vec();
225    let cipher = AesGcm::<Aes, NonceSize, TagSize>::new(key);
226    cipher
227        .encrypt_in_place(&nonce, additional_data, &mut ciphertext)
228        .map_err(|_| {
229            Error::Operation(Some(
230                "AES-GCM failed to perform the Authenticated Encryption Function".to_string(),
231            ))
232        })?;
233
234    Ok(ciphertext)
235}
236
237/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-decrypt>
238pub(crate) fn decrypt(
239    normalized_algorithm: &SubtleAesGcmParams,
240    key: &CryptoKey,
241    ciphertext: &[u8],
242) -> Result<Vec<u8>, Error> {
243    // Step 1.
244    // If the tagLength member of normalizedAlgorithm is not present:
245    //     Let tagLength be 128.
246    // If the tagLength member of normalizedAlgorithm is one of 32, 64, 96, 104, 112, 120 or 128:
247    //     Let tagLength be equal to the tagLength member of normalizedAlgorithm
248    // Otherwise:
249    //     throw an OperationError.
250    let tag_length = match normalized_algorithm.tag_length {
251        None => 128,
252        Some(tag_length) if matches!(tag_length, 32 | 64 | 96 | 104 | 112 | 120 | 128) => {
253            tag_length
254        },
255        _ => {
256            return Err(Error::Operation(Some(
257                "The tagLength member of normalizedAlgorithm is present, \
258                and not one of 32, 64, 96, 104, 112, 120 or 128"
259                    .to_string(),
260            )));
261        },
262    };
263
264    // Step 2. If ciphertext has a length in bits less than tagLength, then throw an
265    // OperationError.
266    if ciphertext.len() * 8 < tag_length as usize {
267        return Err(Error::Operation(Some(
268            "The ciphertext is shorter than the tag".into(),
269        )));
270    }
271
272    // Step 2. If the iv member of normalizedAlgorithm has a length greater than 2^64 - 1 bytes,
273    // then throw an OperationError.
274    if normalized_algorithm.iv.len() > u64::MAX as usize {
275        return Err(Error::Operation(Some(
276            "The iv member of normalizedAlgorithm is too long".into(),
277        )));
278    }
279
280    // Step 3. If the additionalData member of normalizedAlgorithm is present and has a length
281    // greater than 2^64 - 1 bytes, then throw an OperationError.
282    if normalized_algorithm
283        .additional_data
284        .as_ref()
285        .is_some_and(|data| data.len() > u64::MAX as usize)
286    {
287        return Err(Error::Operation(Some(
288            "The additional authentication data is too long".into(),
289        )));
290    }
291
292    // Step 5. Let tag be the last tagLength bits of ciphertext.
293    // Step 6. Let actualCiphertext be the result of removing the last tagLength bits from
294    // ciphertext.
295    // NOTE: aes_gcm splits the ciphertext for us
296
297    // Step 7. Let additionalData be the additionalData member of normalizedAlgorithm if present or
298    // an empty byte sequence otherwise.
299    let additional_data = normalized_algorithm
300        .additional_data
301        .as_deref()
302        .unwrap_or_default();
303
304    // Step 8. Perform the Authenticated Decryption Function described in Section 7.2 of
305    // [NIST-SP800-38D] using AES as the block cipher, the iv member of normalizedAlgorithm as the
306    // IV input parameter, additionalData as the A input parameter, tagLength as the t
307    // pre-requisite, actualCiphertext as the input ciphertext, C and tag as the authentication
308    // tag, T.
309    //
310    // If the result of the algorithm is the indication of inauthenticity, "FAIL":
311    //     throw an OperationError
312    // Otherwise:
313    //     Let plaintext be the output P of the Authenticated Decryption Function.
314    //
315    // NOTE: We currently only support IV with length 96-bit, 128-bit, or 256-bit.
316    let iv = normalized_algorithm.iv.as_slice();
317    let plaintext = match key.handle() {
318        Handle::Aes128Key(key) => match (iv.len(), tag_length) {
319            // 96-bit nonce
320            (12, 32) => gcm_decrypt::<Aes128, U12, U4>(key, ciphertext, iv, additional_data)?,
321            (12, 64) => gcm_decrypt::<Aes128, U12, U8>(key, ciphertext, iv, additional_data)?,
322            (12, 96) => gcm_decrypt::<Aes128, U12, U12>(key, ciphertext, iv, additional_data)?,
323            (12, 104) => gcm_decrypt::<Aes128, U12, U13>(key, ciphertext, iv, additional_data)?,
324            (12, 112) => gcm_decrypt::<Aes128, U12, U14>(key, ciphertext, iv, additional_data)?,
325            (12, 120) => gcm_decrypt::<Aes128, U12, U15>(key, ciphertext, iv, additional_data)?,
326            (12, 128) => gcm_decrypt::<Aes128, U12, U16>(key, ciphertext, iv, additional_data)?,
327
328            // 128-bit nonce
329            (16, 32) => gcm_decrypt::<Aes128, U16, U4>(key, ciphertext, iv, additional_data)?,
330            (16, 64) => gcm_decrypt::<Aes128, U16, U8>(key, ciphertext, iv, additional_data)?,
331            (16, 96) => gcm_decrypt::<Aes128, U16, U12>(key, ciphertext, iv, additional_data)?,
332            (16, 104) => gcm_decrypt::<Aes128, U16, U13>(key, ciphertext, iv, additional_data)?,
333            (16, 112) => gcm_decrypt::<Aes128, U16, U14>(key, ciphertext, iv, additional_data)?,
334            (16, 120) => gcm_decrypt::<Aes128, U16, U15>(key, ciphertext, iv, additional_data)?,
335            (16, 128) => gcm_decrypt::<Aes128, U16, U16>(key, ciphertext, iv, additional_data)?,
336
337            // 256-bit nonce
338            (32, 32) => gcm_decrypt::<Aes128, U32, U4>(key, ciphertext, iv, additional_data)?,
339            (32, 64) => gcm_decrypt::<Aes128, U32, U8>(key, ciphertext, iv, additional_data)?,
340            (32, 96) => gcm_decrypt::<Aes128, U32, U12>(key, ciphertext, iv, additional_data)?,
341            (32, 104) => gcm_decrypt::<Aes128, U32, U13>(key, ciphertext, iv, additional_data)?,
342            (32, 112) => gcm_decrypt::<Aes128, U32, U14>(key, ciphertext, iv, additional_data)?,
343            (32, 120) => gcm_decrypt::<Aes128, U32, U15>(key, ciphertext, iv, additional_data)?,
344            (32, 128) => gcm_decrypt::<Aes128, U32, U16>(key, ciphertext, iv, additional_data)?,
345
346            _ => {
347                return Err(Error::Operation(Some(format!(
348                    "Unsupported iv size: {} bytes",
349                    iv.len() * 8,
350                ))));
351            },
352        },
353        Handle::Aes192Key(key) => match (iv.len(), tag_length) {
354            // 96-bit nonce
355            (12, 32) => gcm_decrypt::<Aes192, U12, U4>(key, ciphertext, iv, additional_data)?,
356            (12, 64) => gcm_decrypt::<Aes192, U12, U8>(key, ciphertext, iv, additional_data)?,
357            (12, 96) => gcm_decrypt::<Aes192, U12, U12>(key, ciphertext, iv, additional_data)?,
358            (12, 104) => gcm_decrypt::<Aes192, U12, U13>(key, ciphertext, iv, additional_data)?,
359            (12, 112) => gcm_decrypt::<Aes192, U12, U14>(key, ciphertext, iv, additional_data)?,
360            (12, 120) => gcm_decrypt::<Aes192, U12, U15>(key, ciphertext, iv, additional_data)?,
361            (12, 128) => gcm_decrypt::<Aes192, U12, U16>(key, ciphertext, iv, additional_data)?,
362
363            // 128-bit nonce
364            (16, 32) => gcm_decrypt::<Aes192, U16, U4>(key, ciphertext, iv, additional_data)?,
365            (16, 64) => gcm_decrypt::<Aes192, U16, U8>(key, ciphertext, iv, additional_data)?,
366            (16, 96) => gcm_decrypt::<Aes192, U16, U12>(key, ciphertext, iv, additional_data)?,
367            (16, 104) => gcm_decrypt::<Aes192, U16, U13>(key, ciphertext, iv, additional_data)?,
368            (16, 112) => gcm_decrypt::<Aes192, U16, U14>(key, ciphertext, iv, additional_data)?,
369            (16, 120) => gcm_decrypt::<Aes192, U16, U15>(key, ciphertext, iv, additional_data)?,
370            (16, 128) => gcm_decrypt::<Aes192, U16, U16>(key, ciphertext, iv, additional_data)?,
371
372            // 256-bit nonce
373            (32, 32) => gcm_decrypt::<Aes192, U32, U4>(key, ciphertext, iv, additional_data)?,
374            (32, 64) => gcm_decrypt::<Aes192, U32, U8>(key, ciphertext, iv, additional_data)?,
375            (32, 96) => gcm_decrypt::<Aes192, U32, U12>(key, ciphertext, iv, additional_data)?,
376            (32, 104) => gcm_decrypt::<Aes192, U32, U13>(key, ciphertext, iv, additional_data)?,
377            (32, 112) => gcm_decrypt::<Aes192, U32, U14>(key, ciphertext, iv, additional_data)?,
378            (32, 120) => gcm_decrypt::<Aes192, U32, U15>(key, ciphertext, iv, additional_data)?,
379            (32, 128) => gcm_decrypt::<Aes192, U32, U16>(key, ciphertext, iv, additional_data)?,
380
381            _ => {
382                return Err(Error::Operation(Some(format!(
383                    "Unsupported iv size: {} bytes",
384                    iv.len() * 8,
385                ))));
386            },
387        },
388        Handle::Aes256Key(key) => match (iv.len(), tag_length) {
389            // 96-bit nonce
390            (12, 32) => gcm_decrypt::<Aes256, U12, U4>(key, ciphertext, iv, additional_data)?,
391            (12, 64) => gcm_decrypt::<Aes256, U12, U8>(key, ciphertext, iv, additional_data)?,
392            (12, 96) => gcm_decrypt::<Aes256, U12, U12>(key, ciphertext, iv, additional_data)?,
393            (12, 104) => gcm_decrypt::<Aes256, U12, U13>(key, ciphertext, iv, additional_data)?,
394            (12, 112) => gcm_decrypt::<Aes256, U12, U14>(key, ciphertext, iv, additional_data)?,
395            (12, 120) => gcm_decrypt::<Aes256, U12, U15>(key, ciphertext, iv, additional_data)?,
396            (12, 128) => gcm_decrypt::<Aes256, U12, U16>(key, ciphertext, iv, additional_data)?,
397
398            // 128-bit nonce
399            (16, 32) => gcm_decrypt::<Aes256, U16, U4>(key, ciphertext, iv, additional_data)?,
400            (16, 64) => gcm_decrypt::<Aes256, U16, U8>(key, ciphertext, iv, additional_data)?,
401            (16, 96) => gcm_decrypt::<Aes256, U16, U12>(key, ciphertext, iv, additional_data)?,
402            (16, 104) => gcm_decrypt::<Aes256, U16, U13>(key, ciphertext, iv, additional_data)?,
403            (16, 112) => gcm_decrypt::<Aes256, U16, U14>(key, ciphertext, iv, additional_data)?,
404            (16, 120) => gcm_decrypt::<Aes256, U16, U15>(key, ciphertext, iv, additional_data)?,
405            (16, 128) => gcm_decrypt::<Aes256, U16, U16>(key, ciphertext, iv, additional_data)?,
406
407            // 256-bit nonce
408            (32, 32) => gcm_decrypt::<Aes256, U32, U4>(key, ciphertext, iv, additional_data)?,
409            (32, 64) => gcm_decrypt::<Aes256, U32, U8>(key, ciphertext, iv, additional_data)?,
410            (32, 96) => gcm_decrypt::<Aes256, U32, U12>(key, ciphertext, iv, additional_data)?,
411            (32, 104) => gcm_decrypt::<Aes256, U32, U13>(key, ciphertext, iv, additional_data)?,
412            (32, 112) => gcm_decrypt::<Aes256, U32, U14>(key, ciphertext, iv, additional_data)?,
413            (32, 120) => gcm_decrypt::<Aes256, U32, U15>(key, ciphertext, iv, additional_data)?,
414            (32, 128) => gcm_decrypt::<Aes256, U32, U16>(key, ciphertext, iv, additional_data)?,
415
416            _ => {
417                return Err(Error::Operation(Some(format!(
418                    "Unsupported iv size: {} bytes",
419                    iv.len() * 8,
420                ))));
421            },
422        },
423        _ => {
424            return Err(Error::Operation(Some(
425                "The key handle is not representing an AES key".to_string(),
426            )));
427        },
428    };
429
430    // Step 9. Return plaintext.
431    Ok(plaintext)
432}
433
434/// Helper for Step 8 of <https://w3c.github.io/webcrypto/#aes-gcm-operations-decrypt>
435fn gcm_decrypt<Aes, NonceSize, TagSize>(
436    key: &Key<Aes>,
437    ciphertext: &[u8],
438    iv: &[u8],
439    additional_data: &[u8],
440) -> Result<Vec<u8>, Error>
441where
442    Aes: BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt + KeyInit,
443    NonceSize: ArraySize,
444    TagSize: SealedTagSize,
445{
446    let nonce = iv
447        .try_into()
448        .map_err(|_| Error::Operation(Some("Invalid AES-GCM IV".into())))?;
449    let mut plaintext = ciphertext.to_vec();
450    let cipher = AesGcm::<Aes, NonceSize, TagSize>::new(key);
451    cipher
452        .decrypt_in_place(&nonce, additional_data, &mut plaintext)
453        .map_err(|_| {
454            Error::Operation(Some(
455                "AES-GCM failed to perform the Authenticated Decryption Function".to_string(),
456            ))
457        })?;
458
459    Ok(plaintext)
460}
461
462/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-generate-key>
463pub(crate) fn generate_key(
464    cx: &mut JSContext,
465    global: &GlobalScope,
466    normalized_algorithm: &SubtleAesKeyGenParams,
467    extractable: bool,
468    usages: Vec<KeyUsage>,
469) -> Result<DomRoot<CryptoKey>, Error> {
470    aes_common::generate_key(
471        AesAlgorithm::AesGcm,
472        cx,
473        global,
474        normalized_algorithm,
475        extractable,
476        usages,
477    )
478}
479
480/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-import-key>
481pub(crate) fn import_key(
482    cx: &mut JSContext,
483    global: &GlobalScope,
484    format: KeyFormat,
485    key_data: &[u8],
486    extractable: bool,
487    usages: Vec<KeyUsage>,
488) -> Result<DomRoot<CryptoKey>, Error> {
489    aes_common::import_key(
490        AesAlgorithm::AesGcm,
491        cx,
492        global,
493        format,
494        key_data,
495        extractable,
496        usages,
497    )
498}
499
500/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-export-key>
501pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
502    aes_common::export_key(AesAlgorithm::AesGcm, format, key)
503}
504
505/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-get-key-length>
506pub(crate) fn get_key_length(
507    normalized_derived_key_algorithm: &SubtleAesDerivedKeyParams,
508) -> Result<Option<u32>, Error> {
509    aes_common::get_key_length(normalized_derived_key_algorithm)
510}