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