Skip to main content

jwt_simple/algorithms/jwe/
aes_kw.rs

1//! AES Key Wrap algorithms for JWE.
2//!
3//! Implements A256KW and A128KW (AES Key Wrap as per RFC 3394).
4
5#[cfg(any(feature = "pure-rust", target_arch = "wasm32", target_arch = "wasm64"))]
6use superboring as boring;
7
8use boring::aes::{unwrap_key, wrap_key, AesKey};
9use rand::Rng;
10use serde::{de::DeserializeOwned, Serialize};
11use zeroize::Zeroize;
12
13use crate::claims::*;
14use crate::error::*;
15use crate::jwe_header::JWEHeader;
16use crate::jwe_token::{DecryptionOptions, EncryptionOptions, JWEToken, JWETokenMetadata};
17
18/// AES-256 Key Wrap key for JWE.
19///
20/// This is a symmetric key that can both encrypt and decrypt JWE tokens.
21#[derive(Clone)]
22pub struct A256KWKey {
23    key: Vec<u8>,
24    key_id: Option<String>,
25}
26
27impl std::fmt::Debug for A256KWKey {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        f.debug_struct("A256KWKey")
30            .field("key_id", &self.key_id)
31            .finish_non_exhaustive()
32    }
33}
34
35impl Drop for A256KWKey {
36    fn drop(&mut self) {
37        self.key.zeroize();
38    }
39}
40
41impl A256KWKey {
42    const KEY_SIZE: usize = 32;
43    const ALG_NAME: &'static str = "A256KW";
44
45    /// Create a key from raw bytes.
46    ///
47    /// The key must be exactly 32 bytes (256 bits).
48    pub fn from_bytes(key: &[u8]) -> Result<Self, Error> {
49        ensure!(key.len() == Self::KEY_SIZE, JWTError::InvalidEncryptionKey);
50        Ok(A256KWKey {
51            key: key.to_vec(),
52            key_id: None,
53        })
54    }
55
56    /// Generate a random key.
57    pub fn generate() -> Self {
58        let mut key = vec![0u8; Self::KEY_SIZE];
59        rand::rng().fill_bytes(&mut key);
60        A256KWKey { key, key_id: None }
61    }
62
63    /// Export the key as raw bytes.
64    pub fn to_bytes(&self) -> Vec<u8> {
65        self.key.clone()
66    }
67
68    /// Set the key ID.
69    pub fn with_key_id(mut self, key_id: impl Into<String>) -> Self {
70        self.key_id = Some(key_id.into());
71        self
72    }
73
74    /// Get the key ID.
75    pub fn key_id(&self) -> Option<&str> {
76        self.key_id.as_deref()
77    }
78
79    pub(crate) fn wrap_key(&self, cek: &[u8]) -> Result<Vec<u8>, Error> {
80        let aes_key = AesKey::new_encrypt(&self.key).map_err(|_| JWTError::InvalidEncryptionKey)?;
81
82        // Output is 8 bytes larger than input (for IV)
83        let mut wrapped = vec![0u8; cek.len() + 8];
84        wrap_key(&aes_key, None, &mut wrapped, cek).map_err(|_| JWTError::InvalidEncryptionKey)?;
85
86        Ok(wrapped)
87    }
88
89    pub(crate) fn unwrap_key(&self, wrapped: &[u8]) -> Result<Vec<u8>, Error> {
90        ensure!(wrapped.len() >= 16, JWTError::KeyUnwrapFailed);
91
92        let aes_key = AesKey::new_decrypt(&self.key).map_err(|_| JWTError::InvalidEncryptionKey)?;
93
94        // Output is 8 bytes smaller than input
95        let mut cek = vec![0u8; wrapped.len() - 8];
96        unwrap_key(&aes_key, None, &mut cek, wrapped).map_err(|_| JWTError::KeyUnwrapFailed)?;
97
98        Ok(cek)
99    }
100
101    /// Encrypt claims into a JWE token.
102    pub fn encrypt<CustomClaims: Serialize>(
103        &self,
104        claims: JWTClaims<CustomClaims>,
105    ) -> Result<String, Error> {
106        self.encrypt_with_options(claims, &EncryptionOptions::default())
107    }
108
109    /// Encrypt claims into a JWE token with options.
110    pub fn encrypt_with_options<CustomClaims: Serialize>(
111        &self,
112        claims: JWTClaims<CustomClaims>,
113        options: &EncryptionOptions,
114    ) -> Result<String, Error> {
115        let content_encryption = options.content_encryption;
116        let mut header = JWEHeader::new(Self::ALG_NAME, content_encryption.alg_name());
117
118        if let Some(key_id) = &self.key_id {
119            header.key_id = Some(key_id.clone());
120        }
121        if let Some(key_id) = &options.key_id {
122            header.key_id = Some(key_id.clone());
123        }
124        if let Some(cty) = &options.content_type {
125            header.content_type = Some(cty.clone());
126        }
127
128        JWEToken::build_from_claims(&header, &claims, content_encryption, |cek| {
129            self.wrap_key(cek)
130        })
131    }
132
133    /// Decrypt a JWE token and return the claims.
134    pub fn decrypt_token<CustomClaims: DeserializeOwned>(
135        &self,
136        token: &str,
137        options: Option<DecryptionOptions>,
138    ) -> Result<JWTClaims<CustomClaims>, Error> {
139        JWEToken::decrypt(Self::ALG_NAME, token, options, |_header, encrypted_key| {
140            self.unwrap_key(encrypted_key)
141        })
142    }
143
144    /// Decode token metadata without decrypting.
145    pub fn decode_metadata(token: &str) -> Result<JWETokenMetadata, Error> {
146        JWEToken::decode_metadata(token)
147    }
148}
149
150/// AES-128 Key Wrap key for JWE.
151///
152/// This is a symmetric key that can both encrypt and decrypt JWE tokens.
153/// Note: A256KW is preferred for new applications.
154#[derive(Clone)]
155pub struct A128KWKey {
156    key: Vec<u8>,
157    key_id: Option<String>,
158}
159
160impl std::fmt::Debug for A128KWKey {
161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162        f.debug_struct("A128KWKey")
163            .field("key_id", &self.key_id)
164            .finish_non_exhaustive()
165    }
166}
167
168impl Drop for A128KWKey {
169    fn drop(&mut self) {
170        self.key.zeroize();
171    }
172}
173
174impl A128KWKey {
175    const KEY_SIZE: usize = 16;
176    const ALG_NAME: &'static str = "A128KW";
177
178    /// Create a key from raw bytes.
179    ///
180    /// The key must be exactly 16 bytes (128 bits).
181    pub fn from_bytes(key: &[u8]) -> Result<Self, Error> {
182        ensure!(key.len() == Self::KEY_SIZE, JWTError::InvalidEncryptionKey);
183        Ok(A128KWKey {
184            key: key.to_vec(),
185            key_id: None,
186        })
187    }
188
189    /// Generate a random key.
190    pub fn generate() -> Self {
191        let mut key = vec![0u8; Self::KEY_SIZE];
192        rand::rng().fill_bytes(&mut key);
193        A128KWKey { key, key_id: None }
194    }
195
196    /// Export the key as raw bytes.
197    pub fn to_bytes(&self) -> Vec<u8> {
198        self.key.clone()
199    }
200
201    /// Set the key ID.
202    pub fn with_key_id(mut self, key_id: impl Into<String>) -> Self {
203        self.key_id = Some(key_id.into());
204        self
205    }
206
207    /// Get the key ID.
208    pub fn key_id(&self) -> Option<&str> {
209        self.key_id.as_deref()
210    }
211
212    pub(crate) fn wrap_key(&self, cek: &[u8]) -> Result<Vec<u8>, Error> {
213        let aes_key = AesKey::new_encrypt(&self.key).map_err(|_| JWTError::InvalidEncryptionKey)?;
214
215        // Output is 8 bytes larger than input (for IV)
216        let mut wrapped = vec![0u8; cek.len() + 8];
217        wrap_key(&aes_key, None, &mut wrapped, cek).map_err(|_| JWTError::InvalidEncryptionKey)?;
218
219        Ok(wrapped)
220    }
221
222    pub(crate) fn unwrap_key(&self, wrapped: &[u8]) -> Result<Vec<u8>, Error> {
223        ensure!(wrapped.len() >= 16, JWTError::KeyUnwrapFailed);
224
225        let aes_key = AesKey::new_decrypt(&self.key).map_err(|_| JWTError::InvalidEncryptionKey)?;
226
227        // Output is 8 bytes smaller than input
228        let mut cek = vec![0u8; wrapped.len() - 8];
229        unwrap_key(&aes_key, None, &mut cek, wrapped).map_err(|_| JWTError::KeyUnwrapFailed)?;
230
231        Ok(cek)
232    }
233
234    /// Encrypt claims into a JWE token.
235    pub fn encrypt<CustomClaims: Serialize>(
236        &self,
237        claims: JWTClaims<CustomClaims>,
238    ) -> Result<String, Error> {
239        self.encrypt_with_options(claims, &EncryptionOptions::default())
240    }
241
242    /// Encrypt claims into a JWE token with options.
243    pub fn encrypt_with_options<CustomClaims: Serialize>(
244        &self,
245        claims: JWTClaims<CustomClaims>,
246        options: &EncryptionOptions,
247    ) -> Result<String, Error> {
248        let content_encryption = options.content_encryption;
249        let mut header = JWEHeader::new(Self::ALG_NAME, content_encryption.alg_name());
250
251        if let Some(key_id) = &self.key_id {
252            header.key_id = Some(key_id.clone());
253        }
254        if let Some(key_id) = &options.key_id {
255            header.key_id = Some(key_id.clone());
256        }
257        if let Some(cty) = &options.content_type {
258            header.content_type = Some(cty.clone());
259        }
260
261        JWEToken::build_from_claims(&header, &claims, content_encryption, |cek| {
262            self.wrap_key(cek)
263        })
264    }
265
266    /// Decrypt a JWE token and return the claims.
267    pub fn decrypt_token<CustomClaims: DeserializeOwned>(
268        &self,
269        token: &str,
270        options: Option<DecryptionOptions>,
271    ) -> Result<JWTClaims<CustomClaims>, Error> {
272        JWEToken::decrypt(Self::ALG_NAME, token, options, |_header, encrypted_key| {
273            self.unwrap_key(encrypted_key)
274        })
275    }
276
277    /// Decode token metadata without decrypting.
278    pub fn decode_metadata(token: &str) -> Result<JWETokenMetadata, Error> {
279        JWEToken::decode_metadata(token)
280    }
281}