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::common::{Generate, Key};
6use aes::{Aes128, Aes192, Aes256};
7use js::context::JSContext;
8use zeroize::Zeroizing;
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 => Handle::Aes128Key(Key::<Aes128>::try_generate().map_err(|_| {
91 Error::Operation(Some(
92 "Failed to generate AES key with length 128 bits".into(),
93 ))
94 })?),
95 192 => Handle::Aes192Key(Key::<Aes192>::try_generate().map_err(|_| {
96 Error::Operation(Some(
97 "Failed to generate AES key with length 192 bits".into(),
98 ))
99 })?),
100 256 => Handle::Aes256Key(Key::<Aes256>::try_generate().map_err(|_| {
101 Error::Operation(Some(
102 "Failed to generate AES key with length 256 bits".into(),
103 ))
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: Zeroizing<Vec<u8>>;
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().into();
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().into();
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(
466 Key::<Aes128>::try_from(data.as_slice())
467 .map_err(|_| Error::Operation(Some("Invalid AES-128 key".into())))?,
468 ),
469 24 => Handle::Aes192Key(
470 Key::<Aes192>::try_from(data.as_slice())
471 .map_err(|_| Error::Operation(Some("Invalid AES-192 key".into())))?,
472 ),
473 32 => Handle::Aes256Key(
474 Key::<Aes256>::try_from(data.as_slice())
475 .map_err(|_| Error::Operation(Some("Invalid AES-256 key".into())))?,
476 ),
477 _ => {
478 return Err(Error::Data(Some(
479 "The length in bits of data is not 128, 192 or 256".to_string(),
480 )));
481 },
482 };
483 let algorithm = SubtleAesKeyAlgorithm {
484 name: match &aes_algorithm {
485 AesAlgorithm::AesCtr => {
486 // Step 6. Set the name attribute of algorithm to "AES-CTR".
487 CryptoAlgorithm::AesCtr
488 },
489 AesAlgorithm::AesCbc => {
490 // Step 6. Set the name attribute of algorithm to "AES-CBC".
491 CryptoAlgorithm::AesCbc
492 },
493 AesAlgorithm::AesGcm => {
494 // Step 6. Set the name attribute of algorithm to "AES-GCM".
495 CryptoAlgorithm::AesGcm
496 },
497 AesAlgorithm::AesKw => {
498 // Step 6. Set the name attribute of algorithm to "AES-KW".
499 CryptoAlgorithm::AesKw
500 },
501 AesAlgorithm::AesOcb => {
502 // Step 6. Set the name attribute of algorithm to "AES-OCB".
503 CryptoAlgorithm::AesOcb
504 },
505 },
506 length: data.len() as u16 * 8,
507 };
508 let key = CryptoKey::new(
509 cx,
510 global,
511 KeyType::Secret,
512 extractable,
513 KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm),
514 usages,
515 handle,
516 );
517
518 // Step 9. Return key.
519 Ok(key)
520}
521
522/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-export-key>
523/// <https://w3c.github.io/webcrypto/#aes-cbc-operations-export-key>
524/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-export-key>
525/// <https://w3c.github.io/webcrypto/#aes-kw-operations-export-key>
526/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-export-key>
527pub(crate) fn export_key(
528 aes_algorithm: AesAlgorithm,
529 format: KeyFormat,
530 key: &CryptoKey,
531) -> Result<ExportedKey, Error> {
532 // Step 1. If the underlying cryptographic key material represented by the [[handle]] internal
533 // slot of key cannot be accessed, then throw an OperationError.
534
535 // Step 2.
536 let result = match format {
537 // If format is "raw": (Only applied to AES-CTR, AES-CBC, AES-GCM, AES-KW)
538 KeyFormat::Raw
539 if matches!(
540 aes_algorithm,
541 AesAlgorithm::AesCtr |
542 AesAlgorithm::AesCbc |
543 AesAlgorithm::AesGcm |
544 AesAlgorithm::AesKw
545 ) =>
546 {
547 // Step 2.1. Let data be a byte sequence containing the raw octets of the key
548 // represented by [[handle]] internal slot of key.
549 let data = match key.handle() {
550 Handle::Aes128Key(key) => key.to_vec(),
551 Handle::Aes192Key(key) => key.to_vec(),
552 Handle::Aes256Key(key) => key.to_vec(),
553 _ => {
554 return Err(Error::Operation(Some(
555 "The key handle is not representing an AES key".to_string(),
556 )));
557 },
558 };
559
560 // Step 2.2. Let result be data.
561 ExportedKey::new_bytes(data)
562 },
563 // If format is "raw-secret":
564 KeyFormat::Raw_secret => {
565 // Step 2.1. Let data be a byte sequence containing the raw octets of the key
566 // represented by [[handle]] internal slot of key.
567 let data = match key.handle() {
568 Handle::Aes128Key(key) => key.to_vec(),
569 Handle::Aes192Key(key) => key.to_vec(),
570 Handle::Aes256Key(key) => key.to_vec(),
571 _ => {
572 return Err(Error::Operation(Some(
573 "The key handle is not representing an AES key".to_string(),
574 )));
575 },
576 };
577
578 // Step 2.2. Let result be data.
579 ExportedKey::new_bytes(data)
580 },
581 // If format is "jwk":
582 KeyFormat::Jwk => {
583 // Step 2.1. Let jwk be a new JsonWebKey dictionary.
584 let mut jwk = JsonWebKey::default();
585
586 // Step 2.2. Set the kty attribute of jwk to the string "oct".
587 jwk.kty = Some(DOMString::from("oct"));
588
589 // Step 2.3. Set the k attribute of jwk to be a string containing the raw octets of the
590 // key represented by [[handle]] internal slot of key, encoded according to Section 6.4
591 // of JSON Web Algorithms [JWA].
592 let key_bytes = match key.handle() {
593 Handle::Aes128Key(key) => key.as_slice(),
594 Handle::Aes192Key(key) => key.as_slice(),
595 Handle::Aes256Key(key) => key.as_slice(),
596 _ => {
597 return Err(Error::Operation(Some(
598 "The key handle is not representing an AES key".to_string(),
599 )));
600 },
601 };
602 jwk.encode_string_field(JwkStringField::K, key_bytes);
603
604 match aes_algorithm {
605 AesAlgorithm::AesCtr => {
606 // Step 2.4.
607 // If the length attribute of key is 128:
608 // Set the alg attribute of jwk to the string "A128CTR".
609 // If the length attribute of key is 192:
610 // Set the alg attribute of jwk to the string "A192CTR".
611 // If the length attribute of key is 256:
612 // Set the alg attribute of jwk to the string "A256CTR".
613 let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
614 else {
615 return Err(Error::Operation(Some(
616 "The key is not an AES-CTR key".to_string(),
617 )));
618 };
619 let alg = match algorithm.length {
620 128 => "A128CTR",
621 192 => "A192CTR",
622 256 => "A256CTR",
623 _ => return Err(Error::Operation(Some(
624 "The length attribute of the [[algorithm]] internal slot of key is not \
625 128, 192 or 256".to_string(),
626 )))
627 };
628 jwk.alg = Some(DOMString::from(alg));
629 },
630 AesAlgorithm::AesCbc => {
631 // Step 2.4.
632 // If the length attribute of key is 128:
633 // Set the alg attribute of jwk to the string "A128CBC".
634 // If the length attribute of key is 192:
635 // Set the alg attribute of jwk to the string "A192CBC".
636 // If the length attribute of key is 256:
637 // Set the alg attribute of jwk to the string "A256CBC".
638 let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
639 else {
640 return Err(Error::Operation(Some(
641 "The key is not an AES-CBC key".to_string(),
642 )));
643 };
644 let alg = match algorithm.length {
645 128 => "A128CBC",
646 192 => "A192CBC",
647 256 => "A256CBC",
648 _ => return Err(Error::Operation(Some(
649 "The length attribute of the [[algorithm]] internal slot of key is not \
650 128, 192 or 256".to_string(),
651 )))
652 };
653 jwk.alg = Some(DOMString::from(alg));
654 },
655 AesAlgorithm::AesGcm => {
656 // Step 2.4.
657 // If the length attribute of key is 128:
658 // Set the alg attribute of jwk to the string "A128GCM".
659 // If the length attribute of key is 192:
660 // Set the alg attribute of jwk to the string "A192GCM".
661 // If the length attribute of key is 256:
662 // Set the alg attribute of jwk to the string "A256GCM".
663 let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
664 else {
665 return Err(Error::Operation(Some(
666 "The key is not an AES-GCM key".to_string(),
667 )));
668 };
669 let alg = match algorithm.length {
670 128 => "A128GCM",
671 192 => "A192GCM",
672 256 => "A256GCM",
673 _ => return Err(Error::Operation(Some(
674 "The length attribute of the [[algorithm]] internal slot of key is not \
675 128, 192 or 256".to_string(),
676 )))
677 };
678 jwk.alg = Some(DOMString::from(alg));
679 },
680 AesAlgorithm::AesKw => {
681 // Step 2.4.
682 // If the length attribute of key is 128:
683 // Set the alg attribute of jwk to the string "A128KW".
684 // If the length attribute of key is 192:
685 // Set the alg attribute of jwk to the string "A192KW".
686 // If the length attribute of key is 256:
687 // Set the alg attribute of jwk to the string "A256KW".
688 let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
689 else {
690 return Err(Error::Operation(Some(
691 "The key is not an AES-KW key".to_string(),
692 )));
693 };
694 let alg = match algorithm.length {
695 128 => "A128KW",
696 192 => "A192KW",
697 256 => "A256KW",
698 _ => return Err(Error::Operation(Some(
699 "The length attribute of the [[algorithm]] internal slot of key is not \
700 128, 192 or 256".to_string(),
701 )))
702 };
703 jwk.alg = Some(DOMString::from(alg));
704 },
705 AesAlgorithm::AesOcb => {
706 // Step 2.4.
707 // If the length attribute of key is 128:
708 // Set the alg attribute of jwk to the string "A128OCB".
709 // If the length attribute of key is 192:
710 // Set the alg attribute of jwk to the string "A192OCB".
711 // If the length attribute of key is 256:
712 // Set the alg attribute of jwk to the string "A256OCB".
713 let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
714 else {
715 return Err(Error::Operation(Some(
716 "The key is not an AES-OCB key".to_string(),
717 )));
718 };
719 let alg = match algorithm.length {
720 128 => "A128OCB",
721 192 => "A192OCB",
722 256 => "A256OCB",
723 _ => return Err(Error::Operation(Some(
724 "The length attribute of the [[algorithm]] internal slot of key is not \
725 128, 192 or 256".to_string(),
726 )))
727 };
728 jwk.alg = Some(DOMString::from(alg));
729 },
730 }
731
732 // Step 2.5. Set the key_ops attribute of jwk to equal the usages attribute of key.
733 jwk.set_key_ops(&key.usages());
734
735 // Step 2.6. Set the ext attribute of jwk to equal the [[extractable]] internal slot of
736 // key.
737 jwk.ext = Some(key.Extractable());
738
739 // Step 2.7. Let result be jwk.
740 ExportedKey::new_jwk(jwk)
741 },
742 _ => {
743 // throw a NotSupportedError.
744 return Err(Error::NotSupported(Some(
745 "Unsupported import key format for AES key".to_string(),
746 )));
747 },
748 };
749
750 // Step 3. Return result.
751 Ok(result)
752}
753
754/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-get-key-length>
755/// <https://w3c.github.io/webcrypto/#aes-cbc-operations-get-key-length>
756/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-get-key-length>
757/// <https://w3c.github.io/webcrypto/#aes-kw-operations-get-key-length>
758/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-get-key-length>
759pub(crate) fn get_key_length(
760 normalized_derived_key_algorithm: &SubtleAesDerivedKeyParams,
761) -> Result<Option<u32>, Error> {
762 // Step 1. If the length member of normalizedDerivedKeyAlgorithm is not 128, 192 or 256, then
763 // throw an OperationError.
764 if !matches!(normalized_derived_key_algorithm.length, 128 | 192 | 256) {
765 return Err(Error::Operation(Some(
766 "The length member of normalizedDerivedKeyAlgorithm is not 128, 192 or 256".to_string(),
767 )));
768 }
769
770 // Step 2. Return the length member of normalizedDerivedKeyAlgorithm.
771 Ok(Some(normalized_derived_key_algorithm.length as u32))
772}