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