Skip to main content

script_webcrypto/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_kw::{KeyInit, KwAes128, KwAes192, KwAes256};
6use js::context::JSContext;
7use script_bindings::codegen::GenericBindings::CryptoKeyBinding::KeyUsage;
8use script_bindings::codegen::GenericBindings::SubtleCryptoBinding::KeyFormat;
9use script_bindings::error::Error;
10use script_bindings::root::DomRoot;
11use zeroize::Zeroizing;
12
13use crate::cryptokey::{CryptoKey, Handle};
14use crate::subtlecrypto::aes_common::AesAlgorithm;
15use crate::subtlecrypto::{AesDerivedKeyParams, AesKeyGenParams, ExportedKey, aes_common};
16use crate::traits::Equivalence;
17
18/// <https://w3c.github.io/webcrypto/#aes-kw-operations-wrap-key>
19pub(crate) fn wrap_key<D: Equivalence>(
20    key: &CryptoKey<D>,
21    plaintext: &[u8],
22) -> Result<Vec<u8>, Error> {
23    // Step 1. If plaintext is not a multiple of 64 bits in length, then throw an OperationError.
24    if !plaintext.len().is_multiple_of(8) {
25        return Err(Error::Operation(Some(
26            "The plaintext bit-length is not a multiple of 64".into(),
27        )));
28    }
29
30    // Step 2. Let ciphertext be the result of performing the Key Wrap operation described in
31    // Section 2.2.1 of [RFC3394] with plaintext as the plaintext to be wrapped and using the
32    // default Initial Value defined in Section 2.2.3.1 of the same document.
33    // NOTE: The length of buffer must be greater or equal to length of plaintext plus 8 bytes.
34    let mut buffer = vec![0u8; plaintext.len() + 8];
35    let ciphertext = match key.handle() {
36        Handle::Aes128Key(key) => {
37            let key_wrapper = KwAes128::new(key);
38            key_wrapper.wrap_key(plaintext, &mut buffer)
39        },
40        Handle::Aes192Key(key) => {
41            let key_wrapper = KwAes192::new(key);
42            key_wrapper.wrap_key(plaintext, &mut buffer)
43        },
44        Handle::Aes256Key(key) => {
45            let key_wrapper = KwAes256::new(key);
46            key_wrapper.wrap_key(plaintext, &mut buffer)
47        },
48        _ => {
49            return Err(Error::Operation(Some(
50                "The key handle is not representing an AES key".to_string(),
51            )));
52        },
53    }
54    .map_err(|_| {
55        Error::Operation(Some(
56            "AES-KW failed to perform the Key Wrap operation".into(),
57        ))
58    })?;
59
60    // Step 3. Return ciphertext.
61    Ok(ciphertext.to_vec())
62}
63
64/// <https://w3c.github.io/webcrypto/#aes-kw-operations-unwrap-key>
65pub(crate) fn unwrap_key<D: Equivalence>(
66    key: &CryptoKey<D>,
67    ciphertext: &[u8],
68) -> Result<Vec<u8>, Error> {
69    // Step 1. Let plaintext be the result of performing the Key Unwrap operation described in
70    // Section 2.2.2 of [RFC3394] with ciphertext as the input ciphertext and using the default
71    // Initial Value defined in Section 2.2.3.1 of the same document.
72    // Step 2. If the Key Unwrap operation returns an error, then throw an OperationError.
73    let mut buffer = Zeroizing::new(vec![0u8; ciphertext.len()]);
74    let plaintext = match key.handle() {
75        Handle::Aes128Key(key) => {
76            let key_unwrapper = KwAes128::new(key);
77            key_unwrapper.unwrap_key(ciphertext, &mut buffer)
78        },
79        Handle::Aes192Key(key) => {
80            let key_unwrapper = KwAes192::new(key);
81            key_unwrapper.unwrap_key(ciphertext, &mut buffer)
82        },
83        Handle::Aes256Key(key) => {
84            let key_unwrapper = KwAes256::new(key);
85            key_unwrapper.unwrap_key(ciphertext, &mut buffer)
86        },
87        _ => {
88            return Err(Error::Operation(Some(
89                "The key handle is not representing an AES key".to_string(),
90            )));
91        },
92    }
93    .map_err(|_| {
94        Error::Operation(Some(
95            "AES-KW failed to perform the Key Unwrap operation".into(),
96        ))
97    })?;
98
99    // Step 3. Return plaintext.
100    Ok(plaintext.to_vec())
101}
102
103/// <https://w3c.github.io/webcrypto/#aes-kw-operations-generate-key>
104pub(crate) fn generate_key<D: Equivalence>(
105    cx: &mut JSContext,
106    global: &D::GlobalScope,
107    normalized_algorithm: &AesKeyGenParams,
108    extractable: bool,
109    usages: Vec<KeyUsage>,
110) -> Result<DomRoot<CryptoKey<D>>, Error> {
111    aes_common::generate_key(
112        cx,
113        global,
114        AesAlgorithm::AesKw,
115        normalized_algorithm,
116        extractable,
117        usages,
118    )
119}
120
121/// <https://w3c.github.io/webcrypto/#aes-kw-operations-import-key>
122pub(crate) fn import_key<D: Equivalence>(
123    cx: &mut JSContext,
124    global: &D::GlobalScope,
125    format: KeyFormat,
126    key_data: &[u8],
127    extractable: bool,
128    usages: Vec<KeyUsage>,
129) -> Result<DomRoot<CryptoKey<D>>, Error> {
130    aes_common::import_key(
131        cx,
132        global,
133        AesAlgorithm::AesKw,
134        format,
135        key_data,
136        extractable,
137        usages,
138    )
139}
140
141/// <https://w3c.github.io/webcrypto/#aes-kw-operations-export-key>
142pub(crate) fn export_key<D: Equivalence>(
143    format: KeyFormat,
144    key: &CryptoKey<D>,
145) -> Result<ExportedKey, Error> {
146    aes_common::export_key(AesAlgorithm::AesKw, format, key)
147}
148
149/// <https://w3c.github.io/webcrypto/#aes-kw-operations-get-key-length>
150pub(crate) fn get_key_length(
151    normalized_derived_key_algorithm: &AesDerivedKeyParams,
152) -> Result<Option<u32>, Error> {
153    aes_common::get_key_length(normalized_derived_key_algorithm)
154}