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