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