Skip to content

Commit

Permalink
feat(runtime): support AES-CBC for SubtleCrypto#encrypt & `SubtleCr…
Browse files Browse the repository at this point in the history
…ypto#decrypt` (#848)
  • Loading branch information
QuiiBz authored May 11, 2023
1 parent 52b170a commit cd214f2
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 2 deletions.
8 changes: 8 additions & 0 deletions .changeset/strange-moles-wave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@lagon/cli': patch
'@lagon/runtime': patch
'@lagon/serverless': patch
'@lagon/docs': patch
---

Support AES-CBC for `SubtleCrypto#encrypt` & `SubtleCrypto#decrypt`
20 changes: 20 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

74 changes: 72 additions & 2 deletions crates/runtime/tests/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ async fn crypto_digest_object() {
}

#[tokio::test]
async fn crypto_encrypt() {
async fn crypto_encrypt_aes_gcm() {
utils::setup();
let (send, receiver) = utils::create_isolate(IsolateOptions::new(
"export async function handler() {
Expand Down Expand Up @@ -271,7 +271,7 @@ async fn crypto_encrypt() {
}

#[tokio::test]
async fn crypto_decrypt() {
async fn crypto_decrypt_aes_gcm() {
utils::setup();
let (send, receiver) = utils::create_isolate(IsolateOptions::new(
"export async function handler() {
Expand Down Expand Up @@ -308,6 +308,76 @@ async fn crypto_decrypt() {
);
}

#[tokio::test]
async fn crypto_encrypt_aes_cbc() {
utils::setup();
let (send, receiver) = utils::create_isolate(IsolateOptions::new(
"export async function handler() {
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode('secret'),
{ name: 'AES-CBC' },
false,
['sign'],
);
const iv = crypto.getRandomValues(new Uint8Array(16));
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-CBC', iv },
key,
new TextEncoder().encode('hello, world'),
);
return new Response(`${ciphertext instanceof Uint8Array} ${ciphertext.length}`);
}"
.into(),
));
send(Request::default());

assert_eq!(
receiver.recv_async().await.unwrap().as_response(),
Response::from("true 16")
);
}

#[tokio::test]
async fn crypto_decrypt_aes_cbc() {
utils::setup();
let (send, receiver) = utils::create_isolate(IsolateOptions::new(
"export async function handler() {
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode('secret'),
{ name: 'AES-CBC' },
false,
['sign'],
);
const iv = crypto.getRandomValues(new Uint8Array(16));
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-CBC', iv },
key,
new TextEncoder().encode('hello, world'),
);
const text = await crypto.subtle.decrypt(
{ name: 'AES-CBC', iv },
key,
ciphertext,
);
return new Response(new TextDecoder().decode(text));
}"
.into(),
));
send(Request::default());

assert_eq!(
receiver.recv_async().await.unwrap().as_response(),
Response::from("hello, world")
);
}

#[tokio::test]
async fn crypto_hkdf_derive_bits() {
utils::setup();
Expand Down
1 change: 1 addition & 0 deletions crates/runtime_crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ sha1 = "0.10.5"
sha2 = "0.10.6"
aes = "0.8.2"
aes-gcm = "0.10.1"
cbc = { version = "0.1.2", features = ["std"] }
ring = { version = "0.16.20", features = ["std"] }
p256 = { version = "0.11.1", features = ["ecdh"] }
p384 = "0.11.1"
11 changes: 11 additions & 0 deletions crates/runtime_crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub enum Sha {
pub enum Algorithm {
Hmac,
AesGcm(Vec<u8>),
AesCbc(Vec<u8>),
}

pub enum CryptoNamedCurve {
Expand Down Expand Up @@ -61,6 +62,16 @@ pub fn extract_algorithm_object(

return Ok(Algorithm::AesGcm(iv));
}

if name == "AES-CBC" {
let iv_key = v8_string(scope, "iv");
let iv = match algorithm.get(scope, iv_key.into()) {
Some(iv) => extract_v8_uint8array(iv)?,
None => return Err(anyhow!("Algorithm iv not found")),
};

return Ok(Algorithm::AesCbc(iv));
}
}

Err(anyhow!("Algorithm not supported"))
Expand Down
11 changes: 11 additions & 0 deletions crates/runtime_crypto/src/methods/decrypt.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, KeyIvInit};
use aes_gcm::{aead::Aead, KeyInit, Nonce};
use anyhow::{anyhow, Result};

use crate::{Aes256Gcm, Algorithm};

type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;

pub fn decrypt(algorithm: Algorithm, key_value: Vec<u8>, data: Vec<u8>) -> Result<Vec<u8>> {
match algorithm {
Algorithm::AesGcm(iv) => {
Expand All @@ -14,6 +17,14 @@ pub fn decrypt(algorithm: Algorithm, key_value: Vec<u8>, data: Vec<u8>) -> Resul
Err(_) => Err(anyhow!("Decryption failed")),
}
}
Algorithm::AesCbc(iv) => {
match Aes256CbcDec::new(key_value.as_slice().into(), iv.as_slice().into())
.decrypt_padded_vec_mut::<Pkcs7>(&data)
{
Ok(result) => Ok(result),
Err(_) => Err(anyhow!("Decryption failed")),
}
}
_ => Err(anyhow!("Algorithm not supported")),
}
}
8 changes: 8 additions & 0 deletions crates/runtime_crypto/src/methods/encrypt.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use aes::cipher::{block_padding::Pkcs7, BlockEncryptMut, KeyIvInit};
use aes_gcm::{aead::Aead, KeyInit, Nonce};
use anyhow::{anyhow, Result};

use crate::{Aes256Gcm, Algorithm};

type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;

pub fn encrypt(algorithm: Algorithm, key_value: Vec<u8>, data: Vec<u8>) -> Result<Vec<u8>> {
match algorithm {
Algorithm::AesGcm(iv) => {
Expand All @@ -14,6 +17,11 @@ pub fn encrypt(algorithm: Algorithm, key_value: Vec<u8>, data: Vec<u8>) -> Resul
Err(_) => Err(anyhow!("Encryption failed")),
}
}
Algorithm::AesCbc(iv) => Ok(Aes256CbcEnc::new(
key_value.as_slice().into(),
iv.as_slice().into(),
)
.encrypt_padded_vec_mut::<Pkcs7>(&data)),
_ => Err(anyhow!("Algorithm not supported")),
}
}
1 change: 1 addition & 0 deletions packages/docs/pages/runtime-apis.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ The standard `CryptoSubtle` object. [See the documentation on MDN](https://devel
| SHA-384 | | || | |
| SHA-512 | | || | |
| AES-GCM | || | ||
| AES-CBC | || | ||
| ECDH | | | || |
| HKDF | | | || |
| PBKDF2 | | | || |
Expand Down

1 comment on commit cd214f2

@vercel
Copy link

@vercel vercel bot commented on cd214f2 May 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs – ./packages/docs

lagon-docs.vercel.app
docs-lagon.vercel.app
docs-git-main-lagon.vercel.app
docs.lagon.app

Please sign in to comment.