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