Skip to main content

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