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}