1use aes::{Aes128, Aes192, Aes256};
6use aes_gcm::aead::common::BlockSizeUser;
7use aes_gcm::aead::common::array::ArraySize;
8use aes_gcm::aead::common::typenum::{U4, U8, U12, U13, U14, U15, U16, U32};
9use aes_gcm::aes::cipher::BlockCipherEncrypt;
10use aes_gcm::{AeadInOut, AesGcm, Key, KeyInit, TagSize as SealedTagSize};
11use js::context::JSContext;
12
13use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::KeyUsage;
14use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::KeyFormat;
15use crate::dom::bindings::error::Error;
16use crate::dom::bindings::root::DomRoot;
17use crate::dom::cryptokey::{CryptoKey, Handle};
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::subtlecrypto::aes_common::AesAlgorithm;
20use crate::dom::subtlecrypto::{
21 ExportedKey, SubtleAesDerivedKeyParams, SubtleAesGcmParams, SubtleAesKeyGenParams, aes_common,
22};
23
24pub(crate) fn encrypt(
26 normalized_algorithm: &SubtleAesGcmParams,
27 key: &CryptoKey,
28 plaintext: &[u8],
29) -> Result<Vec<u8>, Error> {
30 if plaintext.len() as u64 > (1 << 39) - 256 {
33 return Err(Error::Operation(Some("The plaintext is too long".into())));
34 }
35
36 if normalized_algorithm.iv.len() > u64::MAX as usize {
39 return Err(Error::Operation(Some(
40 "The iv member of normalizedAlgorithm is too long".into(),
41 )));
42 }
43
44 if normalized_algorithm
47 .additional_data
48 .as_ref()
49 .is_some_and(|data| data.len() > u64::MAX as usize)
50 {
51 return Err(Error::Operation(Some(
52 "The additional authentication data is too long".into(),
53 )));
54 }
55
56 let tag_length = match normalized_algorithm.tag_length {
64 None => 128,
65 Some(tag_length) if matches!(tag_length, 32 | 64 | 96 | 104 | 112 | 120 | 128) => {
66 tag_length
67 },
68 _ => {
69 return Err(Error::Operation(Some(
70 "The tagLength member of normalizedAlgorithm is present, \
71 and not one of 32, 64, 96, 104, 112, 120 or 128"
72 .to_string(),
73 )));
74 },
75 };
76
77 let additional_data = normalized_algorithm
80 .additional_data
81 .as_deref()
82 .unwrap_or_default();
83
84 let iv = normalized_algorithm.iv.as_slice();
92 let ciphertext = match key.handle() {
93 Handle::Aes128Key(key) => match (iv.len(), tag_length) {
94 (12, 32) => gcm_encrypt::<Aes128, U12, U4>(key, plaintext, iv, additional_data)?,
96 (12, 64) => gcm_encrypt::<Aes128, U12, U8>(key, plaintext, iv, additional_data)?,
97 (12, 96) => gcm_encrypt::<Aes128, U12, U12>(key, plaintext, iv, additional_data)?,
98 (12, 104) => gcm_encrypt::<Aes128, U12, U13>(key, plaintext, iv, additional_data)?,
99 (12, 112) => gcm_encrypt::<Aes128, U12, U14>(key, plaintext, iv, additional_data)?,
100 (12, 120) => gcm_encrypt::<Aes128, U12, U15>(key, plaintext, iv, additional_data)?,
101 (12, 128) => gcm_encrypt::<Aes128, U12, U16>(key, plaintext, iv, additional_data)?,
102
103 (16, 32) => gcm_encrypt::<Aes128, U16, U4>(key, plaintext, iv, additional_data)?,
105 (16, 64) => gcm_encrypt::<Aes128, U16, U8>(key, plaintext, iv, additional_data)?,
106 (16, 96) => gcm_encrypt::<Aes128, U16, U12>(key, plaintext, iv, additional_data)?,
107 (16, 104) => gcm_encrypt::<Aes128, U16, U13>(key, plaintext, iv, additional_data)?,
108 (16, 112) => gcm_encrypt::<Aes128, U16, U14>(key, plaintext, iv, additional_data)?,
109 (16, 120) => gcm_encrypt::<Aes128, U16, U15>(key, plaintext, iv, additional_data)?,
110 (16, 128) => gcm_encrypt::<Aes128, U16, U16>(key, plaintext, iv, additional_data)?,
111
112 (32, 32) => gcm_encrypt::<Aes128, U32, U4>(key, plaintext, iv, additional_data)?,
114 (32, 64) => gcm_encrypt::<Aes128, U32, U8>(key, plaintext, iv, additional_data)?,
115 (32, 96) => gcm_encrypt::<Aes128, U32, U12>(key, plaintext, iv, additional_data)?,
116 (32, 104) => gcm_encrypt::<Aes128, U32, U13>(key, plaintext, iv, additional_data)?,
117 (32, 112) => gcm_encrypt::<Aes128, U32, U14>(key, plaintext, iv, additional_data)?,
118 (32, 120) => gcm_encrypt::<Aes128, U32, U15>(key, plaintext, iv, additional_data)?,
119 (32, 128) => gcm_encrypt::<Aes128, U32, U16>(key, plaintext, iv, additional_data)?,
120
121 _ => {
122 return Err(Error::Operation(Some(format!(
123 "Unsupported iv size: {} bytes",
124 iv.len() * 8,
125 ))));
126 },
127 },
128 Handle::Aes192Key(key) => match (iv.len(), tag_length) {
129 (12, 32) => gcm_encrypt::<Aes192, U12, U4>(key, plaintext, iv, additional_data)?,
131 (12, 64) => gcm_encrypt::<Aes192, U12, U8>(key, plaintext, iv, additional_data)?,
132 (12, 96) => gcm_encrypt::<Aes192, U12, U12>(key, plaintext, iv, additional_data)?,
133 (12, 104) => gcm_encrypt::<Aes192, U12, U13>(key, plaintext, iv, additional_data)?,
134 (12, 112) => gcm_encrypt::<Aes192, U12, U14>(key, plaintext, iv, additional_data)?,
135 (12, 120) => gcm_encrypt::<Aes192, U12, U15>(key, plaintext, iv, additional_data)?,
136 (12, 128) => gcm_encrypt::<Aes192, U12, U16>(key, plaintext, iv, additional_data)?,
137
138 (16, 32) => gcm_encrypt::<Aes192, U16, U4>(key, plaintext, iv, additional_data)?,
140 (16, 64) => gcm_encrypt::<Aes192, U16, U8>(key, plaintext, iv, additional_data)?,
141 (16, 96) => gcm_encrypt::<Aes192, U16, U12>(key, plaintext, iv, additional_data)?,
142 (16, 104) => gcm_encrypt::<Aes192, U16, U13>(key, plaintext, iv, additional_data)?,
143 (16, 112) => gcm_encrypt::<Aes192, U16, U14>(key, plaintext, iv, additional_data)?,
144 (16, 120) => gcm_encrypt::<Aes192, U16, U15>(key, plaintext, iv, additional_data)?,
145 (16, 128) => gcm_encrypt::<Aes192, U16, U16>(key, plaintext, iv, additional_data)?,
146
147 (32, 32) => gcm_encrypt::<Aes192, U32, U4>(key, plaintext, iv, additional_data)?,
149 (32, 64) => gcm_encrypt::<Aes192, U32, U8>(key, plaintext, iv, additional_data)?,
150 (32, 96) => gcm_encrypt::<Aes192, U32, U12>(key, plaintext, iv, additional_data)?,
151 (32, 104) => gcm_encrypt::<Aes192, U32, U13>(key, plaintext, iv, additional_data)?,
152 (32, 112) => gcm_encrypt::<Aes192, U32, U14>(key, plaintext, iv, additional_data)?,
153 (32, 120) => gcm_encrypt::<Aes192, U32, U15>(key, plaintext, iv, additional_data)?,
154 (32, 128) => gcm_encrypt::<Aes192, U32, U16>(key, plaintext, iv, additional_data)?,
155
156 _ => {
157 return Err(Error::Operation(Some(format!(
158 "Unsupported iv size: {} bytes",
159 iv.len() * 8,
160 ))));
161 },
162 },
163 Handle::Aes256Key(key) => match (iv.len(), tag_length) {
164 (12, 32) => gcm_encrypt::<Aes256, U12, U4>(key, plaintext, iv, additional_data)?,
166 (12, 64) => gcm_encrypt::<Aes256, U12, U8>(key, plaintext, iv, additional_data)?,
167 (12, 96) => gcm_encrypt::<Aes256, U12, U12>(key, plaintext, iv, additional_data)?,
168 (12, 104) => gcm_encrypt::<Aes256, U12, U13>(key, plaintext, iv, additional_data)?,
169 (12, 112) => gcm_encrypt::<Aes256, U12, U14>(key, plaintext, iv, additional_data)?,
170 (12, 120) => gcm_encrypt::<Aes256, U12, U15>(key, plaintext, iv, additional_data)?,
171 (12, 128) => gcm_encrypt::<Aes256, U12, U16>(key, plaintext, iv, additional_data)?,
172
173 (16, 32) => gcm_encrypt::<Aes256, U16, U4>(key, plaintext, iv, additional_data)?,
175 (16, 64) => gcm_encrypt::<Aes256, U16, U8>(key, plaintext, iv, additional_data)?,
176 (16, 96) => gcm_encrypt::<Aes256, U16, U12>(key, plaintext, iv, additional_data)?,
177 (16, 104) => gcm_encrypt::<Aes256, U16, U13>(key, plaintext, iv, additional_data)?,
178 (16, 112) => gcm_encrypt::<Aes256, U16, U14>(key, plaintext, iv, additional_data)?,
179 (16, 120) => gcm_encrypt::<Aes256, U16, U15>(key, plaintext, iv, additional_data)?,
180 (16, 128) => gcm_encrypt::<Aes256, U16, U16>(key, plaintext, iv, additional_data)?,
181
182 (32, 32) => gcm_encrypt::<Aes256, U32, U4>(key, plaintext, iv, additional_data)?,
184 (32, 64) => gcm_encrypt::<Aes256, U32, U8>(key, plaintext, iv, additional_data)?,
185 (32, 96) => gcm_encrypt::<Aes256, U32, U12>(key, plaintext, iv, additional_data)?,
186 (32, 104) => gcm_encrypt::<Aes256, U32, U13>(key, plaintext, iv, additional_data)?,
187 (32, 112) => gcm_encrypt::<Aes256, U32, U14>(key, plaintext, iv, additional_data)?,
188 (32, 120) => gcm_encrypt::<Aes256, U32, U15>(key, plaintext, iv, additional_data)?,
189 (32, 128) => gcm_encrypt::<Aes256, U32, U16>(key, plaintext, iv, additional_data)?,
190
191 _ => {
192 return Err(Error::Operation(Some(format!(
193 "Unsupported iv size: {} bytes",
194 iv.len() * 8,
195 ))));
196 },
197 },
198 _ => {
199 return Err(Error::Operation(Some(
200 "The key handle is not representing an AES key".to_string(),
201 )));
202 },
203 };
204
205 Ok(ciphertext)
207}
208
209fn gcm_encrypt<Aes, NonceSize, TagSize>(
211 key: &Key<Aes>,
212 plaintext: &[u8],
213 iv: &[u8],
214 additional_data: &[u8],
215) -> Result<Vec<u8>, Error>
216where
217 Aes: BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt + KeyInit,
218 NonceSize: ArraySize,
219 TagSize: SealedTagSize,
220{
221 let nonce = iv
222 .try_into()
223 .map_err(|_| Error::Operation(Some("Invalid AES-GCM IV".into())))?;
224 let mut ciphertext = plaintext.to_vec();
225 let cipher = AesGcm::<Aes, NonceSize, TagSize>::new(key);
226 cipher
227 .encrypt_in_place(&nonce, additional_data, &mut ciphertext)
228 .map_err(|_| {
229 Error::Operation(Some(
230 "AES-GCM failed to perform the Authenticated Encryption Function".to_string(),
231 ))
232 })?;
233
234 Ok(ciphertext)
235}
236
237pub(crate) fn decrypt(
239 normalized_algorithm: &SubtleAesGcmParams,
240 key: &CryptoKey,
241 ciphertext: &[u8],
242) -> Result<Vec<u8>, Error> {
243 let tag_length = match normalized_algorithm.tag_length {
251 None => 128,
252 Some(tag_length) if matches!(tag_length, 32 | 64 | 96 | 104 | 112 | 120 | 128) => {
253 tag_length
254 },
255 _ => {
256 return Err(Error::Operation(Some(
257 "The tagLength member of normalizedAlgorithm is present, \
258 and not one of 32, 64, 96, 104, 112, 120 or 128"
259 .to_string(),
260 )));
261 },
262 };
263
264 if ciphertext.len() * 8 < tag_length as usize {
267 return Err(Error::Operation(Some(
268 "The ciphertext is shorter than the tag".into(),
269 )));
270 }
271
272 if normalized_algorithm.iv.len() > u64::MAX as usize {
275 return Err(Error::Operation(Some(
276 "The iv member of normalizedAlgorithm is too long".into(),
277 )));
278 }
279
280 if normalized_algorithm
283 .additional_data
284 .as_ref()
285 .is_some_and(|data| data.len() > u64::MAX as usize)
286 {
287 return Err(Error::Operation(Some(
288 "The additional authentication data is too long".into(),
289 )));
290 }
291
292 let additional_data = normalized_algorithm
300 .additional_data
301 .as_deref()
302 .unwrap_or_default();
303
304 let iv = normalized_algorithm.iv.as_slice();
317 let plaintext = match key.handle() {
318 Handle::Aes128Key(key) => match (iv.len(), tag_length) {
319 (12, 32) => gcm_decrypt::<Aes128, U12, U4>(key, ciphertext, iv, additional_data)?,
321 (12, 64) => gcm_decrypt::<Aes128, U12, U8>(key, ciphertext, iv, additional_data)?,
322 (12, 96) => gcm_decrypt::<Aes128, U12, U12>(key, ciphertext, iv, additional_data)?,
323 (12, 104) => gcm_decrypt::<Aes128, U12, U13>(key, ciphertext, iv, additional_data)?,
324 (12, 112) => gcm_decrypt::<Aes128, U12, U14>(key, ciphertext, iv, additional_data)?,
325 (12, 120) => gcm_decrypt::<Aes128, U12, U15>(key, ciphertext, iv, additional_data)?,
326 (12, 128) => gcm_decrypt::<Aes128, U12, U16>(key, ciphertext, iv, additional_data)?,
327
328 (16, 32) => gcm_decrypt::<Aes128, U16, U4>(key, ciphertext, iv, additional_data)?,
330 (16, 64) => gcm_decrypt::<Aes128, U16, U8>(key, ciphertext, iv, additional_data)?,
331 (16, 96) => gcm_decrypt::<Aes128, U16, U12>(key, ciphertext, iv, additional_data)?,
332 (16, 104) => gcm_decrypt::<Aes128, U16, U13>(key, ciphertext, iv, additional_data)?,
333 (16, 112) => gcm_decrypt::<Aes128, U16, U14>(key, ciphertext, iv, additional_data)?,
334 (16, 120) => gcm_decrypt::<Aes128, U16, U15>(key, ciphertext, iv, additional_data)?,
335 (16, 128) => gcm_decrypt::<Aes128, U16, U16>(key, ciphertext, iv, additional_data)?,
336
337 (32, 32) => gcm_decrypt::<Aes128, U32, U4>(key, ciphertext, iv, additional_data)?,
339 (32, 64) => gcm_decrypt::<Aes128, U32, U8>(key, ciphertext, iv, additional_data)?,
340 (32, 96) => gcm_decrypt::<Aes128, U32, U12>(key, ciphertext, iv, additional_data)?,
341 (32, 104) => gcm_decrypt::<Aes128, U32, U13>(key, ciphertext, iv, additional_data)?,
342 (32, 112) => gcm_decrypt::<Aes128, U32, U14>(key, ciphertext, iv, additional_data)?,
343 (32, 120) => gcm_decrypt::<Aes128, U32, U15>(key, ciphertext, iv, additional_data)?,
344 (32, 128) => gcm_decrypt::<Aes128, U32, U16>(key, ciphertext, iv, additional_data)?,
345
346 _ => {
347 return Err(Error::Operation(Some(format!(
348 "Unsupported iv size: {} bytes",
349 iv.len() * 8,
350 ))));
351 },
352 },
353 Handle::Aes192Key(key) => match (iv.len(), tag_length) {
354 (12, 32) => gcm_decrypt::<Aes192, U12, U4>(key, ciphertext, iv, additional_data)?,
356 (12, 64) => gcm_decrypt::<Aes192, U12, U8>(key, ciphertext, iv, additional_data)?,
357 (12, 96) => gcm_decrypt::<Aes192, U12, U12>(key, ciphertext, iv, additional_data)?,
358 (12, 104) => gcm_decrypt::<Aes192, U12, U13>(key, ciphertext, iv, additional_data)?,
359 (12, 112) => gcm_decrypt::<Aes192, U12, U14>(key, ciphertext, iv, additional_data)?,
360 (12, 120) => gcm_decrypt::<Aes192, U12, U15>(key, ciphertext, iv, additional_data)?,
361 (12, 128) => gcm_decrypt::<Aes192, U12, U16>(key, ciphertext, iv, additional_data)?,
362
363 (16, 32) => gcm_decrypt::<Aes192, U16, U4>(key, ciphertext, iv, additional_data)?,
365 (16, 64) => gcm_decrypt::<Aes192, U16, U8>(key, ciphertext, iv, additional_data)?,
366 (16, 96) => gcm_decrypt::<Aes192, U16, U12>(key, ciphertext, iv, additional_data)?,
367 (16, 104) => gcm_decrypt::<Aes192, U16, U13>(key, ciphertext, iv, additional_data)?,
368 (16, 112) => gcm_decrypt::<Aes192, U16, U14>(key, ciphertext, iv, additional_data)?,
369 (16, 120) => gcm_decrypt::<Aes192, U16, U15>(key, ciphertext, iv, additional_data)?,
370 (16, 128) => gcm_decrypt::<Aes192, U16, U16>(key, ciphertext, iv, additional_data)?,
371
372 (32, 32) => gcm_decrypt::<Aes192, U32, U4>(key, ciphertext, iv, additional_data)?,
374 (32, 64) => gcm_decrypt::<Aes192, U32, U8>(key, ciphertext, iv, additional_data)?,
375 (32, 96) => gcm_decrypt::<Aes192, U32, U12>(key, ciphertext, iv, additional_data)?,
376 (32, 104) => gcm_decrypt::<Aes192, U32, U13>(key, ciphertext, iv, additional_data)?,
377 (32, 112) => gcm_decrypt::<Aes192, U32, U14>(key, ciphertext, iv, additional_data)?,
378 (32, 120) => gcm_decrypt::<Aes192, U32, U15>(key, ciphertext, iv, additional_data)?,
379 (32, 128) => gcm_decrypt::<Aes192, U32, U16>(key, ciphertext, iv, additional_data)?,
380
381 _ => {
382 return Err(Error::Operation(Some(format!(
383 "Unsupported iv size: {} bytes",
384 iv.len() * 8,
385 ))));
386 },
387 },
388 Handle::Aes256Key(key) => match (iv.len(), tag_length) {
389 (12, 32) => gcm_decrypt::<Aes256, U12, U4>(key, ciphertext, iv, additional_data)?,
391 (12, 64) => gcm_decrypt::<Aes256, U12, U8>(key, ciphertext, iv, additional_data)?,
392 (12, 96) => gcm_decrypt::<Aes256, U12, U12>(key, ciphertext, iv, additional_data)?,
393 (12, 104) => gcm_decrypt::<Aes256, U12, U13>(key, ciphertext, iv, additional_data)?,
394 (12, 112) => gcm_decrypt::<Aes256, U12, U14>(key, ciphertext, iv, additional_data)?,
395 (12, 120) => gcm_decrypt::<Aes256, U12, U15>(key, ciphertext, iv, additional_data)?,
396 (12, 128) => gcm_decrypt::<Aes256, U12, U16>(key, ciphertext, iv, additional_data)?,
397
398 (16, 32) => gcm_decrypt::<Aes256, U16, U4>(key, ciphertext, iv, additional_data)?,
400 (16, 64) => gcm_decrypt::<Aes256, U16, U8>(key, ciphertext, iv, additional_data)?,
401 (16, 96) => gcm_decrypt::<Aes256, U16, U12>(key, ciphertext, iv, additional_data)?,
402 (16, 104) => gcm_decrypt::<Aes256, U16, U13>(key, ciphertext, iv, additional_data)?,
403 (16, 112) => gcm_decrypt::<Aes256, U16, U14>(key, ciphertext, iv, additional_data)?,
404 (16, 120) => gcm_decrypt::<Aes256, U16, U15>(key, ciphertext, iv, additional_data)?,
405 (16, 128) => gcm_decrypt::<Aes256, U16, U16>(key, ciphertext, iv, additional_data)?,
406
407 (32, 32) => gcm_decrypt::<Aes256, U32, U4>(key, ciphertext, iv, additional_data)?,
409 (32, 64) => gcm_decrypt::<Aes256, U32, U8>(key, ciphertext, iv, additional_data)?,
410 (32, 96) => gcm_decrypt::<Aes256, U32, U12>(key, ciphertext, iv, additional_data)?,
411 (32, 104) => gcm_decrypt::<Aes256, U32, U13>(key, ciphertext, iv, additional_data)?,
412 (32, 112) => gcm_decrypt::<Aes256, U32, U14>(key, ciphertext, iv, additional_data)?,
413 (32, 120) => gcm_decrypt::<Aes256, U32, U15>(key, ciphertext, iv, additional_data)?,
414 (32, 128) => gcm_decrypt::<Aes256, U32, U16>(key, ciphertext, iv, additional_data)?,
415
416 _ => {
417 return Err(Error::Operation(Some(format!(
418 "Unsupported iv size: {} bytes",
419 iv.len() * 8,
420 ))));
421 },
422 },
423 _ => {
424 return Err(Error::Operation(Some(
425 "The key handle is not representing an AES key".to_string(),
426 )));
427 },
428 };
429
430 Ok(plaintext)
432}
433
434fn gcm_decrypt<Aes, NonceSize, TagSize>(
436 key: &Key<Aes>,
437 ciphertext: &[u8],
438 iv: &[u8],
439 additional_data: &[u8],
440) -> Result<Vec<u8>, Error>
441where
442 Aes: BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt + KeyInit,
443 NonceSize: ArraySize,
444 TagSize: SealedTagSize,
445{
446 let nonce = iv
447 .try_into()
448 .map_err(|_| Error::Operation(Some("Invalid AES-GCM IV".into())))?;
449 let mut plaintext = ciphertext.to_vec();
450 let cipher = AesGcm::<Aes, NonceSize, TagSize>::new(key);
451 cipher
452 .decrypt_in_place(&nonce, additional_data, &mut plaintext)
453 .map_err(|_| {
454 Error::Operation(Some(
455 "AES-GCM failed to perform the Authenticated Decryption Function".to_string(),
456 ))
457 })?;
458
459 Ok(plaintext)
460}
461
462pub(crate) fn generate_key(
464 cx: &mut JSContext,
465 global: &GlobalScope,
466 normalized_algorithm: &SubtleAesKeyGenParams,
467 extractable: bool,
468 usages: Vec<KeyUsage>,
469) -> Result<DomRoot<CryptoKey>, Error> {
470 aes_common::generate_key(
471 AesAlgorithm::AesGcm,
472 cx,
473 global,
474 normalized_algorithm,
475 extractable,
476 usages,
477 )
478}
479
480pub(crate) fn import_key(
482 cx: &mut JSContext,
483 global: &GlobalScope,
484 format: KeyFormat,
485 key_data: &[u8],
486 extractable: bool,
487 usages: Vec<KeyUsage>,
488) -> Result<DomRoot<CryptoKey>, Error> {
489 aes_common::import_key(
490 AesAlgorithm::AesGcm,
491 cx,
492 global,
493 format,
494 key_data,
495 extractable,
496 usages,
497 )
498}
499
500pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
502 aes_common::export_key(AesAlgorithm::AesGcm, format, key)
503}
504
505pub(crate) fn get_key_length(
507 normalized_derived_key_algorithm: &SubtleAesDerivedKeyParams,
508) -> Result<Option<u32>, Error> {
509 aes_common::get_key_length(normalized_derived_key_algorithm)
510}