script/dom/subtlecrypto/
aes_ctr_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::{Aes128, Aes192, Aes256};
6use cipher::{KeyIvInit, StreamCipher};
7use ctr::Ctr128BE;
8use js::context::JSContext;
9
10use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::KeyUsage;
11use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::KeyFormat;
12use crate::dom::bindings::error::Error;
13use crate::dom::bindings::root::DomRoot;
14use crate::dom::cryptokey::{CryptoKey, Handle};
15use crate::dom::globalscope::GlobalScope;
16use crate::dom::subtlecrypto::aes_common::AesAlgorithm;
17use crate::dom::subtlecrypto::{
18    ExportedKey, SubtleAesCtrParams, SubtleAesDerivedKeyParams, SubtleAesKeyGenParams, aes_common,
19};
20
21/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-encrypt>
22pub(crate) fn encrypt(
23    normalized_algorithm: &SubtleAesCtrParams,
24    key: &CryptoKey,
25    plaintext: &[u8],
26) -> Result<Vec<u8>, Error> {
27    // Step 1. If the counter member of normalizedAlgorithm does not have a length of 16 bytes,
28    // then throw an OperationError.
29    if normalized_algorithm.counter.len() != 16 {
30        return Err(Error::Operation(Some(
31            "The initial counter block length is not 16 bytes".into(),
32        )));
33    }
34
35    // Step 2. If the length member of normalizedAlgorithm is zero or is greater than 128, then
36    // throw an OperationError.
37    if normalized_algorithm.length == 0 {
38        return Err(Error::Operation(Some("The counter length is zero".into())));
39    }
40    if normalized_algorithm.length > 128 {
41        return Err(Error::Operation(Some(
42            "The counter length is greater than 128".into(),
43        )));
44    }
45
46    // Step 3. Let ciphertext be the result of performing the CTR Encryption operation described in
47    // Section 6.5 of [NIST-SP800-38A] using AES as the block cipher, the counter member of
48    // normalizedAlgorithm as the initial value of the counter block, the length member of
49    // normalizedAlgorithm as the input parameter m to the standard counter block incrementing
50    // function defined in Appendix B.1 of [NIST-SP800-38A] and plaintext as the input plaintext.
51    let iv = normalized_algorithm.counter.as_slice();
52    let mut ciphertext = plaintext.to_vec();
53    match key.handle() {
54        Handle::Aes128Key(key) => {
55            let mut cipher = Ctr128BE::<Aes128>::new(key, iv.into());
56            cipher.apply_keystream(&mut ciphertext);
57        },
58        Handle::Aes192Key(key) => {
59            let mut cipher = Ctr128BE::<Aes192>::new(key, iv.into());
60            cipher.apply_keystream(&mut ciphertext);
61        },
62        Handle::Aes256Key(key) => {
63            let mut cipher = Ctr128BE::<Aes256>::new(key, iv.into());
64            cipher.apply_keystream(&mut ciphertext);
65        },
66        _ => {
67            return Err(Error::Operation(Some(
68                "The key handle is not representing an AES key".to_string(),
69            )));
70        },
71    };
72
73    // Step 4. Return ciphertext.
74    Ok(ciphertext)
75}
76
77/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-decrypt>
78pub(crate) fn decrypt(
79    normalized_algorithm: &SubtleAesCtrParams,
80    key: &CryptoKey,
81    ciphertext: &[u8],
82) -> Result<Vec<u8>, Error> {
83    // Step 1. If the counter member of normalizedAlgorithm does not have a length of 16 bytes,
84    // then throw an OperationError.
85    if normalized_algorithm.counter.len() != 16 {
86        return Err(Error::Operation(Some(
87            "The initial counter block length is not 16 bytes".into(),
88        )));
89    }
90
91    // Step 2. If the length member of normalizedAlgorithm is zero or is greater than 128, then
92    // throw an OperationError.
93    if normalized_algorithm.length == 0 {
94        return Err(Error::Operation(Some("The counter length is zero".into())));
95    }
96    if normalized_algorithm.length > 128 {
97        return Err(Error::Operation(Some(
98            "The counter length is greater than 128".into(),
99        )));
100    }
101
102    // Step 3. Let plaintext be the result of performing the CTR Decryption operation described in
103    // Section 6.5 of [NIST-SP800-38A] using AES as the block cipher, the counter member of
104    // normalizedAlgorithm as the initial value of the counter block, the length member of
105    // normalizedAlgorithm as the input parameter m to the standard counter block incrementing
106    // function defined in Appendix B.1 of [NIST-SP800-38A] and ciphertext as the input ciphertext.
107    let iv = normalized_algorithm.counter.as_slice();
108    let mut plaintext = ciphertext.to_vec();
109    match key.handle() {
110        Handle::Aes128Key(key) => {
111            let mut cipher = Ctr128BE::<Aes128>::new(key, iv.into());
112            cipher.apply_keystream(&mut plaintext);
113        },
114        Handle::Aes192Key(key) => {
115            let mut cipher = Ctr128BE::<Aes192>::new(key, iv.into());
116            cipher.apply_keystream(&mut plaintext);
117        },
118        Handle::Aes256Key(key) => {
119            let mut cipher = Ctr128BE::<Aes256>::new(key, iv.into());
120            cipher.apply_keystream(&mut plaintext);
121        },
122        _ => {
123            return Err(Error::Operation(Some(
124                "The key handle is not representing an AES key".to_string(),
125            )));
126        },
127    };
128
129    // Step 4. Return plaintext.
130    Ok(plaintext)
131}
132
133/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-generate-key>
134pub(crate) fn generate_key(
135    cx: &mut JSContext,
136    global: &GlobalScope,
137    normalized_algorithm: &SubtleAesKeyGenParams,
138    extractable: bool,
139    usages: Vec<KeyUsage>,
140) -> Result<DomRoot<CryptoKey>, Error> {
141    aes_common::generate_key(
142        AesAlgorithm::AesCtr,
143        cx,
144        global,
145        normalized_algorithm,
146        extractable,
147        usages,
148    )
149}
150
151/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-import-key>
152pub(crate) fn import_key(
153    cx: &mut JSContext,
154    global: &GlobalScope,
155    format: KeyFormat,
156    key_data: &[u8],
157    extractable: bool,
158    usages: Vec<KeyUsage>,
159) -> Result<DomRoot<CryptoKey>, Error> {
160    aes_common::import_key(
161        AesAlgorithm::AesCtr,
162        cx,
163        global,
164        format,
165        key_data,
166        extractable,
167        usages,
168    )
169}
170
171/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-export-key>
172pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
173    aes_common::export_key(AesAlgorithm::AesCtr, format, key)
174}
175
176/// <https://w3c.github.io/webcrypto/#aes-ctr-operations-get-key-length>
177pub(crate) fn get_key_length(
178    normalized_derived_key_algorithm: &SubtleAesDerivedKeyParams,
179) -> Result<Option<u32>, Error> {
180    aes_common::get_key_length(normalized_derived_key_algorithm)
181}