script/dom/subtlecrypto/
aes_kw_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 aes_kw::Kek;
8
9use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{KeyType, KeyUsage};
10use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::KeyFormat;
11use crate::dom::bindings::error::Error;
12use crate::dom::bindings::root::DomRoot;
13use crate::dom::cryptokey::{CryptoKey, Handle};
14use crate::dom::globalscope::GlobalScope;
15use crate::dom::subtlecrypto::aes_common::AesAlgorithm;
16use crate::dom::subtlecrypto::{
17    ALG_AES_KW, ExportedKey, KeyAlgorithmAndDerivatives, SubtleAesDerivedKeyParams,
18    SubtleAesKeyAlgorithm, SubtleAesKeyGenParams, aes_common,
19};
20use crate::script_runtime::CanGc;
21
22/// <https://w3c.github.io/webcrypto/#aes-kw-operations-wrap-key>
23pub(crate) fn wrap_key(key: &CryptoKey, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
24    // Step 1. If plaintext is not a multiple of 64 bits in length, then throw an OperationError.
25    if plaintext.len() % 8 != 0 {
26        return Err(Error::Operation(Some(
27            "The plaintext bit-length is not a multiple of 64".into(),
28        )));
29    }
30
31    // Step 2. Let ciphertext be the result of performing the Key Wrap operation described in
32    // Section 2.2.1 of [RFC3394] with plaintext as the plaintext to be wrapped and using the
33    // default Initial Value defined in Section 2.2.3.1 of the same document.
34    let ciphertext = match key.handle() {
35        Handle::Aes128Key(key) => {
36            let kek = Kek::<Aes128>::new(key);
37            kek.wrap_vec(plaintext).map_err(|_| {
38                Error::Operation(Some(
39                    "AES-KW failed to perform the Key Wrap operation".to_string(),
40                ))
41            })?
42        },
43        Handle::Aes192Key(key) => {
44            let kek = Kek::<Aes192>::new(key);
45            kek.wrap_vec(plaintext).map_err(|_| {
46                Error::Operation(Some(
47                    "AES-KW failed to perform the Key Wrap operation".to_string(),
48                ))
49            })?
50        },
51        Handle::Aes256Key(key) => {
52            let kek = Kek::<Aes256>::new(key);
53            kek.wrap_vec(plaintext).map_err(|_| {
54                Error::Operation(Some(
55                    "AES-KW failed to perform the Key Wrap operation".to_string(),
56                ))
57            })?
58        },
59        _ => {
60            return Err(Error::Operation(Some(
61                "The key handle is not representing an AES key".to_string(),
62            )));
63        },
64    };
65
66    // Step 3. Return ciphertext.
67    Ok(ciphertext)
68}
69
70/// <https://w3c.github.io/webcrypto/#aes-kw-operations-unwrap-key>
71pub(crate) fn unwrap_key(key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
72    // Step 1. Let plaintext be the result of performing the Key Unwrap operation described in
73    // Section 2.2.2 of [RFC3394] with ciphertext as the input ciphertext and using the default
74    // Initial Value defined in Section 2.2.3.1 of the same document.
75    // Step 2. If the Key Unwrap operation returns an error, then throw an OperationError.
76    let plaintext = match key.handle() {
77        Handle::Aes128Key(key) => {
78            let kek = Kek::<Aes128>::new(key);
79            kek.unwrap_vec(ciphertext).map_err(|_| {
80                Error::Operation(Some(
81                    "AES-KW failed to perform the Key Unwrap operation".to_string(),
82                ))
83            })?
84        },
85        Handle::Aes192Key(key) => {
86            let kek = Kek::<Aes192>::new(key);
87            kek.unwrap_vec(ciphertext).map_err(|_| {
88                Error::Operation(Some(
89                    "AES-KW failed to perform the Key Unwrap operation".to_string(),
90                ))
91            })?
92        },
93        Handle::Aes256Key(key) => {
94            let kek = Kek::<Aes256>::new(key);
95            kek.unwrap_vec(ciphertext).map_err(|_| {
96                Error::Operation(Some(
97                    "AES-KW failed to perform the Key Unwrap operation".to_string(),
98                ))
99            })?
100        },
101        _ => {
102            return Err(Error::Operation(Some(
103                "The key handle is not representing an AES key".to_string(),
104            )));
105        },
106    };
107
108    // Step 3. Return plaintext.
109    Ok(plaintext)
110}
111
112/// <https://w3c.github.io/webcrypto/#aes-kw-operations-generate-key>
113pub(crate) fn generate_key(
114    global: &GlobalScope,
115    normalized_algorithm: &SubtleAesKeyGenParams,
116    extractable: bool,
117    usages: Vec<KeyUsage>,
118    can_gc: CanGc,
119) -> Result<DomRoot<CryptoKey>, Error> {
120    aes_common::generate_key(
121        AesAlgorithm::AesKw,
122        global,
123        normalized_algorithm,
124        extractable,
125        usages,
126        can_gc,
127    )
128}
129
130/// <https://w3c.github.io/webcrypto/#aes-kw-operations-import-key>
131pub(crate) fn import_key(
132    global: &GlobalScope,
133    format: KeyFormat,
134    key_data: &[u8],
135    extractable: bool,
136    usages: Vec<KeyUsage>,
137    can_gc: CanGc,
138) -> Result<DomRoot<CryptoKey>, Error> {
139    // Step 1. Let keyData be the key data to be imported.
140
141    // Step 2. If usages contains an entry which is not one of "encrypt", "decrypt", "wrapKey" or
142    // "unwrapKey", then throw a SyntaxError.
143    if usages.iter().any(|usage| {
144        !matches!(
145            usage,
146            KeyUsage::Encrypt | KeyUsage::Decrypt | KeyUsage::WrapKey | KeyUsage::UnwrapKey
147        )
148    }) {
149        return Err(Error::Syntax(Some(
150            "Usages contains an entry which is not one of \"encrypt\", \"decrypt\", \"wrapKey\" \
151            or \"unwrapKey\""
152                .to_string(),
153        )));
154    }
155
156    // Step 3.
157    let data = aes_common::import_key_from_key_data(
158        AesAlgorithm::AesKw,
159        format,
160        key_data,
161        extractable,
162        &usages,
163    )?;
164
165    // Step 4. Let key be a new CryptoKey object representing an AES key with value data.
166    // Step 5. Let algorithm be a new AesKeyAlgorithm.
167    // Step 6. Set the name attribute of algorithm to "AES-KW".
168    // Step 7. Set the length attribute of algorithm to the length, in bits, of data.
169    // Step 8. Set the [[algorithm]] internal slot of key to algorithm.
170    let handle = match data.len() {
171        16 => Handle::Aes128Key(Key::<Aes128>::clone_from_slice(&data)),
172        24 => Handle::Aes192Key(Key::<Aes192>::clone_from_slice(&data)),
173        32 => Handle::Aes256Key(Key::<Aes256>::clone_from_slice(&data)),
174        _ => {
175            return Err(Error::Data(Some(
176                "The length in bits of data is not 128, 192 or 256".to_string(),
177            )));
178        },
179    };
180    let algorithm = SubtleAesKeyAlgorithm {
181        name: ALG_AES_KW.to_string(),
182        length: data.len() as u16 * 8,
183    };
184    let key = CryptoKey::new(
185        global,
186        KeyType::Secret,
187        extractable,
188        KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm),
189        usages,
190        handle,
191        can_gc,
192    );
193
194    // Step 9. Return key.
195    Ok(key)
196}
197
198/// <https://w3c.github.io/webcrypto/#aes-kw-operations-export-key>
199pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
200    aes_common::export_key(AesAlgorithm::AesKw, format, key)
201}
202
203/// <https://w3c.github.io/webcrypto/#aes-kw-operations-get-key-length>
204pub(crate) fn get_key_length(
205    normalized_derived_key_algorithm: &SubtleAesDerivedKeyParams,
206) -> Result<Option<u32>, Error> {
207    aes_common::get_key_length(normalized_derived_key_algorithm)
208}