1use aes::cipher::BlockDecryptMut;
4use aes::cipher::KeyIvInit;
5use aes::cipher::block_padding::Pkcs7;
6use aes_gcm::AeadInPlace;
7use aes_gcm::KeyInit;
8use aes_gcm::Nonce;
9use aes_gcm::aead::generic_array::ArrayLength;
10use aes_gcm::aead::generic_array::typenum::U12;
11use aes_gcm::aead::generic_array::typenum::U16;
12use aes_gcm::aes::Aes128;
13use aes_gcm::aes::Aes192;
14use aes_gcm::aes::Aes256;
15use ctr::Ctr32BE;
16use ctr::Ctr64BE;
17use ctr::Ctr128BE;
18use ctr::cipher::StreamCipher;
19use deno_core::JsBuffer;
20use deno_core::ToJsBuffer;
21use deno_core::op2;
22use deno_core::unsync::spawn_blocking;
23use rsa::pkcs1::DecodeRsaPrivateKey;
24use serde::Deserialize;
25use sha1::Sha1;
26use sha2::Sha256;
27use sha2::Sha384;
28use sha2::Sha512;
29
30use crate::shared::*;
31
32#[derive(Deserialize)]
33#[serde(rename_all = "camelCase")]
34pub struct DecryptOptions {
35 key: V8RawKeyData,
36 #[serde(flatten)]
37 algorithm: DecryptAlgorithm,
38}
39
40#[derive(Deserialize)]
41#[serde(rename_all = "camelCase", tag = "algorithm")]
42pub enum DecryptAlgorithm {
43 #[serde(rename = "RSA-OAEP")]
44 RsaOaep {
45 hash: ShaHash,
46 #[serde(with = "serde_bytes")]
47 label: Vec<u8>,
48 },
49 #[serde(rename = "AES-CBC", rename_all = "camelCase")]
50 AesCbc {
51 #[serde(with = "serde_bytes")]
52 iv: Vec<u8>,
53 length: usize,
54 },
55 #[serde(rename = "AES-CTR", rename_all = "camelCase")]
56 AesCtr {
57 #[serde(with = "serde_bytes")]
58 counter: Vec<u8>,
59 ctr_length: usize,
60 key_length: usize,
61 },
62 #[serde(rename = "AES-GCM", rename_all = "camelCase")]
63 AesGcm {
64 #[serde(with = "serde_bytes")]
65 iv: Vec<u8>,
66 #[serde(with = "serde_bytes")]
67 additional_data: Option<Vec<u8>>,
68 length: usize,
69 tag_length: usize,
70 },
71}
72
73#[derive(Debug, thiserror::Error, deno_error::JsError)]
74pub enum DecryptError {
75 #[class(inherit)]
76 #[error(transparent)]
77 General(
78 #[from]
79 #[inherit]
80 SharedError,
81 ),
82 #[class(generic)]
83 #[error(transparent)]
84 Pkcs1(#[from] rsa::pkcs1::Error),
85 #[class("DOMExceptionOperationError")]
86 #[error("Decryption failed")]
87 Failed,
88 #[class(type)]
89 #[error("invalid length")]
90 InvalidLength,
91 #[class(type)]
92 #[error("invalid counter length. Currently supported 32/64/128 bits")]
93 InvalidCounterLength,
94 #[class(type)]
95 #[error("tag length not equal to 128")]
96 InvalidTagLength,
97 #[class("DOMExceptionOperationError")]
98 #[error("invalid key or iv")]
99 InvalidKeyOrIv,
100 #[class("DOMExceptionOperationError")]
101 #[error("tried to decrypt too much data")]
102 TooMuchData,
103 #[class(type)]
104 #[error("iv length not equal to 12 or 16")]
105 InvalidIvLength,
106 #[class("DOMExceptionOperationError")]
107 #[error("{0}")]
108 Rsa(rsa::Error),
109}
110
111#[op2(async)]
112#[serde]
113pub async fn op_crypto_decrypt(
114 #[serde] opts: DecryptOptions,
115 #[buffer] data: JsBuffer,
116) -> Result<ToJsBuffer, DecryptError> {
117 let key = opts.key;
118 let fun = move || match opts.algorithm {
119 DecryptAlgorithm::RsaOaep { hash, label } => {
120 decrypt_rsa_oaep(key, hash, label, &data)
121 }
122 DecryptAlgorithm::AesCbc { iv, length } => {
123 decrypt_aes_cbc(key, length, iv, &data)
124 }
125 DecryptAlgorithm::AesCtr {
126 counter,
127 ctr_length,
128 key_length,
129 } => decrypt_aes_ctr(key, key_length, &counter, ctr_length, &data),
130 DecryptAlgorithm::AesGcm {
131 iv,
132 additional_data,
133 length,
134 tag_length,
135 } => decrypt_aes_gcm(key, length, tag_length, iv, additional_data, &data),
136 };
137 let buf = spawn_blocking(fun).await.unwrap()?;
138 Ok(buf.into())
139}
140
141fn decrypt_rsa_oaep(
142 key: V8RawKeyData,
143 hash: ShaHash,
144 label: Vec<u8>,
145 data: &[u8],
146) -> Result<Vec<u8>, DecryptError> {
147 let key = key.as_rsa_private_key()?;
148
149 let private_key = rsa::RsaPrivateKey::from_pkcs1_der(key)?;
150 let label = Some(String::from_utf8_lossy(&label).to_string());
151
152 let padding = match hash {
153 ShaHash::Sha1 => rsa::Oaep {
154 digest: Box::<Sha1>::default(),
155 mgf_digest: Box::<Sha1>::default(),
156 label,
157 },
158 ShaHash::Sha256 => rsa::Oaep {
159 digest: Box::<Sha256>::default(),
160 mgf_digest: Box::<Sha256>::default(),
161 label,
162 },
163 ShaHash::Sha384 => rsa::Oaep {
164 digest: Box::<Sha384>::default(),
165 mgf_digest: Box::<Sha384>::default(),
166 label,
167 },
168 ShaHash::Sha512 => rsa::Oaep {
169 digest: Box::<Sha512>::default(),
170 mgf_digest: Box::<Sha512>::default(),
171 label,
172 },
173 };
174
175 private_key
176 .decrypt(padding, data)
177 .map_err(DecryptError::Rsa)
178}
179
180fn decrypt_aes_cbc(
181 key: V8RawKeyData,
182 length: usize,
183 iv: Vec<u8>,
184 data: &[u8],
185) -> Result<Vec<u8>, DecryptError> {
186 let key = key.as_secret_key()?;
187
188 let plaintext = match length {
190 128 => {
191 type Aes128CbcDec = cbc::Decryptor<aes::Aes128>;
193 let cipher = Aes128CbcDec::new_from_slices(key, &iv)
194 .map_err(|_| DecryptError::InvalidKeyOrIv)?;
195
196 cipher
197 .decrypt_padded_vec_mut::<Pkcs7>(data)
198 .map_err(|_| DecryptError::Failed)?
199 }
200 192 => {
201 type Aes192CbcDec = cbc::Decryptor<aes::Aes192>;
203 let cipher = Aes192CbcDec::new_from_slices(key, &iv)
204 .map_err(|_| DecryptError::InvalidKeyOrIv)?;
205
206 cipher
207 .decrypt_padded_vec_mut::<Pkcs7>(data)
208 .map_err(|_| DecryptError::Failed)?
209 }
210 256 => {
211 type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
213 let cipher = Aes256CbcDec::new_from_slices(key, &iv)
214 .map_err(|_| DecryptError::InvalidKeyOrIv)?;
215
216 cipher
217 .decrypt_padded_vec_mut::<Pkcs7>(data)
218 .map_err(|_| DecryptError::Failed)?
219 }
220 _ => unreachable!(),
221 };
222
223 Ok(plaintext)
225}
226
227fn decrypt_aes_ctr_gen<B>(
228 key: &[u8],
229 counter: &[u8],
230 data: &[u8],
231) -> Result<Vec<u8>, DecryptError>
232where
233 B: KeyIvInit + StreamCipher,
234{
235 let mut cipher = B::new(key.into(), counter.into());
236
237 let mut plaintext = data.to_vec();
238 cipher
239 .try_apply_keystream(&mut plaintext)
240 .map_err(|_| DecryptError::TooMuchData)?;
241
242 Ok(plaintext)
243}
244
245fn decrypt_aes_gcm_gen<N: ArrayLength<u8>>(
246 key: &[u8],
247 tag: &aes_gcm::Tag,
248 nonce: &[u8],
249 length: usize,
250 additional_data: Vec<u8>,
251 plaintext: &mut [u8],
252) -> Result<(), DecryptError> {
253 let nonce = Nonce::from_slice(nonce);
254 match length {
255 128 => {
256 let cipher = aes_gcm::AesGcm::<Aes128, N>::new_from_slice(key)
257 .map_err(|_| DecryptError::Failed)?;
258 cipher
259 .decrypt_in_place_detached(
260 nonce,
261 additional_data.as_slice(),
262 plaintext,
263 tag,
264 )
265 .map_err(|_| DecryptError::Failed)?
266 }
267 192 => {
268 let cipher = aes_gcm::AesGcm::<Aes192, N>::new_from_slice(key)
269 .map_err(|_| DecryptError::Failed)?;
270 cipher
271 .decrypt_in_place_detached(
272 nonce,
273 additional_data.as_slice(),
274 plaintext,
275 tag,
276 )
277 .map_err(|_| DecryptError::Failed)?
278 }
279 256 => {
280 let cipher = aes_gcm::AesGcm::<Aes256, N>::new_from_slice(key)
281 .map_err(|_| DecryptError::Failed)?;
282 cipher
283 .decrypt_in_place_detached(
284 nonce,
285 additional_data.as_slice(),
286 plaintext,
287 tag,
288 )
289 .map_err(|_| DecryptError::Failed)?
290 }
291 _ => return Err(DecryptError::InvalidLength),
292 };
293
294 Ok(())
295}
296
297fn decrypt_aes_ctr(
298 key: V8RawKeyData,
299 key_length: usize,
300 counter: &[u8],
301 ctr_length: usize,
302 data: &[u8],
303) -> Result<Vec<u8>, DecryptError> {
304 let key = key.as_secret_key()?;
305
306 match ctr_length {
307 32 => match key_length {
308 128 => decrypt_aes_ctr_gen::<Ctr32BE<aes::Aes128>>(key, counter, data),
309 192 => decrypt_aes_ctr_gen::<Ctr32BE<aes::Aes192>>(key, counter, data),
310 256 => decrypt_aes_ctr_gen::<Ctr32BE<aes::Aes256>>(key, counter, data),
311 _ => Err(DecryptError::InvalidLength),
312 },
313 64 => match key_length {
314 128 => decrypt_aes_ctr_gen::<Ctr64BE<aes::Aes128>>(key, counter, data),
315 192 => decrypt_aes_ctr_gen::<Ctr64BE<aes::Aes192>>(key, counter, data),
316 256 => decrypt_aes_ctr_gen::<Ctr64BE<aes::Aes256>>(key, counter, data),
317 _ => Err(DecryptError::InvalidLength),
318 },
319 128 => match key_length {
320 128 => decrypt_aes_ctr_gen::<Ctr128BE<aes::Aes128>>(key, counter, data),
321 192 => decrypt_aes_ctr_gen::<Ctr128BE<aes::Aes192>>(key, counter, data),
322 256 => decrypt_aes_ctr_gen::<Ctr128BE<aes::Aes256>>(key, counter, data),
323 _ => Err(DecryptError::InvalidLength),
324 },
325 _ => Err(DecryptError::InvalidCounterLength),
326 }
327}
328
329fn decrypt_aes_gcm(
330 key: V8RawKeyData,
331 length: usize,
332 tag_length: usize,
333 iv: Vec<u8>,
334 additional_data: Option<Vec<u8>>,
335 data: &[u8],
336) -> Result<Vec<u8>, DecryptError> {
337 let key = key.as_secret_key()?;
338 let additional_data = additional_data.unwrap_or_default();
339
340 if tag_length != 128 {
345 return Err(DecryptError::InvalidTagLength);
346 }
347
348 let sep = data.len() - (tag_length / 8);
349 let tag = &data[sep..];
350
351 let mut plaintext = data[..sep].to_vec();
353
354 match iv.len() {
356 12 => decrypt_aes_gcm_gen::<U12>(
357 key,
358 tag.into(),
359 &iv,
360 length,
361 additional_data,
362 &mut plaintext,
363 )?,
364 16 => decrypt_aes_gcm_gen::<U16>(
365 key,
366 tag.into(),
367 &iv,
368 length,
369 additional_data,
370 &mut plaintext,
371 )?,
372 _ => return Err(DecryptError::InvalidIvLength),
373 }
374
375 Ok(plaintext)
376}