Skip to main content

script/dom/webcrypto/subtlecrypto/
aes_common.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::common::{Generate, Key};
6use aes::{Aes128, Aes192, Aes256};
7use js::context::JSContext;
8use zeroize::Zeroizing;
9
10use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
11    CryptoKeyMethods, KeyType, KeyUsage,
12};
13use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{JsonWebKey, KeyFormat};
14use crate::dom::bindings::error::Error;
15use crate::dom::bindings::root::DomRoot;
16use crate::dom::bindings::str::DOMString;
17use crate::dom::cryptokey::{CryptoKey, Handle};
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::subtlecrypto::{
20    CryptoAlgorithm, ExportedKey, JsonWebKeyExt, JwkStringField, KeyAlgorithmAndDerivatives,
21    SubtleAesDerivedKeyParams, SubtleAesKeyAlgorithm, SubtleAesKeyGenParams,
22};
23
24#[expect(clippy::enum_variant_names)]
25pub(crate) enum AesAlgorithm {
26    AesCtr,
27    AesCbc,
28    AesGcm,
29    AesKw,
30    AesOcb,
31}
32
33/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-generate-key>
34/// <https://w3c.github.io/webcrypto/#aes-cbc-operations-generate-key>
35/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-generate-key>
36/// <https://w3c.github.io/webcrypto/#aes-kw-operations-generate-key>
37/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-generate-key>
38///
39/// The step order in the specification of AES-OCB is slightly different, but it is equivalent to
40/// this implementation.
41pub(crate) fn generate_key(
42    aes_algorithm: AesAlgorithm,
43    cx: &mut JSContext,
44    global: &GlobalScope,
45    normalized_algorithm: &SubtleAesKeyGenParams,
46    extractable: bool,
47    usages: Vec<KeyUsage>,
48) -> Result<DomRoot<CryptoKey>, Error> {
49    match aes_algorithm {
50        AesAlgorithm::AesCtr |
51        AesAlgorithm::AesCbc |
52        AesAlgorithm::AesGcm |
53        AesAlgorithm::AesOcb => {
54            // Step 1. If usages contains any entry which is not one of "encrypt", "decrypt",
55            // "wrapKey" or "unwrapKey", then throw a SyntaxError.
56            if usages.iter().any(|usage| {
57                !matches!(
58                    usage,
59                    KeyUsage::Encrypt | KeyUsage::Decrypt | KeyUsage::WrapKey | KeyUsage::UnwrapKey
60                )
61            }) {
62                return Err(Error::Syntax(Some(
63                    "Usages contains an entry which is not one of \"encrypt\", \"decrypt\", \
64                    \"wrapKey\" or \"unwrapKey\""
65                        .to_string(),
66                )));
67            }
68        },
69        AesAlgorithm::AesKw => {
70            // Step 1. If usages contains any entry which is not one of "wrapKey" or "unwrapKey",
71            // then throw a SyntaxError.
72            if usages
73                .iter()
74                .any(|usage| !matches!(usage, KeyUsage::WrapKey | KeyUsage::UnwrapKey))
75            {
76                return Err(Error::Syntax(Some(
77                    "Usages contains an entry which is not one of \"wrapKey\" or \"unwrapKey\""
78                        .to_string(),
79                )));
80            }
81        },
82    }
83
84    // Step 2. If the length member of normalizedAlgorithm is not equal to one of 128, 192 or 256,
85    // then throw an OperationError.
86    // Step 3. Generate an AES key of length equal to the length member of normalizedAlgorithm.
87    // Step 4. If the key generation step fails, then throw an OperationError.
88    let handle =
89        match normalized_algorithm.length {
90            128 => Handle::Aes128Key(Key::<Aes128>::try_generate().map_err(|_| {
91                Error::Operation(Some(
92                    "Failed to generate AES key with length 128 bits".into(),
93                ))
94            })?),
95            192 => Handle::Aes192Key(Key::<Aes192>::try_generate().map_err(|_| {
96                Error::Operation(Some(
97                    "Failed to generate AES key with length 192 bits".into(),
98                ))
99            })?),
100            256 => Handle::Aes256Key(Key::<Aes256>::try_generate().map_err(|_| {
101                Error::Operation(Some(
102                    "Failed to generate AES key with length 256 bits".into(),
103                ))
104            })?),
105            _ => return Err(Error::Operation(Some(
106                "The length member of normalizedAlgorithm is not equal to one of 128, 192 or 256"
107                    .to_string(),
108            ))),
109        };
110
111    // Step 5. Let key be a new CryptoKey object representing the generated AES key.
112    // Step 6. Let algorithm be a new AesKeyAlgorithm.
113    // Step 8. Set the length attribute of algorithm to equal the length member of
114    // normalizedAlgorithm.
115    // Step 9. Set the [[type]] internal slot of key to "secret".
116    // Step 10. Set the [[algorithm]] internal slot of key to algorithm.
117    // Step 11. Set the [[extractable]] internal slot of key to be extractable.
118    // Step 12. Set the [[usages]] internal slot of key to be usages.
119    let algorithm_name = match aes_algorithm {
120        AesAlgorithm::AesCtr => {
121            // Step 7. Set the name attribute of algorithm to "AES-CTR".
122            CryptoAlgorithm::AesCtr
123        },
124        AesAlgorithm::AesCbc => {
125            // Step 7. Set the name attribute of algorithm to "AES-CBC".
126            CryptoAlgorithm::AesCbc
127        },
128        AesAlgorithm::AesGcm => {
129            // Step 7. Set the name attribute of algorithm to "AES-GCM".
130            CryptoAlgorithm::AesGcm
131        },
132        AesAlgorithm::AesKw => {
133            // Step 7. Set the name attribute of algorithm to "AES-KW".
134            CryptoAlgorithm::AesKw
135        },
136        AesAlgorithm::AesOcb => {
137            // Step 7. Set the name attribute of algorithm to "AES-OCB".
138            CryptoAlgorithm::AesOcb
139        },
140    };
141    let algorithm = SubtleAesKeyAlgorithm {
142        name: algorithm_name,
143        length: normalized_algorithm.length,
144    };
145    let key = CryptoKey::new(
146        cx,
147        global,
148        KeyType::Secret,
149        extractable,
150        KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm),
151        usages,
152        handle,
153    );
154
155    // Step 13. Return key.
156    Ok(key)
157}
158
159/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-import-key>
160/// <https://w3c.github.io/webcrypto/#aes-cbc-operations-import-key>
161/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-import-key>
162/// <https://w3c.github.io/webcrypto/#aes-kw-operations-import-key>
163/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-import-key>
164///
165/// The specification of AES-OCB has one more step at the beginning of the operation:
166///
167/// > Let keyData be the key data to be imported.
168///
169/// As it is simply used to name the variable, it is safe to omit it in the implementation below to
170/// align with the specification of other AES algorithms.
171pub(crate) fn import_key(
172    aes_algorithm: AesAlgorithm,
173    cx: &mut JSContext,
174    global: &GlobalScope,
175    format: KeyFormat,
176    key_data: &[u8],
177    extractable: bool,
178    usages: Vec<KeyUsage>,
179) -> Result<DomRoot<CryptoKey>, Error> {
180    match &aes_algorithm {
181        AesAlgorithm::AesCtr |
182        AesAlgorithm::AesCbc |
183        AesAlgorithm::AesGcm |
184        AesAlgorithm::AesOcb => {
185            // Step 1. If usages contains an entry which is not one of "encrypt", "decrypt",
186            // "wrapKey" or "unwrapKey", then throw a SyntaxError.
187            if usages.iter().any(|usage| {
188                !matches!(
189                    usage,
190                    KeyUsage::Encrypt | KeyUsage::Decrypt | KeyUsage::WrapKey | KeyUsage::UnwrapKey
191                )
192            }) {
193                return Err(Error::Syntax(Some(
194                    "Usages contains an entry which is not one of \"encrypt\", \"decrypt\", \
195                    \"wrapKey\"  or \"unwrapKey\""
196                        .to_string(),
197                )));
198            }
199        },
200        AesAlgorithm::AesKw => {
201            // Step 1. If usages contains an entry which is not one of "wrapKey" or "unwrapKey",
202            // then throw a SyntaxError.
203            if usages
204                .iter()
205                .any(|usage| !matches!(usage, KeyUsage::WrapKey | KeyUsage::UnwrapKey))
206            {
207                return Err(Error::Syntax(Some(
208                    "Usages contains an entry which is not one of \"wrapKey\"  or \"unwrapKey\""
209                        .to_string(),
210                )));
211            }
212        },
213    }
214
215    // Step 2.
216    let data: Zeroizing<Vec<u8>>;
217    match format {
218        // If format is "raw": (Only applied to AES-CTR, AES-CBC, AES-GCM, AES-KW)
219        KeyFormat::Raw
220            if matches!(
221                aes_algorithm,
222                AesAlgorithm::AesCtr |
223                    AesAlgorithm::AesCbc |
224                    AesAlgorithm::AesGcm |
225                    AesAlgorithm::AesKw
226            ) =>
227        {
228            // Step 2.1. Let data be keyData.
229            data = key_data.to_vec().into();
230
231            // Step 2.2. If the length in bits of data is not 128, 192 or 256 then throw a
232            // DataError.
233            if !matches!(data.len(), 16 | 24 | 32) {
234                return Err(Error::Data(Some(
235                    "The length in bits of data is not 128, 192 or 256".to_string(),
236                )));
237            }
238        },
239        // If format is "raw-secret":
240        KeyFormat::Raw_secret => {
241            // Step 2.1. Let data be keyData.
242            data = key_data.to_vec().into();
243
244            // Step 2.2. If the length in bits of data is not 128, 192 or 256 then throw a
245            // DataError.
246            if !matches!(data.len(), 16 | 24 | 32) {
247                return Err(Error::Data(Some(
248                    "The length in bits of key is not 128, 192 or 256".to_string(),
249                )));
250            }
251        },
252        // If format is "jwk":
253        KeyFormat::Jwk => {
254            // Step 2.1.
255            // If keyData is a JsonWebKey dictionary:
256            //     Let jwk equal keyData.
257            // Otherwise:
258            //     Throw a DataError.
259            let jwk = JsonWebKey::parse(cx, key_data)?;
260
261            // Step 2.2. If the kty field of jwk is not "oct", then throw a DataError.
262            if jwk.kty.as_ref().is_none_or(|kty| kty != "oct") {
263                return Err(Error::Data(Some(
264                    "The kty field of jwk is not \"oct\"".to_string(),
265                )));
266            }
267
268            // Step 2.3. If jwk does not meet the requirements of Section 6.4 of JSON Web
269            // Algorithms [JWA], then throw a DataError.
270            // Step 2.4. Let data be the byte sequence obtained by decoding the k field of jwk.
271            data = jwk.decode_required_string_field(JwkStringField::K)?;
272
273            match aes_algorithm {
274                AesAlgorithm::AesCtr => {
275                    // Step 2.5.
276                    // If data has length 128 bits:
277                    //     If the alg field of jwk is present, and is not "A128CTR", then throw a
278                    //     DataError.
279                    // If data has length 192 bits:
280                    //     If the alg field of jwk is present, and is not "A192CTR", then throw a
281                    //     DataError.
282                    // If data has length 256 bits:
283                    //     If the alg field of jwk is present, and is not "A256CTR", then throw a
284                    //     DataError.
285                    // Otherwise:
286                    //     throw a DataError.
287                    let expected_alg = match data.len() {
288                        16 => "A128CTR",
289                        24 => "A192CTR",
290                        32 => "A256CTR",
291                        _ => {
292                            return Err(Error::Data(Some(
293                                "The length in bits of data is not 128, 192 or 256".to_string(),
294                            )));
295                        },
296                    };
297                    if jwk.alg.as_ref().is_none_or(|alg| alg != expected_alg) {
298                        return Err(Error::Data(Some(format!(
299                            "The alg field of jwk is present, and is not {}",
300                            expected_alg
301                        ))));
302                    }
303                },
304                AesAlgorithm::AesCbc => {
305                    // Step 2.5.
306                    // If data has length 128 bits:
307                    //     If the alg field of jwk is present, and is not "A128CBC", then throw a
308                    //     DataError.
309                    // If data has length 192 bits:
310                    //     If the alg field of jwk is present, and is not "A192CBC", then throw a
311                    //     DataError.
312                    // If data has length 256 bits:
313                    //     If the alg field of jwk is present, and is not "A256CBC", then throw a
314                    //     DataError.
315                    // Otherwise:
316                    //     throw a DataError.
317                    let expected_alg = match data.len() {
318                        16 => "A128CBC",
319                        24 => "A192CBC",
320                        32 => "A256CBC",
321                        _ => {
322                            return Err(Error::Data(Some(
323                                "The length in bits of data is not 128, 192 or 256".to_string(),
324                            )));
325                        },
326                    };
327                    if jwk.alg.as_ref().is_none_or(|alg| alg != expected_alg) {
328                        return Err(Error::Data(Some(format!(
329                            "The alg field of jwk is present, and is not {}",
330                            expected_alg
331                        ))));
332                    }
333                },
334                AesAlgorithm::AesGcm => {
335                    // Step 2.5.
336                    // If data has length 128 bits:
337                    //     If the alg field of jwk is present, and is not "A128GCM", then throw a
338                    //     DataError.
339                    // If data has length 192 bits:
340                    //     If the alg field of jwk is present, and is not "A192GCM", then throw a
341                    //     DataError.
342                    // If data has length 256 bits:
343                    //     If the alg field of jwk is present, and is not "A256GCM", then throw a
344                    //     DataError.
345                    // Otherwise:
346                    //     throw a DataError.
347                    let expected_alg = match data.len() {
348                        16 => "A128GCM",
349                        24 => "A192GCM",
350                        32 => "A256GCM",
351                        _ => {
352                            return Err(Error::Data(Some(
353                                "The length in bits of data is not 128, 192 or 256".to_string(),
354                            )));
355                        },
356                    };
357                    if jwk.alg.as_ref().is_none_or(|alg| alg != expected_alg) {
358                        return Err(Error::Data(Some(format!(
359                            "The alg field of jwk is present, and is not {}",
360                            expected_alg
361                        ))));
362                    }
363                },
364                AesAlgorithm::AesKw => {
365                    // Step 2.5.
366                    // If data has length 128 bits:
367                    //     If the alg field of jwk is present, and is not "A128KW", then throw a
368                    //     DataError.
369                    // If data has length 192 bits:
370                    //     If the alg field of jwk is present, and is not "A192KW", then throw a
371                    //     DataError.
372                    // If data has length 256 bits:
373                    //     If the alg field of jwk is present, and is not "A256KW", then throw a
374                    //     DataError.
375                    // Otherwise:
376                    //     throw a DataError.
377                    let expected_alg = match data.len() {
378                        16 => "A128KW",
379                        24 => "A192KW",
380                        32 => "A256KW",
381                        _ => {
382                            return Err(Error::Data(Some(
383                                "The length in bits of data is not 128, 192 or 256".to_string(),
384                            )));
385                        },
386                    };
387                    if jwk.alg.as_ref().is_none_or(|alg| alg != expected_alg) {
388                        return Err(Error::Data(Some(format!(
389                            "The alg field of jwk is present, and is not {}",
390                            expected_alg
391                        ))));
392                    }
393                },
394                AesAlgorithm::AesOcb => {
395                    // Step 2.5.
396                    // If data has length 128 bits:
397                    //     If the alg field of jwk is present, and is not "A128OCB", then throw a
398                    //     DataError.
399                    // If data has length 192 bits:
400                    //     If the alg field of jwk is present, and is not "A192OCB", then throw a
401                    //     DataError.
402                    // If data has length 256 bits:
403                    //     If the alg field of jwk is present, and is not "A256OCB", then throw a
404                    //     DataError.
405                    // Otherwise:
406                    //     throw a DataError.
407                    let expected_alg = match data.len() {
408                        16 => "A128OCB",
409                        24 => "A192OCB",
410                        32 => "A256OCB",
411                        _ => {
412                            return Err(Error::Data(Some(
413                                "The length in bits of key is not 128, 192 or 256".to_string(),
414                            )));
415                        },
416                    };
417                    if jwk.alg.as_ref().is_none_or(|alg| alg != expected_alg) {
418                        return Err(Error::Data(Some(format!(
419                            "The alg field of jwk is present, and is not {}",
420                            expected_alg
421                        ))));
422                    }
423                },
424            }
425
426            // Step 2.6. If usages is non-empty and the use field of jwk is present and is not
427            // "enc", then throw a DataError.
428            if !usages.is_empty() && jwk.use_.as_ref().is_some_and(|use_| use_ != "enc") {
429                return Err(Error::Data(Some(
430                    "Usages is non-empty and the use field of jwk is present and is not \"enc\""
431                        .to_string(),
432                )));
433            }
434
435            // Step 2.7. If the key_ops field of jwk is present, and is invalid according to the
436            // requirements of JSON Web Key [JWK] or does not contain all of the specified usages
437            // values, then throw a DataError.
438            jwk.check_key_ops(&usages)?;
439
440            // Step 2.8. If the ext field of jwk is present and has the value false and extractable
441            // is true, then throw a DataError.
442            if jwk.ext.is_some_and(|ext| !ext) && extractable {
443                return Err(Error::Data(Some(
444                    "The ext field of jwk is present and has the value false and \
445                    extractable is true"
446                        .to_string(),
447                )));
448            }
449        },
450        // Otherwise:
451        _ => {
452            // throw a NotSupportedError.
453            return Err(Error::NotSupported(Some(
454                "Unupported import key format for AES key".to_string(),
455            )));
456        },
457    }
458
459    // Step 3. Let key be a new CryptoKey object representing an AES key with value data.
460    // Step 4. Set the [[type]] internal slot of key to "secret".
461    // Step 5. Let algorithm be a new AesKeyAlgorithm.
462    // Step 7. Set the length attribute of algorithm to the length, in bits, of data.
463    // Step 8. Set the [[algorithm]] internal slot of key to algorithm.
464    let handle = match data.len() {
465        16 => Handle::Aes128Key(
466            Key::<Aes128>::try_from(data.as_slice())
467                .map_err(|_| Error::Operation(Some("Invalid AES-128 key".into())))?,
468        ),
469        24 => Handle::Aes192Key(
470            Key::<Aes192>::try_from(data.as_slice())
471                .map_err(|_| Error::Operation(Some("Invalid AES-192 key".into())))?,
472        ),
473        32 => Handle::Aes256Key(
474            Key::<Aes256>::try_from(data.as_slice())
475                .map_err(|_| Error::Operation(Some("Invalid AES-256 key".into())))?,
476        ),
477        _ => {
478            return Err(Error::Data(Some(
479                "The length in bits of data is not 128, 192 or 256".to_string(),
480            )));
481        },
482    };
483    let algorithm = SubtleAesKeyAlgorithm {
484        name: match &aes_algorithm {
485            AesAlgorithm::AesCtr => {
486                // Step 6. Set the name attribute of algorithm to "AES-CTR".
487                CryptoAlgorithm::AesCtr
488            },
489            AesAlgorithm::AesCbc => {
490                // Step 6. Set the name attribute of algorithm to "AES-CBC".
491                CryptoAlgorithm::AesCbc
492            },
493            AesAlgorithm::AesGcm => {
494                // Step 6. Set the name attribute of algorithm to "AES-GCM".
495                CryptoAlgorithm::AesGcm
496            },
497            AesAlgorithm::AesKw => {
498                // Step 6. Set the name attribute of algorithm to "AES-KW".
499                CryptoAlgorithm::AesKw
500            },
501            AesAlgorithm::AesOcb => {
502                // Step 6. Set the name attribute of algorithm to "AES-OCB".
503                CryptoAlgorithm::AesOcb
504            },
505        },
506        length: data.len() as u16 * 8,
507    };
508    let key = CryptoKey::new(
509        cx,
510        global,
511        KeyType::Secret,
512        extractable,
513        KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm),
514        usages,
515        handle,
516    );
517
518    // Step 9. Return key.
519    Ok(key)
520}
521
522/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-export-key>
523/// <https://w3c.github.io/webcrypto/#aes-cbc-operations-export-key>
524/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-export-key>
525/// <https://w3c.github.io/webcrypto/#aes-kw-operations-export-key>
526/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-export-key>
527pub(crate) fn export_key(
528    aes_algorithm: AesAlgorithm,
529    format: KeyFormat,
530    key: &CryptoKey,
531) -> Result<ExportedKey, Error> {
532    // Step 1. If the underlying cryptographic key material represented by the [[handle]] internal
533    // slot of key cannot be accessed, then throw an OperationError.
534
535    // Step 2.
536    let result = match format {
537        // If format is "raw": (Only applied to AES-CTR, AES-CBC, AES-GCM, AES-KW)
538        KeyFormat::Raw
539            if matches!(
540                aes_algorithm,
541                AesAlgorithm::AesCtr |
542                    AesAlgorithm::AesCbc |
543                    AesAlgorithm::AesGcm |
544                    AesAlgorithm::AesKw
545            ) =>
546        {
547            // Step 2.1. Let data be a byte sequence containing the raw octets of the key
548            // represented by [[handle]] internal slot of key.
549            let data = match key.handle() {
550                Handle::Aes128Key(key) => key.to_vec(),
551                Handle::Aes192Key(key) => key.to_vec(),
552                Handle::Aes256Key(key) => key.to_vec(),
553                _ => {
554                    return Err(Error::Operation(Some(
555                        "The key handle is not representing an AES key".to_string(),
556                    )));
557                },
558            };
559
560            // Step 2.2. Let result be data.
561            ExportedKey::new_bytes(data)
562        },
563        // If format is "raw-secret":
564        KeyFormat::Raw_secret => {
565            // Step 2.1. Let data be a byte sequence containing the raw octets of the key
566            // represented by [[handle]] internal slot of key.
567            let data = match key.handle() {
568                Handle::Aes128Key(key) => key.to_vec(),
569                Handle::Aes192Key(key) => key.to_vec(),
570                Handle::Aes256Key(key) => key.to_vec(),
571                _ => {
572                    return Err(Error::Operation(Some(
573                        "The key handle is not representing an AES key".to_string(),
574                    )));
575                },
576            };
577
578            // Step 2.2. Let result be data.
579            ExportedKey::new_bytes(data)
580        },
581        // If format is "jwk":
582        KeyFormat::Jwk => {
583            // Step 2.1. Let jwk be a new JsonWebKey dictionary.
584            let mut jwk = JsonWebKey::default();
585
586            // Step 2.2. Set the kty attribute of jwk to the string "oct".
587            jwk.kty = Some(DOMString::from("oct"));
588
589            // Step 2.3. Set the k attribute of jwk to be a string containing the raw octets of the
590            // key represented by [[handle]] internal slot of key, encoded according to Section 6.4
591            // of JSON Web Algorithms [JWA].
592            let key_bytes = match key.handle() {
593                Handle::Aes128Key(key) => key.as_slice(),
594                Handle::Aes192Key(key) => key.as_slice(),
595                Handle::Aes256Key(key) => key.as_slice(),
596                _ => {
597                    return Err(Error::Operation(Some(
598                        "The key handle is not representing an AES key".to_string(),
599                    )));
600                },
601            };
602            jwk.encode_string_field(JwkStringField::K, key_bytes);
603
604            match aes_algorithm {
605                AesAlgorithm::AesCtr => {
606                    // Step 2.4.
607                    // If the length attribute of key is 128:
608                    //     Set the alg attribute of jwk to the string "A128CTR".
609                    // If the length attribute of key is 192:
610                    //     Set the alg attribute of jwk to the string "A192CTR".
611                    // If the length attribute of key is 256:
612                    //     Set the alg attribute of jwk to the string "A256CTR".
613                    let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
614                    else {
615                        return Err(Error::Operation(Some(
616                            "The key is not an AES-CTR key".to_string(),
617                        )));
618                    };
619                    let alg = match algorithm.length {
620                        128 => "A128CTR",
621                        192 => "A192CTR",
622                        256 => "A256CTR",
623                        _ => return Err(Error::Operation(Some(
624                            "The length attribute of the [[algorithm]] internal slot of key is not \
625                            128, 192 or 256".to_string(),
626                        )))
627                    };
628                    jwk.alg = Some(DOMString::from(alg));
629                },
630                AesAlgorithm::AesCbc => {
631                    // Step 2.4.
632                    // If the length attribute of key is 128:
633                    //     Set the alg attribute of jwk to the string "A128CBC".
634                    // If the length attribute of key is 192:
635                    //     Set the alg attribute of jwk to the string "A192CBC".
636                    // If the length attribute of key is 256:
637                    //     Set the alg attribute of jwk to the string "A256CBC".
638                    let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
639                    else {
640                        return Err(Error::Operation(Some(
641                            "The key is not an AES-CBC key".to_string(),
642                        )));
643                    };
644                    let alg = match algorithm.length {
645                        128 => "A128CBC",
646                        192 => "A192CBC",
647                        256 => "A256CBC",
648                        _ => return Err(Error::Operation(Some(
649                            "The length attribute of the [[algorithm]] internal slot of key is not \
650                            128, 192 or 256".to_string(),
651                        )))
652                    };
653                    jwk.alg = Some(DOMString::from(alg));
654                },
655                AesAlgorithm::AesGcm => {
656                    // Step 2.4.
657                    // If the length attribute of key is 128:
658                    //     Set the alg attribute of jwk to the string "A128GCM".
659                    // If the length attribute of key is 192:
660                    //     Set the alg attribute of jwk to the string "A192GCM".
661                    // If the length attribute of key is 256:
662                    //     Set the alg attribute of jwk to the string "A256GCM".
663                    let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
664                    else {
665                        return Err(Error::Operation(Some(
666                            "The key is not an AES-GCM key".to_string(),
667                        )));
668                    };
669                    let alg = match algorithm.length {
670                        128 => "A128GCM",
671                        192 => "A192GCM",
672                        256 => "A256GCM",
673                        _ => return Err(Error::Operation(Some(
674                            "The length attribute of the [[algorithm]] internal slot of key is not \
675                            128, 192 or 256".to_string(),
676                        )))
677                    };
678                    jwk.alg = Some(DOMString::from(alg));
679                },
680                AesAlgorithm::AesKw => {
681                    // Step 2.4.
682                    // If the length attribute of key is 128:
683                    //     Set the alg attribute of jwk to the string "A128KW".
684                    // If the length attribute of key is 192:
685                    //     Set the alg attribute of jwk to the string "A192KW".
686                    // If the length attribute of key is 256:
687                    //     Set the alg attribute of jwk to the string "A256KW".
688                    let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
689                    else {
690                        return Err(Error::Operation(Some(
691                            "The key is not an AES-KW key".to_string(),
692                        )));
693                    };
694                    let alg = match algorithm.length {
695                        128 => "A128KW",
696                        192 => "A192KW",
697                        256 => "A256KW",
698                        _ => return Err(Error::Operation(Some(
699                            "The length attribute of the [[algorithm]] internal slot of key is not \
700                            128, 192 or 256".to_string(),
701                        )))
702                    };
703                    jwk.alg = Some(DOMString::from(alg));
704                },
705                AesAlgorithm::AesOcb => {
706                    // Step 2.4.
707                    // If the length attribute of key is 128:
708                    //     Set the alg attribute of jwk to the string "A128OCB".
709                    // If the length attribute of key is 192:
710                    //     Set the alg attribute of jwk to the string "A192OCB".
711                    // If the length attribute of key is 256:
712                    //     Set the alg attribute of jwk to the string "A256OCB".
713                    let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
714                    else {
715                        return Err(Error::Operation(Some(
716                            "The key is not an AES-OCB key".to_string(),
717                        )));
718                    };
719                    let alg = match algorithm.length {
720                        128 => "A128OCB",
721                        192 => "A192OCB",
722                        256 => "A256OCB",
723                        _ => return Err(Error::Operation(Some(
724                            "The length attribute of the [[algorithm]] internal slot of key is not \
725                            128, 192 or 256".to_string(),
726                        )))
727                    };
728                    jwk.alg = Some(DOMString::from(alg));
729                },
730            }
731
732            // Step 2.5. Set the key_ops attribute of jwk to equal the usages attribute of key.
733            jwk.set_key_ops(&key.usages());
734
735            // Step 2.6. Set the ext attribute of jwk to equal the [[extractable]] internal slot of
736            // key.
737            jwk.ext = Some(key.Extractable());
738
739            // Step 2.7. Let result be jwk.
740            ExportedKey::new_jwk(jwk)
741        },
742        _ => {
743            // throw a NotSupportedError.
744            return Err(Error::NotSupported(Some(
745                "Unsupported import key format for AES key".to_string(),
746            )));
747        },
748    };
749
750    // Step 3. Return result.
751    Ok(result)
752}
753
754/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-get-key-length>
755/// <https://w3c.github.io/webcrypto/#aes-cbc-operations-get-key-length>
756/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-get-key-length>
757/// <https://w3c.github.io/webcrypto/#aes-kw-operations-get-key-length>
758/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-get-key-length>
759pub(crate) fn get_key_length(
760    normalized_derived_key_algorithm: &SubtleAesDerivedKeyParams,
761) -> Result<Option<u32>, Error> {
762    // Step 1. If the length member of normalizedDerivedKeyAlgorithm is not 128, 192 or 256, then
763    // throw an OperationError.
764    if !matches!(normalized_derived_key_algorithm.length, 128 | 192 | 256) {
765        return Err(Error::Operation(Some(
766            "The length member of normalizedDerivedKeyAlgorithm is not 128, 192 or 256".to_string(),
767        )));
768    }
769
770    // Step 2. Return the length member of normalizedDerivedKeyAlgorithm.
771    Ok(Some(normalized_derived_key_algorithm.length as u32))
772}