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 pkcs8::rand_core::{OsRng, RngCore};
8
9use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
10 CryptoKeyMethods, KeyType, KeyUsage,
11};
12use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{JsonWebKey, KeyFormat};
13use crate::dom::bindings::error::Error;
14use crate::dom::bindings::root::DomRoot;
15use crate::dom::bindings::str::DOMString;
16use crate::dom::cryptokey::{CryptoKey, Handle};
17use crate::dom::globalscope::GlobalScope;
18use crate::dom::subtlecrypto::{
19 ExportedKey, JsonWebKeyExt, JwkStringField, KeyAlgorithmAndDerivatives,
20 SubtleAesDerivedKeyParams, SubtleAesKeyAlgorithm, SubtleAesKeyGenParams,
21};
22use crate::script_runtime::CanGc;
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>
38pub(crate) fn generate_key(
39 aes_algorithm: AesAlgorithm,
40 global: &GlobalScope,
41 normalized_algorithm: &SubtleAesKeyGenParams,
42 extractable: bool,
43 usages: Vec<KeyUsage>,
44 can_gc: CanGc,
45) -> Result<DomRoot<CryptoKey>, Error> {
46 match aes_algorithm {
47 AesAlgorithm::AesCtr |
48 AesAlgorithm::AesCbc |
49 AesAlgorithm::AesGcm |
50 AesAlgorithm::AesOcb => {
51 // Step 1. If usages contains any entry which is not one of "encrypt", "decrypt",
52 // "wrapKey" or "unwrapKey", then throw a SyntaxError.
53 if usages.iter().any(|usage| {
54 !matches!(
55 usage,
56 KeyUsage::Encrypt | KeyUsage::Decrypt | KeyUsage::WrapKey | KeyUsage::UnwrapKey
57 )
58 }) {
59 return Err(Error::Syntax(Some(
60 "Usages contains an entry which is not one of \"encrypt\", \"decrypt\", \
61 \"wrapKey\" or \"unwrapKey\""
62 .to_string(),
63 )));
64 }
65 },
66 AesAlgorithm::AesKw => {
67 // Step 1. If usages contains any entry which is not one of "wrapKey" or "unwrapKey",
68 // then throw a SyntaxError.
69 if usages
70 .iter()
71 .any(|usage| !matches!(usage, KeyUsage::WrapKey | KeyUsage::UnwrapKey))
72 {
73 return Err(Error::Syntax(Some(
74 "Usages contains an entry which is not one of \"wrapKey\" or \"unwrapKey\""
75 .to_string(),
76 )));
77 }
78 },
79 }
80
81 // Step 2. If the length member of normalizedAlgorithm is not equal to one of 128, 192 or 256,
82 // then throw an OperationError.
83 // Step 3. Generate an AES key of length equal to the length member of normalizedAlgorithm.
84 // Step 4. If the key generation step fails, then throw an OperationError.
85 let handle =
86 match normalized_algorithm.length {
87 128 => {
88 let mut key_bytes = vec![0; 16];
89 OsRng.fill_bytes(&mut key_bytes);
90 Handle::Aes128Key(Key::<Aes128>::clone_from_slice(&key_bytes))
91 },
92 192 => {
93 let mut key_bytes = vec![0; 24];
94 OsRng.fill_bytes(&mut key_bytes);
95 Handle::Aes192Key(Key::<Aes192>::clone_from_slice(&key_bytes))
96 },
97 256 => {
98 let mut key_bytes = vec![0; 32];
99 OsRng.fill_bytes(&mut key_bytes);
100 Handle::Aes256Key(Key::<Aes256>::clone_from_slice(&key_bytes))
101 },
102 _ => return Err(Error::Operation(Some(
103 "The length member of normalizedAlgorithm is not equal to one of 128, 192 or 256"
104 .to_string(),
105 ))),
106 };
107
108 // Step 5. Let key be a new CryptoKey object representing the generated AES key.
109 // Step 6. Set the [[type]] internal slot of key to "secret".
110 // Step 7. Let algorithm be a new AesKeyAlgorithm.
111 // Step 9. Set the length attribute of algorithm to equal the length member of
112 // normalizedAlgorithm.
113 // Step 10. Set the [[algorithm]] internal slot of key to algorithm.
114 // Step 11. Set the [[extractable]] internal slot of key to be extractable.
115 // Step 12. Set the [[usages]] internal slot of key to be usages.
116 let algorithm_name = match aes_algorithm {
117 AesAlgorithm::AesCtr => {
118 // Step 8. Set the name attribute of algorithm to "AES-CTR".
119 "AES-CTR"
120 },
121 AesAlgorithm::AesCbc => {
122 // Step 8. Set the name attribute of algorithm to "AES-CBC".
123 "AES-CBC"
124 },
125 AesAlgorithm::AesGcm => {
126 // Step 8. Set the name attribute of algorithm to "AES-GCM".
127 "AES-GCM"
128 },
129 AesAlgorithm::AesKw => {
130 // Step 8. Set the name attribute of algorithm to "AES-KW".
131 "AES-KW"
132 },
133 AesAlgorithm::AesOcb => {
134 // Step 8. Set the name attribute of algorithm to "AES-OCB".
135 "AES-OCB"
136 },
137 };
138 let algorithm = SubtleAesKeyAlgorithm {
139 name: algorithm_name.to_string(),
140 length: normalized_algorithm.length,
141 };
142 let key = CryptoKey::new(
143 global,
144 KeyType::Secret,
145 extractable,
146 KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm),
147 usages,
148 handle,
149 can_gc,
150 );
151
152 // Step 13. Return key.
153 Ok(key)
154}
155
156/// Step 3 of <https://w3c.github.io/webcrypto/#aes-ctr-operations-import-key>
157/// Step 3 of <https://w3c.github.io/webcrypto/#aes-cbc-operations-import-key>
158/// Step 3 of <https://w3c.github.io/webcrypto/#aes-gcm-operations-import-key>
159/// Step 3 of <https://w3c.github.io/webcrypto/#aes-kw-operations-import-key>
160/// Step 3 of <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-import-key>
161pub(crate) fn import_key_from_key_data(
162 aes_algorithm: AesAlgorithm,
163 format: KeyFormat,
164 key_data: &[u8],
165 extractable: bool,
166 usages: &[KeyUsage],
167) -> Result<Vec<u8>, Error> {
168 let data;
169 match format {
170 // If format is "raw": (Only applied to AES-CTR, AES-CBC, AES-GCM, AES-KW)
171 KeyFormat::Raw
172 if matches!(
173 aes_algorithm,
174 AesAlgorithm::AesCtr |
175 AesAlgorithm::AesCbc |
176 AesAlgorithm::AesGcm |
177 AesAlgorithm::AesKw
178 ) =>
179 {
180 // Step 1. Let data be keyData.
181 data = key_data.to_vec();
182
183 // Step 2. If the length in bits of data is not 128, 192 or 256 then throw a DataError.
184 if !matches!(data.len(), 16 | 24 | 32) {
185 return Err(Error::Data(Some(
186 "The length in bits of data is not 128, 192 or 256".to_string(),
187 )));
188 }
189 },
190 // If format is "raw-secret":
191 KeyFormat::Raw_secret => {
192 // Step 1. Let data be keyData.
193 data = key_data.to_vec();
194
195 // Step 2. If the length in bits of data is not 128, 192 or 256 then throw a DataError.
196 if !matches!(data.len(), 16 | 24 | 32) {
197 return Err(Error::Data(Some(
198 "The length in bits of key is not 128, 192 or 256".to_string(),
199 )));
200 }
201 },
202 // If format is "jwk":
203 KeyFormat::Jwk => {
204 // Step 1.
205 // If keyData is a JsonWebKey dictionary:
206 // Let jwk equal keyData.
207 // Otherwise:
208 // Throw a DataError.
209 let jwk = JsonWebKey::parse(GlobalScope::get_cx(), key_data)?;
210
211 // Step 3.2. If the kty field of jwk is not "oct", then throw a DataError.
212 if jwk.kty.as_ref().is_none_or(|kty| kty != "oct") {
213 return Err(Error::Data(Some(
214 "The kty field of jwk is not \"oct\"".to_string(),
215 )));
216 }
217
218 // Step 3. If jwk does not meet the requirements of Section 6.4 of JSON Web Algorithms
219 // [JWA], then throw a DataError.
220 // Step 4. Let data be the byte sequence obtained by decoding the k field of jwk.
221 data = jwk.decode_required_string_field(JwkStringField::K)?;
222
223 match aes_algorithm {
224 AesAlgorithm::AesCtr => {
225 // Step 5.
226 // If data has length 128 bits:
227 // If the alg field of jwk is present, and is not "A128CTR", then throw a
228 // DataError.
229 // If data has length 192 bits:
230 // If the alg field of jwk is present, and is not "A192CTR", then throw a
231 // DataError.
232 // If data has length 256 bits:
233 // If the alg field of jwk is present, and is not "A256CTR", then throw a
234 // DataError.
235 // Otherwise:
236 // throw a DataError.
237 let expected_alg = match data.len() {
238 16 => "A128CTR",
239 24 => "A192CTR",
240 32 => "A256CTR",
241 _ => {
242 return Err(Error::Data(Some(
243 "The length in bits of data is not 128, 192 or 256".to_string(),
244 )));
245 },
246 };
247 if jwk.alg.as_ref().is_none_or(|alg| alg != expected_alg) {
248 return Err(Error::Data(Some(format!(
249 "The alg field of jwk is present, and is not {}",
250 expected_alg
251 ))));
252 }
253 },
254 AesAlgorithm::AesCbc => {
255 // Step 5.
256 // If data has length 128 bits:
257 // If the alg field of jwk is present, and is not "A128CBC", then throw a
258 // DataError.
259 // If data has length 192 bits:
260 // If the alg field of jwk is present, and is not "A192CBC", then throw a
261 // DataError.
262 // If data has length 256 bits:
263 // If the alg field of jwk is present, and is not "A256CBC", then throw a
264 // DataError.
265 // Otherwise:
266 // throw a DataError.
267 let expected_alg = match data.len() {
268 16 => "A128CBC",
269 24 => "A192CBC",
270 32 => "A256CBC",
271 _ => {
272 return Err(Error::Data(Some(
273 "The length in bits of data is not 128, 192 or 256".to_string(),
274 )));
275 },
276 };
277 if jwk.alg.as_ref().is_none_or(|alg| alg != expected_alg) {
278 return Err(Error::Data(Some(format!(
279 "The alg field of jwk is present, and is not {}",
280 expected_alg
281 ))));
282 }
283 },
284 AesAlgorithm::AesGcm => {
285 // Step 5.
286 // If data has length 128 bits:
287 // If the alg field of jwk is present, and is not "A128GCM", then throw a
288 // DataError.
289 // If data has length 192 bits:
290 // If the alg field of jwk is present, and is not "A192GCM", then throw a
291 // DataError.
292 // If data has length 256 bits:
293 // If the alg field of jwk is present, and is not "A256GCM", then throw a
294 // DataError.
295 // Otherwise:
296 // throw a DataError.
297 let expected_alg = match data.len() {
298 16 => "A128GCM",
299 24 => "A192GCM",
300 32 => "A256GCM",
301 _ => {
302 return Err(Error::Data(Some(
303 "The length in bits of data is not 128, 192 or 256".to_string(),
304 )));
305 },
306 };
307 if jwk.alg.as_ref().is_none_or(|alg| alg != expected_alg) {
308 return Err(Error::Data(Some(format!(
309 "The alg field of jwk is present, and is not {}",
310 expected_alg
311 ))));
312 }
313 },
314 AesAlgorithm::AesKw => {
315 // Step 5.
316 // If data has length 128 bits:
317 // If the alg field of jwk is present, and is not "A128KW", then throw a
318 // DataError.
319 // If data has length 192 bits:
320 // If the alg field of jwk is present, and is not "A192KW", then throw a
321 // DataError.
322 // If data has length 256 bits:
323 // If the alg field of jwk is present, and is not "A256KW", then throw a
324 // DataError.
325 // Otherwise:
326 // throw a DataError.
327 let expected_alg = match data.len() {
328 16 => "A128KW",
329 24 => "A192KW",
330 32 => "A256KW",
331 _ => {
332 return Err(Error::Data(Some(
333 "The length in bits of data is not 128, 192 or 256".to_string(),
334 )));
335 },
336 };
337 if jwk.alg.as_ref().is_none_or(|alg| alg != expected_alg) {
338 return Err(Error::Data(Some(format!(
339 "The alg field of jwk is present, and is not {}",
340 expected_alg
341 ))));
342 }
343 },
344 AesAlgorithm::AesOcb => {
345 // Step 5.
346 // If data has length 128 bits:
347 // If the alg field of jwk is present, and is not "A128OCB", then throw a
348 // DataError.
349 // If data has length 192 bits:
350 // If the alg field of jwk is present, and is not "A192OCB", then throw a
351 // DataError.
352 // If data has length 256 bits:
353 // If the alg field of jwk is present, and is not "A256OCB", then throw a
354 // DataError.
355 // Otherwise:
356 // throw a DataError.
357 let expected_alg = match data.len() {
358 16 => "A128OCB",
359 24 => "A192OCB",
360 32 => "A256OCB",
361 _ => {
362 return Err(Error::Data(Some(
363 "The length in bits of key is not 128, 192 or 256".to_string(),
364 )));
365 },
366 };
367 if jwk.alg.as_ref().is_none_or(|alg| alg != expected_alg) {
368 return Err(Error::Data(Some(format!(
369 "The alg field of jwk is present, and is not {}",
370 expected_alg
371 ))));
372 }
373 },
374 }
375
376 // Step 6. If usages is non-empty and the use field of jwk is present and is not "enc",
377 // then throw a DataError.
378 if !usages.is_empty() && jwk.use_.as_ref().is_some_and(|use_| use_ != "enc") {
379 return Err(Error::Data(Some(
380 "Usages is non-empty and the use field of jwk is present and is not \"enc\""
381 .to_string(),
382 )));
383 }
384
385 // Step 7. If the key_ops field of jwk is present, and is invalid according to the
386 // requirements of JSON Web Key [JWK] or does not contain all of the specified usages
387 // values, then throw a DataError.
388 jwk.check_key_ops(usages)?;
389
390 // Step 8. If the ext field of jwk is present and has the value false and extractable
391 // is true, then throw a DataError.
392 if jwk.ext.is_some_and(|ext| !ext) && extractable {
393 return Err(Error::Data(Some(
394 "The ext field of jwk is present and has the value false and \
395 extractable is true"
396 .to_string(),
397 )));
398 }
399 },
400 // Otherwise:
401 _ => {
402 // throw a NotSupportedError.
403 return Err(Error::NotSupported(Some(
404 "Unupported import key format for AES key".to_string(),
405 )));
406 },
407 }
408
409 Ok(data)
410}
411
412/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-export-key>
413/// <https://w3c.github.io/webcrypto/#aes-cbc-operations-export-key>
414/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-export-key>
415/// <https://w3c.github.io/webcrypto/#aes-kw-operations-export-key>
416/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-export-key>
417pub(crate) fn export_key(
418 aes_algorithm: AesAlgorithm,
419 format: KeyFormat,
420 key: &CryptoKey,
421) -> Result<ExportedKey, Error> {
422 // Step 1. If the underlying cryptographic key material represented by the [[handle]] internal
423 // slot of key cannot be accessed, then throw an OperationError.
424
425 // Step 2.
426 let result = match format {
427 // If format is "raw": (Only applied to AES-CTR, AES-CBC, AES-GCM, AES-KW)
428 KeyFormat::Raw
429 if matches!(
430 aes_algorithm,
431 AesAlgorithm::AesCtr |
432 AesAlgorithm::AesCbc |
433 AesAlgorithm::AesGcm |
434 AesAlgorithm::AesKw
435 ) =>
436 {
437 // Step 2.1. Let data be a byte sequence containing the raw octets of the key
438 // represented by [[handle]] internal slot of key.
439 let data = match key.handle() {
440 Handle::Aes128Key(key) => key.to_vec(),
441 Handle::Aes192Key(key) => key.to_vec(),
442 Handle::Aes256Key(key) => key.to_vec(),
443 _ => {
444 return Err(Error::Operation(Some(
445 "The key handle is not representing an AES key".to_string(),
446 )));
447 },
448 };
449
450 // Step 2.2. Let result be data.
451 ExportedKey::Bytes(data)
452 },
453 // If format is "raw-secret":
454 KeyFormat::Raw_secret => {
455 // Step 2.1. Let data be a byte sequence containing the raw octets of the key
456 // represented by [[handle]] internal slot of key.
457 let data = match key.handle() {
458 Handle::Aes128Key(key) => key.to_vec(),
459 Handle::Aes192Key(key) => key.to_vec(),
460 Handle::Aes256Key(key) => key.to_vec(),
461 _ => {
462 return Err(Error::Operation(Some(
463 "The key handle is not representing an AES key".to_string(),
464 )));
465 },
466 };
467
468 // Step 2.2. Let result be data.
469 ExportedKey::Bytes(data)
470 },
471 // If format is "jwk":
472 KeyFormat::Jwk => {
473 // Step 2.1. Let jwk be a new JsonWebKey dictionary.
474 // Step 2.2. Set the kty attribute of jwk to the string "oct".
475 let mut jwk = JsonWebKey {
476 kty: Some(DOMString::from("oct")),
477 ..Default::default()
478 };
479
480 // Step 2.3. Set the k attribute of jwk to be a string containing the raw octets of the
481 // key represented by [[handle]] internal slot of key, encoded according to Section 6.4
482 // of JSON Web Algorithms [JWA].
483 let key_bytes = match key.handle() {
484 Handle::Aes128Key(key) => key.as_slice(),
485 Handle::Aes192Key(key) => key.as_slice(),
486 Handle::Aes256Key(key) => key.as_slice(),
487 _ => {
488 return Err(Error::Operation(Some(
489 "The key handle is not representing an AES key".to_string(),
490 )));
491 },
492 };
493 jwk.encode_string_field(JwkStringField::K, key_bytes);
494
495 match aes_algorithm {
496 AesAlgorithm::AesCtr => {
497 // Step 2.4.
498 // If the length attribute of key is 128:
499 // Set the alg attribute of jwk to the string "A128CTR".
500 // If the length attribute of key is 192:
501 // Set the alg attribute of jwk to the string "A192CTR".
502 // If the length attribute of key is 256:
503 // Set the alg attribute of jwk to the string "A256CTR".
504 let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
505 else {
506 return Err(Error::Operation(None));
507 };
508 let alg = match algorithm.length {
509 128 => "A128CTR",
510 192 => "A192CTR",
511 256 => "A256CTR",
512 _ => return Err(Error::Operation(Some(
513 "The length attribute of the [[algorithm]] internal slot of key is not \
514 128, 192 or 256".to_string(),
515 )))
516 };
517 jwk.alg = Some(DOMString::from(alg));
518 },
519 AesAlgorithm::AesCbc => {
520 // Step 2.4.
521 // If the length attribute of key is 128:
522 // Set the alg attribute of jwk to the string "A128CBC".
523 // If the length attribute of key is 192:
524 // Set the alg attribute of jwk to the string "A192CBC".
525 // If the length attribute of key is 256:
526 // Set the alg attribute of jwk to the string "A256CBC".
527 let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
528 else {
529 return Err(Error::Operation(None));
530 };
531 let alg = match algorithm.length {
532 128 => "A128CBC",
533 192 => "A192CBC",
534 256 => "A256CBC",
535 _ => return Err(Error::Operation(Some(
536 "The length attribute of the [[algorithm]] internal slot of key is not \
537 128, 192 or 256".to_string(),
538 )))
539 };
540 jwk.alg = Some(DOMString::from(alg));
541 },
542 AesAlgorithm::AesGcm => {
543 // Step 2.4.
544 // If the length attribute of key is 128:
545 // Set the alg attribute of jwk to the string "A128GCM".
546 // If the length attribute of key is 192:
547 // Set the alg attribute of jwk to the string "A192GCM".
548 // If the length attribute of key is 256:
549 // Set the alg attribute of jwk to the string "A256GCM".
550 let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
551 else {
552 return Err(Error::Operation(None));
553 };
554 let alg = match algorithm.length {
555 128 => "A128GCM",
556 192 => "A192GCM",
557 256 => "A256GCM",
558 _ => return Err(Error::Operation(Some(
559 "The length attribute of the [[algorithm]] internal slot of key is not \
560 128, 192 or 256".to_string(),
561 )))
562 };
563 jwk.alg = Some(DOMString::from(alg));
564 },
565 AesAlgorithm::AesKw => {
566 // Step 2.4.
567 // If the length attribute of key is 128:
568 // Set the alg attribute of jwk to the string "A128KW".
569 // If the length attribute of key is 192:
570 // Set the alg attribute of jwk to the string "A192KW".
571 // If the length attribute of key is 256:
572 // Set the alg attribute of jwk to the string "A256KW".
573 let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
574 else {
575 return Err(Error::Operation(None));
576 };
577 let alg = match algorithm.length {
578 128 => "A128KW",
579 192 => "A192KW",
580 256 => "A256KW",
581 _ => return Err(Error::Operation(Some(
582 "The length attribute of the [[algorithm]] internal slot of key is not \
583 128, 192 or 256".to_string(),
584 )))
585 };
586 jwk.alg = Some(DOMString::from(alg));
587 },
588 AesAlgorithm::AesOcb => {
589 // Step 2.4.
590 // If the length attribute of key is 128:
591 // Set the alg attribute of jwk to the string "A128OCB".
592 // If the length attribute of key is 192:
593 // Set the alg attribute of jwk to the string "A192OCB".
594 // If the length attribute of key is 256:
595 // Set the alg attribute of jwk to the string "A256OCB".
596 let KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) = key.algorithm()
597 else {
598 return Err(Error::Operation(None));
599 };
600 let alg = match algorithm.length {
601 128 => "A128OCB",
602 192 => "A192OCB",
603 256 => "A256OCB",
604 _ => return Err(Error::Operation(Some(
605 "The length attribute of the [[algorithm]] internal slot of key is not \
606 128, 192 or 256".to_string(),
607 )))
608 };
609 jwk.alg = Some(DOMString::from(alg));
610 },
611 }
612
613 // Step 2.5. Set the key_ops attribute of jwk to equal the usages attribute of key.
614 jwk.set_key_ops(key.usages());
615
616 // Step 2.6. Set the ext attribute of jwk to equal the [[extractable]] internal slot of
617 // key.
618 jwk.ext = Some(key.Extractable());
619
620 // Step 2.7. Let result be jwk.
621 ExportedKey::Jwk(Box::new(jwk))
622 },
623 _ => {
624 // throw a NotSupportedError.
625 return Err(Error::NotSupported(Some(
626 "Unsupported import key format for AES key".to_string(),
627 )));
628 },
629 };
630
631 // Step 3. Return result.
632 Ok(result)
633}
634
635/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-get-key-length>
636/// <https://w3c.github.io/webcrypto/#aes-cbc-operations-get-key-length>
637/// <https://w3c.github.io/webcrypto/#aes-gcm-operations-get-key-length>
638/// <https://w3c.github.io/webcrypto/#aes-kw-operations-get-key-length>
639/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-get-key-length>
640pub(crate) fn get_key_length(
641 normalized_derived_key_algorithm: &SubtleAesDerivedKeyParams,
642) -> Result<Option<u32>, Error> {
643 // Step 1. If the length member of normalizedDerivedKeyAlgorithm is not 128, 192 or 256, then
644 // throw an OperationError.
645 if !matches!(normalized_derived_key_algorithm.length, 128 | 192 | 256) {
646 return Err(Error::Operation(Some(
647 "The length member of normalizedDerivedKeyAlgorithm is not 128, 192 or 256".to_string(),
648 )));
649 }
650
651 // Step 2. Return the length member of normalizedDerivedKeyAlgorithm.
652 Ok(Some(normalized_derived_key_algorithm.length as u32))
653}