• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / edge-runtime / 16485156537

24 Jul 2025 12:56AM UTC coverage: 53.956% (-0.04%) from 53.993%
16485156537

push

github

web-flow
fix: some methods in `node:crypto` cause panic (#567)

0 of 4 new or added lines in 1 file covered. (0.0%)

169 existing lines in 2 files now uncovered.

16365 of 30330 relevant lines covered (53.96%)

5237.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/ext/node/ops/crypto/cipher.rs
1
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2

3
use aes::cipher::block_padding::Pkcs7;
4
use aes::cipher::BlockDecryptMut;
5
use aes::cipher::BlockEncryptMut;
6
use aes::cipher::KeyIvInit;
7
use aes::cipher::KeySizeUser;
8
use deno_core::error::type_error;
9
use deno_core::error::AnyError;
10
use deno_core::Resource;
11
use digest::generic_array::GenericArray;
12
use digest::KeyInit;
13

14
use std::borrow::Cow;
15
use std::cell::RefCell;
16
use std::rc::Rc;
17

18
type Tag = Option<Vec<u8>>;
19

20
type Aes128Gcm = aead_gcm_stream::AesGcm<aes::Aes128>;
21
type Aes256Gcm = aead_gcm_stream::AesGcm<aes::Aes256>;
22

23
enum Cipher {
24
    Aes128Cbc(Box<cbc::Encryptor<aes::Aes128>>),
25
    Aes128Ecb(Box<ecb::Encryptor<aes::Aes128>>),
26
    Aes192Ecb(Box<ecb::Encryptor<aes::Aes192>>),
27
    Aes256Ecb(Box<ecb::Encryptor<aes::Aes256>>),
28
    Aes128Gcm(Box<Aes128Gcm>),
29
    Aes256Gcm(Box<Aes256Gcm>),
30
    Aes256Cbc(Box<cbc::Encryptor<aes::Aes256>>),
31
    // TODO(kt3k): add more algorithms Aes192Cbc, etc.
32
}
33

34
enum Decipher {
35
    Aes128Cbc(Box<cbc::Decryptor<aes::Aes128>>),
36
    Aes128Ecb(Box<ecb::Decryptor<aes::Aes128>>),
37
    Aes192Ecb(Box<ecb::Decryptor<aes::Aes192>>),
38
    Aes256Ecb(Box<ecb::Decryptor<aes::Aes256>>),
39
    Aes128Gcm(Box<Aes128Gcm>),
40
    Aes256Gcm(Box<Aes256Gcm>),
41
    Aes256Cbc(Box<cbc::Decryptor<aes::Aes256>>),
42
    // TODO(kt3k): add more algorithms Aes192Cbc, Aes128GCM, etc.
43
}
44

45
pub struct CipherContext {
46
    cipher: Rc<RefCell<Cipher>>,
47
}
48

49
pub struct DecipherContext {
50
    decipher: Rc<RefCell<Decipher>>,
51
}
52

53
impl CipherContext {
54
    pub fn new(algorithm: &str, key: &[u8], iv: &[u8]) -> Result<Self, AnyError> {
×
55
        Ok(Self {
×
56
            cipher: Rc::new(RefCell::new(Cipher::new(algorithm, key, iv)?)),
×
57
        })
58
    }
×
59

60
    pub fn set_aad(&self, aad: &[u8]) {
×
61
        self.cipher.borrow_mut().set_aad(aad);
×
62
    }
×
63

64
    pub fn encrypt(&self, input: &[u8], output: &mut [u8]) {
×
65
        self.cipher.borrow_mut().encrypt(input, output);
×
66
    }
×
67

68
    pub fn take_tag(self) -> Tag {
×
69
        Rc::try_unwrap(self.cipher).ok()?.into_inner().take_tag()
×
70
    }
×
71

72
    pub fn r#final(self, auto_pad: bool, input: &[u8], output: &mut [u8]) -> Result<Tag, AnyError> {
×
73
        Rc::try_unwrap(self.cipher)
×
74
            .map_err(|_| type_error("Cipher context is already in use"))?
×
75
            .into_inner()
×
76
            .r#final(auto_pad, input, output)
×
77
    }
×
78
}
79

80
impl DecipherContext {
81
    pub fn new(algorithm: &str, key: &[u8], iv: &[u8]) -> Result<Self, AnyError> {
×
82
        Ok(Self {
×
83
            decipher: Rc::new(RefCell::new(Decipher::new(algorithm, key, iv)?)),
×
84
        })
85
    }
×
86

87
    pub fn set_aad(&self, aad: &[u8]) {
×
88
        self.decipher.borrow_mut().set_aad(aad);
×
89
    }
×
90

91
    pub fn decrypt(&self, input: &[u8], output: &mut [u8]) {
×
92
        self.decipher.borrow_mut().decrypt(input, output);
×
93
    }
×
94

95
    pub fn r#final(
×
96
        self,
×
97
        auto_pad: bool,
×
98
        input: &[u8],
×
99
        output: &mut [u8],
×
100
        auth_tag: &[u8],
×
101
    ) -> Result<(), AnyError> {
×
102
        Rc::try_unwrap(self.decipher)
×
103
            .map_err(|_| type_error("Decipher context is already in use"))?
×
104
            .into_inner()
×
105
            .r#final(auto_pad, input, output, auth_tag)
×
106
    }
×
107
}
108

109
impl Resource for CipherContext {
110
    fn name(&self) -> Cow<str> {
×
111
        "cryptoCipher".into()
×
112
    }
×
113
}
114

115
impl Resource for DecipherContext {
116
    fn name(&self) -> Cow<str> {
×
117
        "cryptoDecipher".into()
×
118
    }
×
119
}
120

121
impl Cipher {
122
    fn new(algorithm_name: &str, key: &[u8], iv: &[u8]) -> Result<Self, AnyError> {
×
123
        use Cipher::*;
×
124
        Ok(match algorithm_name {
×
125
            "aes-128-cbc" => Aes128Cbc(Box::new(cbc::Encryptor::new(key.into(), iv.into()))),
×
126
            "aes-128-ecb" => Aes128Ecb(Box::new(ecb::Encryptor::new(key.into()))),
×
127
            "aes-192-ecb" => Aes192Ecb(Box::new(ecb::Encryptor::new(key.into()))),
×
128
            "aes-256-ecb" => Aes256Ecb(Box::new(ecb::Encryptor::new(key.into()))),
×
129
            "aes-128-gcm" => {
×
NEW
130
                if key.len() != aes::Aes128::key_size() {
×
131
                    return Err(type_error("IV length must be 12 bytes"));
×
132
                }
×
133

×
134
                let cipher = aead_gcm_stream::AesGcm::<aes::Aes128>::new(key.into(), iv);
×
135

×
136
                Aes128Gcm(Box::new(cipher))
×
137
            }
138
            "aes-256-gcm" => {
×
NEW
139
                if key.len() != aes::Aes256::key_size() {
×
140
                    return Err(type_error("IV length must be 12 bytes"));
×
141
                }
×
142

×
143
                let cipher = aead_gcm_stream::AesGcm::<aes::Aes256>::new(key.into(), iv);
×
144

×
145
                Aes256Gcm(Box::new(cipher))
×
146
            }
147
            "aes256" | "aes-256-cbc" => {
×
148
                Aes256Cbc(Box::new(cbc::Encryptor::new(key.into(), iv.into())))
×
149
            }
150
            _ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))),
×
151
        })
152
    }
×
153

154
    fn set_aad(&mut self, aad: &[u8]) {
×
155
        use Cipher::*;
×
156
        match self {
×
157
            Aes128Gcm(cipher) => {
×
158
                cipher.set_aad(aad);
×
159
            }
×
160
            Aes256Gcm(cipher) => {
×
161
                cipher.set_aad(aad);
×
162
            }
×
163
            _ => {}
×
164
        }
165
    }
×
166

167
    /// encrypt encrypts the data in the middle of the input.
168
    fn encrypt(&mut self, input: &[u8], output: &mut [u8]) {
×
169
        use Cipher::*;
×
170
        match self {
×
171
            Aes128Cbc(encryptor) => {
×
172
                assert!(input.len() % 16 == 0);
×
173
                for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) {
×
174
                    encryptor.encrypt_block_b2b_mut(input.into(), output.into());
×
175
                }
×
176
            }
177
            Aes128Ecb(encryptor) => {
×
178
                assert!(input.len() % 16 == 0);
×
179
                for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) {
×
180
                    encryptor.encrypt_block_b2b_mut(input.into(), output.into());
×
181
                }
×
182
            }
183
            Aes192Ecb(encryptor) => {
×
184
                assert!(input.len() % 16 == 0);
×
185
                for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) {
×
186
                    encryptor.encrypt_block_b2b_mut(input.into(), output.into());
×
187
                }
×
188
            }
189
            Aes256Ecb(encryptor) => {
×
190
                assert!(input.len() % 16 == 0);
×
191
                for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) {
×
192
                    encryptor.encrypt_block_b2b_mut(input.into(), output.into());
×
193
                }
×
194
            }
195
            Aes128Gcm(cipher) => {
×
196
                output[..input.len()].copy_from_slice(input);
×
197
                cipher.encrypt(output);
×
198
            }
×
199
            Aes256Gcm(cipher) => {
×
200
                output[..input.len()].copy_from_slice(input);
×
201
                cipher.encrypt(output);
×
202
            }
×
203
            Aes256Cbc(encryptor) => {
×
204
                assert!(input.len() % 16 == 0);
×
205
                for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) {
×
206
                    encryptor.encrypt_block_b2b_mut(input.into(), output.into());
×
207
                }
×
208
            }
209
        }
210
    }
×
211

212
    /// r#final encrypts the last block of the input data.
213
    fn r#final(self, auto_pad: bool, input: &[u8], output: &mut [u8]) -> Result<Tag, AnyError> {
×
214
        assert!(input.len() < 16);
×
215
        use Cipher::*;
216
        match (self, auto_pad) {
×
217
            (Aes128Cbc(encryptor), true) => {
×
218
                let _ = (*encryptor)
×
219
                    .encrypt_padded_b2b_mut::<Pkcs7>(input, output)
×
220
                    .map_err(|_| type_error("Cannot pad the input data"))?;
×
221
                Ok(None)
×
222
            }
223
            (Aes128Cbc(mut encryptor), false) => {
×
224
                encryptor.encrypt_block_b2b_mut(
×
225
                    GenericArray::from_slice(input),
×
226
                    GenericArray::from_mut_slice(output),
×
227
                );
×
228
                Ok(None)
×
229
            }
230
            (Aes128Ecb(encryptor), true) => {
×
231
                let _ = (*encryptor)
×
232
                    .encrypt_padded_b2b_mut::<Pkcs7>(input, output)
×
233
                    .map_err(|_| type_error("Cannot pad the input data"))?;
×
234
                Ok(None)
×
235
            }
236
            (Aes128Ecb(mut encryptor), false) => {
×
237
                encryptor.encrypt_block_b2b_mut(
×
238
                    GenericArray::from_slice(input),
×
239
                    GenericArray::from_mut_slice(output),
×
240
                );
×
241
                Ok(None)
×
242
            }
243
            (Aes192Ecb(encryptor), true) => {
×
244
                let _ = (*encryptor)
×
245
                    .encrypt_padded_b2b_mut::<Pkcs7>(input, output)
×
246
                    .map_err(|_| type_error("Cannot pad the input data"))?;
×
247
                Ok(None)
×
248
            }
249
            (Aes192Ecb(mut encryptor), false) => {
×
250
                encryptor.encrypt_block_b2b_mut(
×
251
                    GenericArray::from_slice(input),
×
252
                    GenericArray::from_mut_slice(output),
×
253
                );
×
254
                Ok(None)
×
255
            }
256
            (Aes256Ecb(encryptor), true) => {
×
257
                let _ = (*encryptor)
×
258
                    .encrypt_padded_b2b_mut::<Pkcs7>(input, output)
×
259
                    .map_err(|_| type_error("Cannot pad the input data"))?;
×
260
                Ok(None)
×
261
            }
262
            (Aes256Ecb(mut encryptor), false) => {
×
263
                encryptor.encrypt_block_b2b_mut(
×
264
                    GenericArray::from_slice(input),
×
265
                    GenericArray::from_mut_slice(output),
×
266
                );
×
267
                Ok(None)
×
268
            }
269
            (Aes128Gcm(cipher), _) => Ok(Some(cipher.finish().to_vec())),
×
270
            (Aes256Gcm(cipher), _) => Ok(Some(cipher.finish().to_vec())),
×
271
            (Aes256Cbc(encryptor), true) => {
×
272
                let _ = (*encryptor)
×
273
                    .encrypt_padded_b2b_mut::<Pkcs7>(input, output)
×
274
                    .map_err(|_| type_error("Cannot pad the input data"))?;
×
275
                Ok(None)
×
276
            }
277
            (Aes256Cbc(mut encryptor), false) => {
×
278
                encryptor.encrypt_block_b2b_mut(
×
279
                    GenericArray::from_slice(input),
×
280
                    GenericArray::from_mut_slice(output),
×
281
                );
×
282
                Ok(None)
×
283
            }
284
        }
285
    }
×
286

287
    fn take_tag(self) -> Tag {
×
288
        use Cipher::*;
×
289
        match self {
×
290
            Aes128Gcm(cipher) => Some(cipher.finish().to_vec()),
×
291
            Aes256Gcm(cipher) => Some(cipher.finish().to_vec()),
×
292
            _ => None,
×
293
        }
294
    }
×
295
}
296

297
impl Decipher {
298
    fn new(algorithm_name: &str, key: &[u8], iv: &[u8]) -> Result<Self, AnyError> {
×
299
        use Decipher::*;
×
300
        Ok(match algorithm_name {
×
301
            "aes-128-cbc" => Aes128Cbc(Box::new(cbc::Decryptor::new(key.into(), iv.into()))),
×
302
            "aes-128-ecb" => Aes128Ecb(Box::new(ecb::Decryptor::new(key.into()))),
×
303
            "aes-192-ecb" => Aes192Ecb(Box::new(ecb::Decryptor::new(key.into()))),
×
304
            "aes-256-ecb" => Aes256Ecb(Box::new(ecb::Decryptor::new(key.into()))),
×
305
            "aes-128-gcm" => {
×
NEW
306
                if key.len() != aes::Aes128::key_size() {
×
307
                    return Err(type_error("IV length must be 12 bytes"));
×
308
                }
×
309

×
310
                let decipher = aead_gcm_stream::AesGcm::<aes::Aes128>::new(key.into(), iv);
×
311

×
312
                Aes128Gcm(Box::new(decipher))
×
313
            }
314
            "aes-256-gcm" => {
×
NEW
315
                if key.len() != aes::Aes256::key_size() {
×
316
                    return Err(type_error("IV length must be 12 bytes"));
×
317
                }
×
318

×
319
                let decipher = aead_gcm_stream::AesGcm::<aes::Aes256>::new(key.into(), iv);
×
320

×
321
                Aes256Gcm(Box::new(decipher))
×
322
            }
323
            "aes256" | "aes-256-cbc" => {
×
324
                Aes256Cbc(Box::new(cbc::Decryptor::new(key.into(), iv.into())))
×
325
            }
326
            _ => return Err(type_error(format!("Unknown cipher {algorithm_name}"))),
×
327
        })
328
    }
×
329

330
    fn set_aad(&mut self, aad: &[u8]) {
×
331
        use Decipher::*;
×
332
        match self {
×
333
            Aes128Gcm(decipher) => {
×
334
                decipher.set_aad(aad);
×
335
            }
×
336
            Aes256Gcm(decipher) => {
×
337
                decipher.set_aad(aad);
×
338
            }
×
339
            _ => {}
×
340
        }
341
    }
×
342

343
    /// decrypt decrypts the data in the middle of the input.
344
    fn decrypt(&mut self, input: &[u8], output: &mut [u8]) {
×
345
        use Decipher::*;
×
346
        match self {
×
347
            Aes128Cbc(decryptor) => {
×
348
                assert!(input.len() % 16 == 0);
×
349
                for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) {
×
350
                    decryptor.decrypt_block_b2b_mut(input.into(), output.into());
×
351
                }
×
352
            }
353
            Aes128Ecb(decryptor) => {
×
354
                assert!(input.len() % 16 == 0);
×
355
                for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) {
×
356
                    decryptor.decrypt_block_b2b_mut(input.into(), output.into());
×
357
                }
×
358
            }
359
            Aes192Ecb(decryptor) => {
×
360
                assert!(input.len() % 16 == 0);
×
361
                for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) {
×
362
                    decryptor.decrypt_block_b2b_mut(input.into(), output.into());
×
363
                }
×
364
            }
365
            Aes256Ecb(decryptor) => {
×
366
                assert!(input.len() % 16 == 0);
×
367
                for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) {
×
368
                    decryptor.decrypt_block_b2b_mut(input.into(), output.into());
×
369
                }
×
370
            }
371
            Aes128Gcm(decipher) => {
×
372
                output[..input.len()].copy_from_slice(input);
×
373
                decipher.decrypt(output);
×
374
            }
×
375
            Aes256Gcm(decipher) => {
×
376
                output[..input.len()].copy_from_slice(input);
×
377
                decipher.decrypt(output);
×
378
            }
×
379
            Aes256Cbc(decryptor) => {
×
380
                assert!(input.len() % 16 == 0);
×
381
                for (input, output) in input.chunks(16).zip(output.chunks_mut(16)) {
×
382
                    decryptor.decrypt_block_b2b_mut(input.into(), output.into());
×
383
                }
×
384
            }
385
        }
386
    }
×
387

388
    /// r#final decrypts the last block of the input data.
389
    fn r#final(
×
390
        self,
×
391
        auto_pad: bool,
×
392
        input: &[u8],
×
393
        output: &mut [u8],
×
394
        auth_tag: &[u8],
×
395
    ) -> Result<(), AnyError> {
×
396
        use Decipher::*;
×
397
        match (self, auto_pad) {
×
398
            (Aes128Cbc(decryptor), true) => {
×
399
                assert!(input.len() == 16);
×
400
                let _ = (*decryptor)
×
401
                    .decrypt_padded_b2b_mut::<Pkcs7>(input, output)
×
402
                    .map_err(|_| type_error("Cannot unpad the input data"))?;
×
403
                Ok(())
×
404
            }
405
            (Aes128Cbc(mut decryptor), false) => {
×
406
                decryptor.decrypt_block_b2b_mut(
×
407
                    GenericArray::from_slice(input),
×
408
                    GenericArray::from_mut_slice(output),
×
409
                );
×
410
                Ok(())
×
411
            }
412
            (Aes128Ecb(decryptor), true) => {
×
413
                assert!(input.len() == 16);
×
414
                let _ = (*decryptor)
×
415
                    .decrypt_padded_b2b_mut::<Pkcs7>(input, output)
×
416
                    .map_err(|_| type_error("Cannot unpad the input data"))?;
×
417
                Ok(())
×
418
            }
419
            (Aes128Ecb(mut decryptor), false) => {
×
420
                decryptor.decrypt_block_b2b_mut(
×
421
                    GenericArray::from_slice(input),
×
422
                    GenericArray::from_mut_slice(output),
×
423
                );
×
424
                Ok(())
×
425
            }
426
            (Aes192Ecb(decryptor), true) => {
×
427
                assert!(input.len() == 16);
×
428
                let _ = (*decryptor)
×
429
                    .decrypt_padded_b2b_mut::<Pkcs7>(input, output)
×
430
                    .map_err(|_| type_error("Cannot unpad the input data"))?;
×
431
                Ok(())
×
432
            }
433
            (Aes192Ecb(mut decryptor), false) => {
×
434
                decryptor.decrypt_block_b2b_mut(
×
435
                    GenericArray::from_slice(input),
×
436
                    GenericArray::from_mut_slice(output),
×
437
                );
×
438
                Ok(())
×
439
            }
440
            (Aes256Ecb(decryptor), true) => {
×
441
                assert!(input.len() == 16);
×
442
                let _ = (*decryptor)
×
443
                    .decrypt_padded_b2b_mut::<Pkcs7>(input, output)
×
444
                    .map_err(|_| type_error("Cannot unpad the input data"))?;
×
445
                Ok(())
×
446
            }
447
            (Aes256Ecb(mut decryptor), false) => {
×
448
                decryptor.decrypt_block_b2b_mut(
×
449
                    GenericArray::from_slice(input),
×
450
                    GenericArray::from_mut_slice(output),
×
451
                );
×
452
                Ok(())
×
453
            }
454
            (Aes128Gcm(decipher), true) => {
×
455
                let tag = decipher.finish();
×
456
                if tag.as_slice() == auth_tag {
×
457
                    Ok(())
×
458
                } else {
459
                    Err(type_error("Failed to authenticate data"))
×
460
                }
461
            }
462
            (Aes128Gcm(_), false) => Err(type_error(
×
463
                "setAutoPadding(false) not supported for Aes256Gcm yet",
×
464
            )),
×
465
            (Aes256Gcm(decipher), true) => {
×
466
                let tag = decipher.finish();
×
467
                if tag.as_slice() == auth_tag {
×
468
                    Ok(())
×
469
                } else {
470
                    Err(type_error("Failed to authenticate data"))
×
471
                }
472
            }
473
            (Aes256Gcm(_), false) => Err(type_error(
×
474
                "setAutoPadding(false) not supported for Aes256Gcm yet",
×
475
            )),
×
476
            (Aes256Cbc(decryptor), true) => {
×
477
                assert!(input.len() == 16);
×
478
                let _ = (*decryptor)
×
479
                    .decrypt_padded_b2b_mut::<Pkcs7>(input, output)
×
480
                    .map_err(|_| type_error("Cannot unpad the input data"))?;
×
481
                Ok(())
×
482
            }
483
            (Aes256Cbc(mut decryptor), false) => {
×
484
                decryptor.decrypt_block_b2b_mut(
×
485
                    GenericArray::from_slice(input),
×
486
                    GenericArray::from_mut_slice(output),
×
487
                );
×
488
                Ok(())
×
489
            }
490
        }
491
    }
×
492
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc