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