script/dom/subtlecrypto/
aes_ocb_operation.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 cipher::generic_array::typenum::{GrEq, IsGreaterOrEqual, IsLessOrEqual, LeEq, NonZero};
8use cipher::{ArrayLength, BlockDecrypt, BlockEncrypt, BlockSizeUser};
9use ocb3::aead::AeadMutInPlace;
10use ocb3::aead::consts::{U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16};
11use ocb3::{KeyInit, Nonce, Ocb3};
12
13use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{KeyType, 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    ALG_AES_OCB, ExportedKey, KeyAlgorithmAndDerivatives, SubtleAeadParams,
22    SubtleAesDerivedKeyParams, SubtleAesKeyAlgorithm, SubtleAesKeyGenParams, aes_common,
23};
24use crate::script_runtime::CanGc;
25
26/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-encrypt>
27pub(crate) fn encrypt(
28    normalized_algorithm: &SubtleAeadParams,
29    key: &CryptoKey,
30    plaintext: &[u8],
31) -> Result<Vec<u8>, Error> {
32    // Step 1. If the iv member of normalizedAlgorithm has a length greater than 15 bytes, then
33    // throw an OperationError.
34    if normalized_algorithm.iv.len() > 15 {
35        return Err(Error::Operation(Some(
36            "The iv member of normalizedAlgorithm has a length greater than 15 bytes".to_string(),
37        )));
38    }
39
40    // Step 2.
41    // If the tagLength member of normalizedAlgorithm is not present:
42    //     Let tagLength be 128.
43    // If the tagLength member of normalizedAlgorithm is one of 64, 96 or 128:
44    //     Let tagLength be equal to the tagLength member of normalizedAlgorithm
45    // Otherwise:
46    //     throw an OperationError.
47    let tag_length = match normalized_algorithm.tag_length {
48        None => 128,
49        Some(tag_length) if matches!(tag_length, 64 | 96 | 128) => tag_length,
50        _ => {
51            return Err(Error::Operation(Some(
52                "The tagLength member of normalizedAlgorithm is present, \
53                and not one of 64, 96, or 128"
54                    .to_string(),
55            )));
56        },
57    };
58
59    // Step 3. Let additionalData be the additionalData member of normalizedAlgorithm if present or
60    // the empty octet string otherwise.
61    let additional_data = normalized_algorithm
62        .additional_data
63        .as_deref()
64        .unwrap_or_default();
65
66    // Step 4. Let C be the output that results from performing the OCB-ENCRYPT function described
67    // in Section 4.2 of [RFC7253] using AES as the block cipher, using the key represented by
68    // [[handle]] internal slot of key as the K input parameter, the iv member of
69    // normalizedAlgorithm as the N input parameter, additionalData as the A input parameter,
70    // plaintext as the P input parameter, and tagLength as the TAGLEN global parameter.
71    //
72    // NOTE: We only support IV(nonce) size from 6 bytes to 15 bytes because of the restriction
73    // from the `ocb3` crate <https://docs.rs/ocb3/latest/ocb3/struct.Ocb3.html>. This range is
74    // suggested in the paper <https://eprint.iacr.org/2023/326.pdf> to prevent an attack.
75    let iv = &normalized_algorithm.iv;
76    let c = match key.handle() {
77        Handle::Aes128Key(key) => match (iv.len(), tag_length) {
78            (6, 64) => ocb_encrypt::<Aes128, U6, U8>(key, plaintext, iv, additional_data)?,
79            (7, 64) => ocb_encrypt::<Aes128, U7, U8>(key, plaintext, iv, additional_data)?,
80            (8, 64) => ocb_encrypt::<Aes128, U8, U8>(key, plaintext, iv, additional_data)?,
81            (9, 64) => ocb_encrypt::<Aes128, U9, U8>(key, plaintext, iv, additional_data)?,
82            (10, 64) => ocb_encrypt::<Aes128, U10, U8>(key, plaintext, iv, additional_data)?,
83            (11, 64) => ocb_encrypt::<Aes128, U11, U8>(key, plaintext, iv, additional_data)?,
84            (12, 64) => ocb_encrypt::<Aes128, U12, U8>(key, plaintext, iv, additional_data)?,
85            (13, 64) => ocb_encrypt::<Aes128, U13, U8>(key, plaintext, iv, additional_data)?,
86            (14, 64) => ocb_encrypt::<Aes128, U14, U8>(key, plaintext, iv, additional_data)?,
87            (15, 64) => ocb_encrypt::<Aes128, U15, U8>(key, plaintext, iv, additional_data)?,
88
89            (6, 96) => ocb_encrypt::<Aes128, U6, U12>(key, plaintext, iv, additional_data)?,
90            (7, 96) => ocb_encrypt::<Aes128, U7, U12>(key, plaintext, iv, additional_data)?,
91            (8, 96) => ocb_encrypt::<Aes128, U8, U12>(key, plaintext, iv, additional_data)?,
92            (9, 96) => ocb_encrypt::<Aes128, U9, U12>(key, plaintext, iv, additional_data)?,
93            (10, 96) => ocb_encrypt::<Aes128, U10, U12>(key, plaintext, iv, additional_data)?,
94            (11, 96) => ocb_encrypt::<Aes128, U11, U12>(key, plaintext, iv, additional_data)?,
95            (12, 96) => ocb_encrypt::<Aes128, U12, U12>(key, plaintext, iv, additional_data)?,
96            (13, 96) => ocb_encrypt::<Aes128, U13, U12>(key, plaintext, iv, additional_data)?,
97            (14, 96) => ocb_encrypt::<Aes128, U14, U12>(key, plaintext, iv, additional_data)?,
98            (15, 96) => ocb_encrypt::<Aes128, U15, U12>(key, plaintext, iv, additional_data)?,
99
100            (6, 128) => ocb_encrypt::<Aes128, U6, U16>(key, plaintext, iv, additional_data)?,
101            (7, 128) => ocb_encrypt::<Aes128, U7, U16>(key, plaintext, iv, additional_data)?,
102            (8, 128) => ocb_encrypt::<Aes128, U8, U16>(key, plaintext, iv, additional_data)?,
103            (9, 128) => ocb_encrypt::<Aes128, U9, U16>(key, plaintext, iv, additional_data)?,
104            (10, 128) => ocb_encrypt::<Aes128, U10, U16>(key, plaintext, iv, additional_data)?,
105            (11, 128) => ocb_encrypt::<Aes128, U11, U16>(key, plaintext, iv, additional_data)?,
106            (12, 128) => ocb_encrypt::<Aes128, U12, U16>(key, plaintext, iv, additional_data)?,
107            (13, 128) => ocb_encrypt::<Aes128, U13, U16>(key, plaintext, iv, additional_data)?,
108            (14, 128) => ocb_encrypt::<Aes128, U14, U16>(key, plaintext, iv, additional_data)?,
109            (15, 128) => ocb_encrypt::<Aes128, U15, U16>(key, plaintext, iv, additional_data)?,
110
111            _ => {
112                return Err(Error::Operation(Some(format!(
113                    "Unsupported IV size ({}-bytes) and/or tag length ({}-bit)",
114                    iv.len(),
115                    tag_length
116                ))));
117            },
118        },
119        Handle::Aes192Key(key) => match (iv.len(), tag_length) {
120            (6, 64) => ocb_encrypt::<Aes192, U6, U8>(key, plaintext, iv, additional_data)?,
121            (7, 64) => ocb_encrypt::<Aes192, U7, U8>(key, plaintext, iv, additional_data)?,
122            (8, 64) => ocb_encrypt::<Aes192, U8, U8>(key, plaintext, iv, additional_data)?,
123            (9, 64) => ocb_encrypt::<Aes192, U9, U8>(key, plaintext, iv, additional_data)?,
124            (10, 64) => ocb_encrypt::<Aes192, U10, U8>(key, plaintext, iv, additional_data)?,
125            (11, 64) => ocb_encrypt::<Aes192, U11, U8>(key, plaintext, iv, additional_data)?,
126            (12, 64) => ocb_encrypt::<Aes192, U12, U8>(key, plaintext, iv, additional_data)?,
127            (13, 64) => ocb_encrypt::<Aes192, U13, U8>(key, plaintext, iv, additional_data)?,
128            (14, 64) => ocb_encrypt::<Aes192, U14, U8>(key, plaintext, iv, additional_data)?,
129            (15, 64) => ocb_encrypt::<Aes192, U15, U8>(key, plaintext, iv, additional_data)?,
130
131            (6, 96) => ocb_encrypt::<Aes192, U6, U12>(key, plaintext, iv, additional_data)?,
132            (7, 96) => ocb_encrypt::<Aes192, U7, U12>(key, plaintext, iv, additional_data)?,
133            (8, 96) => ocb_encrypt::<Aes192, U8, U12>(key, plaintext, iv, additional_data)?,
134            (9, 96) => ocb_encrypt::<Aes192, U9, U12>(key, plaintext, iv, additional_data)?,
135            (10, 96) => ocb_encrypt::<Aes192, U10, U12>(key, plaintext, iv, additional_data)?,
136            (11, 96) => ocb_encrypt::<Aes192, U11, U12>(key, plaintext, iv, additional_data)?,
137            (12, 96) => ocb_encrypt::<Aes192, U12, U12>(key, plaintext, iv, additional_data)?,
138            (13, 96) => ocb_encrypt::<Aes192, U13, U12>(key, plaintext, iv, additional_data)?,
139            (14, 96) => ocb_encrypt::<Aes192, U14, U12>(key, plaintext, iv, additional_data)?,
140            (15, 96) => ocb_encrypt::<Aes192, U15, U12>(key, plaintext, iv, additional_data)?,
141
142            (6, 128) => ocb_encrypt::<Aes192, U6, U16>(key, plaintext, iv, additional_data)?,
143            (7, 128) => ocb_encrypt::<Aes192, U7, U16>(key, plaintext, iv, additional_data)?,
144            (8, 128) => ocb_encrypt::<Aes192, U8, U16>(key, plaintext, iv, additional_data)?,
145            (9, 128) => ocb_encrypt::<Aes192, U9, U16>(key, plaintext, iv, additional_data)?,
146            (10, 128) => ocb_encrypt::<Aes192, U10, U16>(key, plaintext, iv, additional_data)?,
147            (11, 128) => ocb_encrypt::<Aes192, U11, U16>(key, plaintext, iv, additional_data)?,
148            (12, 128) => ocb_encrypt::<Aes192, U12, U16>(key, plaintext, iv, additional_data)?,
149            (13, 128) => ocb_encrypt::<Aes192, U13, U16>(key, plaintext, iv, additional_data)?,
150            (14, 128) => ocb_encrypt::<Aes192, U14, U16>(key, plaintext, iv, additional_data)?,
151            (15, 128) => ocb_encrypt::<Aes192, U15, U16>(key, plaintext, iv, additional_data)?,
152
153            _ => {
154                return Err(Error::Operation(Some(format!(
155                    "Unsupported IV size ({}-bytes) and/or tag length ({}-bit)",
156                    iv.len(),
157                    tag_length
158                ))));
159            },
160        },
161        Handle::Aes256Key(key) => match (iv.len(), tag_length) {
162            (6, 64) => ocb_encrypt::<Aes256, U6, U8>(key, plaintext, iv, additional_data)?,
163            (7, 64) => ocb_encrypt::<Aes256, U7, U8>(key, plaintext, iv, additional_data)?,
164            (8, 64) => ocb_encrypt::<Aes256, U8, U8>(key, plaintext, iv, additional_data)?,
165            (9, 64) => ocb_encrypt::<Aes256, U9, U8>(key, plaintext, iv, additional_data)?,
166            (10, 64) => ocb_encrypt::<Aes256, U10, U8>(key, plaintext, iv, additional_data)?,
167            (11, 64) => ocb_encrypt::<Aes256, U11, U8>(key, plaintext, iv, additional_data)?,
168            (12, 64) => ocb_encrypt::<Aes256, U12, U8>(key, plaintext, iv, additional_data)?,
169            (13, 64) => ocb_encrypt::<Aes256, U13, U8>(key, plaintext, iv, additional_data)?,
170            (14, 64) => ocb_encrypt::<Aes256, U14, U8>(key, plaintext, iv, additional_data)?,
171            (15, 64) => ocb_encrypt::<Aes256, U15, U8>(key, plaintext, iv, additional_data)?,
172
173            (6, 96) => ocb_encrypt::<Aes256, U6, U12>(key, plaintext, iv, additional_data)?,
174            (7, 96) => ocb_encrypt::<Aes256, U7, U12>(key, plaintext, iv, additional_data)?,
175            (8, 96) => ocb_encrypt::<Aes256, U8, U12>(key, plaintext, iv, additional_data)?,
176            (9, 96) => ocb_encrypt::<Aes256, U9, U12>(key, plaintext, iv, additional_data)?,
177            (10, 96) => ocb_encrypt::<Aes256, U10, U12>(key, plaintext, iv, additional_data)?,
178            (11, 96) => ocb_encrypt::<Aes256, U11, U12>(key, plaintext, iv, additional_data)?,
179            (12, 96) => ocb_encrypt::<Aes256, U12, U12>(key, plaintext, iv, additional_data)?,
180            (13, 96) => ocb_encrypt::<Aes256, U13, U12>(key, plaintext, iv, additional_data)?,
181            (14, 96) => ocb_encrypt::<Aes256, U14, U12>(key, plaintext, iv, additional_data)?,
182            (15, 96) => ocb_encrypt::<Aes256, U15, U12>(key, plaintext, iv, additional_data)?,
183
184            (6, 128) => ocb_encrypt::<Aes256, U6, U16>(key, plaintext, iv, additional_data)?,
185            (7, 128) => ocb_encrypt::<Aes256, U7, U16>(key, plaintext, iv, additional_data)?,
186            (8, 128) => ocb_encrypt::<Aes256, U8, U16>(key, plaintext, iv, additional_data)?,
187            (9, 128) => ocb_encrypt::<Aes256, U9, U16>(key, plaintext, iv, additional_data)?,
188            (10, 128) => ocb_encrypt::<Aes256, U10, U16>(key, plaintext, iv, additional_data)?,
189            (11, 128) => ocb_encrypt::<Aes256, U11, U16>(key, plaintext, iv, additional_data)?,
190            (12, 128) => ocb_encrypt::<Aes256, U12, U16>(key, plaintext, iv, additional_data)?,
191            (13, 128) => ocb_encrypt::<Aes256, U13, U16>(key, plaintext, iv, additional_data)?,
192            (14, 128) => ocb_encrypt::<Aes256, U14, U16>(key, plaintext, iv, additional_data)?,
193            (15, 128) => ocb_encrypt::<Aes256, U15, U16>(key, plaintext, iv, additional_data)?,
194
195            _ => {
196                return Err(Error::Operation(Some(format!(
197                    "Unsupported IV size ({}-bytes) and/or tag length ({}-bit)",
198                    iv.len(),
199                    tag_length
200                ))));
201            },
202        },
203        _ => {
204            return Err(Error::Operation(Some(
205                "The key handle is not representing an AES key".to_string(),
206            )));
207        },
208    };
209
210    // Step 5. Return C.
211    Ok(c)
212}
213
214/// Helper for Step 5 of <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-encrypt>
215fn ocb_encrypt<Cipher, NonceSize, TagSize>(
216    key: &Key<Cipher>,
217    plaintext: &[u8],
218    iv: &[u8],
219    additional_data: &[u8],
220) -> Result<Vec<u8>, Error>
221where
222    Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt + KeyInit + BlockDecrypt,
223    NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
224    GrEq<NonceSize, U6>: NonZero,
225    LeEq<NonceSize, U15>: NonZero,
226    TagSize: ArrayLength<u8> + NonZero + IsLessOrEqual<U16>,
227    LeEq<TagSize, U16>: NonZero,
228{
229    let mut c = plaintext.to_vec();
230    let mut cipher = Ocb3::<Cipher, NonceSize, TagSize>::new(key);
231    cipher
232        .encrypt_in_place(Nonce::from_slice(iv), additional_data, &mut c)
233        .map_err(|_| {
234            Error::Operation(Some("AES-OCB authenticated encryption failed".to_string()))
235        })?;
236    Ok(c)
237}
238
239/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-decrypt>
240pub(crate) fn decrypt(
241    normalized_algorithm: &SubtleAeadParams,
242    key: &CryptoKey,
243    ciphertext: &[u8],
244) -> Result<Vec<u8>, Error> {
245    // Step 1. If the iv member of normalizedAlgorithm has a length greater than 15 bytes, then
246    // throw an OperationError.
247    if normalized_algorithm.iv.len() > 15 {
248        return Err(Error::Operation(Some(
249            "The iv member of normalizedAlgorithm has a length greater than 15 bytes".to_string(),
250        )));
251    }
252
253    // Step 2.
254    // If the tagLength member of normalizedAlgorithm is not present:
255    //     Let tagLength be 128.
256    // If the tagLength member of normalizedAlgorithm is one of 64, 96 or 128:
257    //     Let tagLength be equal to the tagLength member of normalizedAlgorithm
258    // Otherwise:
259    //     throw an OperationError.
260    let tag_length = match normalized_algorithm.tag_length {
261        None => 128,
262        Some(tag_length) if matches!(tag_length, 64 | 96 | 128) => tag_length,
263        _ => {
264            return Err(Error::Operation(Some(
265                "The tagLength member of normalizedAlgorithm is present, \
266                and not one of 64, 96, or 128"
267                    .to_string(),
268            )));
269        },
270    };
271
272    // Step 3. If ciphertext has a length less than tagLength bits, then throw an OperationError.
273    if ciphertext.len() * 8 < tag_length as usize {
274        return Err(Error::Operation(Some(
275            "Ciphertext has a length less than tagLength bits".to_string(),
276        )));
277    }
278
279    // Step 4. Let additionalData be the additionalData member of normalizedAlgorithm if present or
280    // the empty octet string otherwise.
281    let additional_data = normalized_algorithm
282        .additional_data
283        .as_deref()
284        .unwrap_or_default();
285
286    // Step 5. Perform the OCB-DECRYPT function described in Section 4.3 of [RFC7253] using AES as
287    // the block cipher, using the key represented by [[handle]] internal slot of key as the K
288    // input parameter, the iv member of normalizedAlgorithm as the N input parameter,
289    // additionalData as the A input parameter, ciphertext as the C input parameter, and tagLength
290    // as the TAGLEN global parameter.
291    //
292    // If the result of the algorithm is the indication of authentication failure, "INVALID":
293    //     throw an OperationError
294    // Otherwise:
295    //     Let plaintext be the output P of OCB-DECRYPT.
296    //
297    // NOTE: We only support IV(nonce) size from 6 bytes to 15 bytes because of the restriction
298    // from the `ocb3` crate <https://docs.rs/ocb3/latest/ocb3/struct.Ocb3.html>. This range is
299    // suggested in the paper <https://eprint.iacr.org/2023/326.pdf> to prevent an attack.
300    let iv = &normalized_algorithm.iv;
301    let plaintext = match key.handle() {
302        Handle::Aes128Key(key) => match (iv.len(), tag_length) {
303            (6, 64) => ocb_decrypt::<Aes128, U6, U8>(key, ciphertext, iv, additional_data)?,
304            (7, 64) => ocb_decrypt::<Aes128, U7, U8>(key, ciphertext, iv, additional_data)?,
305            (8, 64) => ocb_decrypt::<Aes128, U8, U8>(key, ciphertext, iv, additional_data)?,
306            (9, 64) => ocb_decrypt::<Aes128, U9, U8>(key, ciphertext, iv, additional_data)?,
307            (10, 64) => ocb_decrypt::<Aes128, U10, U8>(key, ciphertext, iv, additional_data)?,
308            (11, 64) => ocb_decrypt::<Aes128, U11, U8>(key, ciphertext, iv, additional_data)?,
309            (12, 64) => ocb_decrypt::<Aes128, U12, U8>(key, ciphertext, iv, additional_data)?,
310            (13, 64) => ocb_decrypt::<Aes128, U13, U8>(key, ciphertext, iv, additional_data)?,
311            (14, 64) => ocb_decrypt::<Aes128, U14, U8>(key, ciphertext, iv, additional_data)?,
312            (15, 64) => ocb_decrypt::<Aes128, U15, U8>(key, ciphertext, iv, additional_data)?,
313
314            (6, 96) => ocb_decrypt::<Aes128, U6, U12>(key, ciphertext, iv, additional_data)?,
315            (7, 96) => ocb_decrypt::<Aes128, U7, U12>(key, ciphertext, iv, additional_data)?,
316            (8, 96) => ocb_decrypt::<Aes128, U8, U12>(key, ciphertext, iv, additional_data)?,
317            (9, 96) => ocb_decrypt::<Aes128, U9, U12>(key, ciphertext, iv, additional_data)?,
318            (10, 96) => ocb_decrypt::<Aes128, U10, U12>(key, ciphertext, iv, additional_data)?,
319            (11, 96) => ocb_decrypt::<Aes128, U11, U12>(key, ciphertext, iv, additional_data)?,
320            (12, 96) => ocb_decrypt::<Aes128, U12, U12>(key, ciphertext, iv, additional_data)?,
321            (13, 96) => ocb_decrypt::<Aes128, U13, U12>(key, ciphertext, iv, additional_data)?,
322            (14, 96) => ocb_decrypt::<Aes128, U14, U12>(key, ciphertext, iv, additional_data)?,
323            (15, 96) => ocb_decrypt::<Aes128, U15, U12>(key, ciphertext, iv, additional_data)?,
324
325            (6, 128) => ocb_decrypt::<Aes128, U6, U16>(key, ciphertext, iv, additional_data)?,
326            (7, 128) => ocb_decrypt::<Aes128, U7, U16>(key, ciphertext, iv, additional_data)?,
327            (8, 128) => ocb_decrypt::<Aes128, U8, U16>(key, ciphertext, iv, additional_data)?,
328            (9, 128) => ocb_decrypt::<Aes128, U9, U16>(key, ciphertext, iv, additional_data)?,
329            (10, 128) => ocb_decrypt::<Aes128, U10, U16>(key, ciphertext, iv, additional_data)?,
330            (11, 128) => ocb_decrypt::<Aes128, U11, U16>(key, ciphertext, iv, additional_data)?,
331            (12, 128) => ocb_decrypt::<Aes128, U12, U16>(key, ciphertext, iv, additional_data)?,
332            (13, 128) => ocb_decrypt::<Aes128, U13, U16>(key, ciphertext, iv, additional_data)?,
333            (14, 128) => ocb_decrypt::<Aes128, U14, U16>(key, ciphertext, iv, additional_data)?,
334            (15, 128) => ocb_decrypt::<Aes128, U15, U16>(key, ciphertext, iv, additional_data)?,
335
336            _ => {
337                return Err(Error::Operation(Some(format!(
338                    "Unsupported IV size ({}-bytes) and/or tag length ({}-bit)",
339                    iv.len(),
340                    tag_length
341                ))));
342            },
343        },
344        Handle::Aes192Key(key) => match (iv.len(), tag_length) {
345            (6, 64) => ocb_decrypt::<Aes192, U6, U8>(key, ciphertext, iv, additional_data)?,
346            (7, 64) => ocb_decrypt::<Aes192, U7, U8>(key, ciphertext, iv, additional_data)?,
347            (8, 64) => ocb_decrypt::<Aes192, U8, U8>(key, ciphertext, iv, additional_data)?,
348            (9, 64) => ocb_decrypt::<Aes192, U9, U8>(key, ciphertext, iv, additional_data)?,
349            (10, 64) => ocb_decrypt::<Aes192, U10, U8>(key, ciphertext, iv, additional_data)?,
350            (11, 64) => ocb_decrypt::<Aes192, U11, U8>(key, ciphertext, iv, additional_data)?,
351            (12, 64) => ocb_decrypt::<Aes192, U12, U8>(key, ciphertext, iv, additional_data)?,
352            (13, 64) => ocb_decrypt::<Aes192, U13, U8>(key, ciphertext, iv, additional_data)?,
353            (14, 64) => ocb_decrypt::<Aes192, U14, U8>(key, ciphertext, iv, additional_data)?,
354            (15, 64) => ocb_decrypt::<Aes192, U15, U8>(key, ciphertext, iv, additional_data)?,
355
356            (6, 96) => ocb_decrypt::<Aes192, U6, U12>(key, ciphertext, iv, additional_data)?,
357            (7, 96) => ocb_decrypt::<Aes192, U7, U12>(key, ciphertext, iv, additional_data)?,
358            (8, 96) => ocb_decrypt::<Aes192, U8, U12>(key, ciphertext, iv, additional_data)?,
359            (9, 96) => ocb_decrypt::<Aes192, U9, U12>(key, ciphertext, iv, additional_data)?,
360            (10, 96) => ocb_decrypt::<Aes192, U10, U12>(key, ciphertext, iv, additional_data)?,
361            (11, 96) => ocb_decrypt::<Aes192, U11, U12>(key, ciphertext, iv, additional_data)?,
362            (12, 96) => ocb_decrypt::<Aes192, U12, U12>(key, ciphertext, iv, additional_data)?,
363            (13, 96) => ocb_decrypt::<Aes192, U13, U12>(key, ciphertext, iv, additional_data)?,
364            (14, 96) => ocb_decrypt::<Aes192, U14, U12>(key, ciphertext, iv, additional_data)?,
365            (15, 96) => ocb_decrypt::<Aes192, U15, U12>(key, ciphertext, iv, additional_data)?,
366
367            (6, 128) => ocb_decrypt::<Aes192, U6, U16>(key, ciphertext, iv, additional_data)?,
368            (7, 128) => ocb_decrypt::<Aes192, U7, U16>(key, ciphertext, iv, additional_data)?,
369            (8, 128) => ocb_decrypt::<Aes192, U8, U16>(key, ciphertext, iv, additional_data)?,
370            (9, 128) => ocb_decrypt::<Aes192, U9, U16>(key, ciphertext, iv, additional_data)?,
371            (10, 128) => ocb_decrypt::<Aes192, U10, U16>(key, ciphertext, iv, additional_data)?,
372            (11, 128) => ocb_decrypt::<Aes192, U11, U16>(key, ciphertext, iv, additional_data)?,
373            (12, 128) => ocb_decrypt::<Aes192, U12, U16>(key, ciphertext, iv, additional_data)?,
374            (13, 128) => ocb_decrypt::<Aes192, U13, U16>(key, ciphertext, iv, additional_data)?,
375            (14, 128) => ocb_decrypt::<Aes192, U14, U16>(key, ciphertext, iv, additional_data)?,
376            (15, 128) => ocb_decrypt::<Aes192, U15, U16>(key, ciphertext, iv, additional_data)?,
377
378            _ => {
379                return Err(Error::Operation(Some(format!(
380                    "Unsupported IV size ({}-bytes) and/or tag length ({}-bit)",
381                    iv.len(),
382                    tag_length
383                ))));
384            },
385        },
386        Handle::Aes256Key(key) => match (iv.len(), tag_length) {
387            (6, 64) => ocb_decrypt::<Aes256, U6, U8>(key, ciphertext, iv, additional_data)?,
388            (7, 64) => ocb_decrypt::<Aes256, U7, U8>(key, ciphertext, iv, additional_data)?,
389            (8, 64) => ocb_decrypt::<Aes256, U8, U8>(key, ciphertext, iv, additional_data)?,
390            (9, 64) => ocb_decrypt::<Aes256, U9, U8>(key, ciphertext, iv, additional_data)?,
391            (10, 64) => ocb_decrypt::<Aes256, U10, U8>(key, ciphertext, iv, additional_data)?,
392            (11, 64) => ocb_decrypt::<Aes256, U11, U8>(key, ciphertext, iv, additional_data)?,
393            (12, 64) => ocb_decrypt::<Aes256, U12, U8>(key, ciphertext, iv, additional_data)?,
394            (13, 64) => ocb_decrypt::<Aes256, U13, U8>(key, ciphertext, iv, additional_data)?,
395            (14, 64) => ocb_decrypt::<Aes256, U14, U8>(key, ciphertext, iv, additional_data)?,
396            (15, 64) => ocb_decrypt::<Aes256, U15, U8>(key, ciphertext, iv, additional_data)?,
397
398            (6, 96) => ocb_decrypt::<Aes256, U6, U12>(key, ciphertext, iv, additional_data)?,
399            (7, 96) => ocb_decrypt::<Aes256, U7, U12>(key, ciphertext, iv, additional_data)?,
400            (8, 96) => ocb_decrypt::<Aes256, U8, U12>(key, ciphertext, iv, additional_data)?,
401            (9, 96) => ocb_decrypt::<Aes256, U9, U12>(key, ciphertext, iv, additional_data)?,
402            (10, 96) => ocb_decrypt::<Aes256, U10, U12>(key, ciphertext, iv, additional_data)?,
403            (11, 96) => ocb_decrypt::<Aes256, U11, U12>(key, ciphertext, iv, additional_data)?,
404            (12, 96) => ocb_decrypt::<Aes256, U12, U12>(key, ciphertext, iv, additional_data)?,
405            (13, 96) => ocb_decrypt::<Aes256, U13, U12>(key, ciphertext, iv, additional_data)?,
406            (14, 96) => ocb_decrypt::<Aes256, U14, U12>(key, ciphertext, iv, additional_data)?,
407            (15, 96) => ocb_decrypt::<Aes256, U15, U12>(key, ciphertext, iv, additional_data)?,
408
409            (6, 128) => ocb_decrypt::<Aes256, U6, U16>(key, ciphertext, iv, additional_data)?,
410            (7, 128) => ocb_decrypt::<Aes256, U7, U16>(key, ciphertext, iv, additional_data)?,
411            (8, 128) => ocb_decrypt::<Aes256, U8, U16>(key, ciphertext, iv, additional_data)?,
412            (9, 128) => ocb_decrypt::<Aes256, U9, U16>(key, ciphertext, iv, additional_data)?,
413            (10, 128) => ocb_decrypt::<Aes256, U10, U16>(key, ciphertext, iv, additional_data)?,
414            (11, 128) => ocb_decrypt::<Aes256, U11, U16>(key, ciphertext, iv, additional_data)?,
415            (12, 128) => ocb_decrypt::<Aes256, U12, U16>(key, ciphertext, iv, additional_data)?,
416            (13, 128) => ocb_decrypt::<Aes256, U13, U16>(key, ciphertext, iv, additional_data)?,
417            (14, 128) => ocb_decrypt::<Aes256, U14, U16>(key, ciphertext, iv, additional_data)?,
418            (15, 128) => ocb_decrypt::<Aes256, U15, U16>(key, ciphertext, iv, additional_data)?,
419
420            _ => {
421                return Err(Error::Operation(Some(format!(
422                    "Unsupported IV size ({}-bytes) and/or tag length ({}-bit)",
423                    iv.len(),
424                    tag_length
425                ))));
426            },
427        },
428        _ => {
429            return Err(Error::Operation(Some(
430                "The key handle is not representing an AES key".to_string(),
431            )));
432        },
433    };
434
435    // Step 6. Return plaintext.
436    Ok(plaintext)
437}
438
439/// Helper for Step 5 of <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-decrypt>
440fn ocb_decrypt<Cipher, NonceSize, TagSize>(
441    key: &Key<Cipher>,
442    ciphertext: &[u8],
443    iv: &[u8],
444    additional_data: &[u8],
445) -> Result<Vec<u8>, Error>
446where
447    Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt + KeyInit + BlockDecrypt,
448    NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
449    GrEq<NonceSize, U6>: NonZero,
450    LeEq<NonceSize, U15>: NonZero,
451    TagSize: ArrayLength<u8> + NonZero + IsLessOrEqual<U16>,
452    LeEq<TagSize, U16>: NonZero,
453{
454    let mut plaintext = ciphertext.to_vec();
455    let mut cipher = Ocb3::<Cipher, NonceSize, TagSize>::new(key);
456    cipher
457        .decrypt_in_place(Nonce::from_slice(iv), additional_data, &mut plaintext)
458        .map_err(|_| {
459            Error::Operation(Some("AES-OCB authenticated decryption failed".to_string()))
460        })?;
461    Ok(plaintext)
462}
463
464/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-generate-key>
465pub(crate) fn generate_key(
466    global: &GlobalScope,
467    normalized_algorithm: &SubtleAesKeyGenParams,
468    extractable: bool,
469    usages: Vec<KeyUsage>,
470    can_gc: CanGc,
471) -> Result<DomRoot<CryptoKey>, Error> {
472    aes_common::generate_key(
473        AesAlgorithm::AesOcb,
474        global,
475        normalized_algorithm,
476        extractable,
477        usages,
478        can_gc,
479    )
480}
481
482/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-import-key>
483pub(crate) fn import_key(
484    global: &GlobalScope,
485    format: KeyFormat,
486    key_data: &[u8],
487    extractable: bool,
488    usages: Vec<KeyUsage>,
489    can_gc: CanGc,
490) -> Result<DomRoot<CryptoKey>, Error> {
491    // Step 1. Let keyData be the key data to be imported.
492
493    // Step 2. If usages contains an entry which is not one of "encrypt", "decrypt", "wrapKey" or
494    // "unwrapKey", then throw a SyntaxError.
495    if usages.iter().any(|usage| {
496        !matches!(
497            usage,
498            KeyUsage::Encrypt | KeyUsage::Decrypt | KeyUsage::WrapKey | KeyUsage::UnwrapKey
499        )
500    }) {
501        return Err(Error::Syntax(Some(
502            "Usages contains an entry which is not one of \"encrypt\", \"decrypt\", \"wrapKey\" \
503            or \"unwrapKey\""
504                .to_string(),
505        )));
506    }
507
508    // Step 3.
509    let data = aes_common::import_key_from_key_data(
510        AesAlgorithm::AesOcb,
511        format,
512        key_data,
513        extractable,
514        &usages,
515    )?;
516
517    // Step 4. Let key be a new CryptoKey object representing an AES key with value data.
518    // Step 5. Let algorithm be a new AesKeyAlgorithm.
519    // Step 6. Set the name attribute of algorithm to "AES-OCB".
520    // Step 7. Set the length attribute of algorithm to the length, in bits, of data.
521    // Step 8. Set the [[algorithm]] internal slot of key to algorithm.
522    let handle = match data.len() {
523        16 => Handle::Aes128Key(Key::<Aes128>::clone_from_slice(&data)),
524        24 => Handle::Aes192Key(Key::<Aes192>::clone_from_slice(&data)),
525        32 => Handle::Aes256Key(Key::<Aes256>::clone_from_slice(&data)),
526        _ => {
527            return Err(Error::Data(Some(
528                "The length in bits of key is not 128, 192 or 256".to_string(),
529            )));
530        },
531    };
532    let algorithm = SubtleAesKeyAlgorithm {
533        name: ALG_AES_OCB.to_string(),
534        length: data.len() as u16 * 8,
535    };
536    let key = CryptoKey::new(
537        global,
538        KeyType::Secret,
539        extractable,
540        KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm),
541        usages,
542        handle,
543        can_gc,
544    );
545
546    // Step 9. Return key.
547    Ok(key)
548}
549
550/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-export-key>
551pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
552    aes_common::export_key(AesAlgorithm::AesOcb, format, key)
553}
554
555/// <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-operations-get-key-length>
556pub(crate) fn get_key_length(
557    normalized_derived_key_algorithm: &SubtleAesDerivedKeyParams,
558) -> Result<Option<u32>, Error> {
559    aes_common::get_key_length(normalized_derived_key_algorithm)
560}