Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ stdlib = [
"datadog",
"parsing",
"dep:aes",
"dep:aes-gcm",
"dep:aes-siv",
"dep:base16",
"dep:base62",
Expand Down Expand Up @@ -219,6 +220,7 @@ zstd = { version = "0.13", default-features = false, features = ["wasm"], option

# Cryptography
aes = { version = "0.8", optional = true }
aes-gcm = { version = "0.10.3", optional = true }
aes-siv = { version = "0.7.0", optional = true }
chacha20poly1305 = { version = "0.10", optional = true }
crypto_secretbox = { version = "0.1", features = ["salsa20"], optional = true }
Expand Down
3 changes: 3 additions & 0 deletions LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ addr2line,https://github.com/gimli-rs/addr2line,Apache-2.0 OR MIT,The addr2line
adler2,https://github.com/oyvindln/adler2,0BSD OR MIT OR Apache-2.0,"Jonas Schievink <jonasschievink@gmail.com>, oyvindln <oyvindln@users.noreply.github.com>"
aead,https://github.com/RustCrypto/traits,MIT OR Apache-2.0,RustCrypto Developers
aes,https://github.com/RustCrypto/block-ciphers,MIT OR Apache-2.0,RustCrypto Developers
aes-gcm,https://github.com/RustCrypto/AEADs,Apache-2.0 OR MIT,RustCrypto Developers
aes-siv,https://github.com/RustCrypto/AEADs,Apache-2.0 OR MIT,RustCrypto Developers
ahash,https://github.com/tkaitchuck/ahash,MIT OR Apache-2.0,Tom Kaitchuck <Tom.Kaitchuck@gmail.com>
aho-corasick,https://github.com/BurntSushi/aho-corasick,Unlicense OR MIT,Andrew Gallant <jamslam@gmail.com>
Expand Down Expand Up @@ -113,6 +114,7 @@ futures-task,https://github.com/rust-lang/futures-rs,MIT OR Apache-2.0,The futur
futures-util,https://github.com/rust-lang/futures-rs,MIT OR Apache-2.0,The futures-util Authors
generic-array,https://github.com/fizyk20/generic-array,MIT,"Bartłomiej Kamiński <fizyk20@gmail.com>, Aaron Trent <novacrazy@gmail.com>"
getrandom,https://github.com/rust-random/getrandom,MIT OR Apache-2.0,The Rand Project Developers
ghash,https://github.com/RustCrypto/universal-hashes,Apache-2.0 OR MIT,RustCrypto Developers
gimli,https://github.com/gimli-rs/gimli,MIT OR Apache-2.0,The gimli Authors
grok,https://github.com/mmastrac/grok,Apache-2.0,"Matt Mastracci <matthew@mastracci.com>, Michael Nitschinger <michael@nitschinger.at>"
h2,https://github.com/hyperium/h2,MIT,"Carl Lerche <me@carllerche.com>, Sean McArthur <sean@seanmonstar.com>"
Expand Down Expand Up @@ -222,6 +224,7 @@ phf_shared,https://github.com/rust-phf/rust-phf,MIT,Steven Fackler <sfackler@gma
pin-project-lite,https://github.com/taiki-e/pin-project-lite,Apache-2.0 OR MIT,The pin-project-lite Authors
pin-utils,https://github.com/rust-lang-nursery/pin-utils,MIT OR Apache-2.0,Josef Brandl <mail@josefbrandl.de>
poly1305,https://github.com/RustCrypto/universal-hashes,Apache-2.0 OR MIT,RustCrypto Developers
polyval,https://github.com/RustCrypto/universal-hashes,Apache-2.0 OR MIT,RustCrypto Developers
portable-atomic,https://github.com/taiki-e/portable-atomic,Apache-2.0 OR MIT,The portable-atomic Authors
potential_utf,https://github.com/unicode-org/icu4x,Unicode-3.0,The ICU4X Project Developers
powerfmt,https://github.com/jhpratt/powerfmt,MIT OR Apache-2.0,Jacob Pratt <jacob@jhpratt.dev>
Expand Down
3 changes: 3 additions & 0 deletions changelog.d/1641.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added AES-GCM support to decrypt/encrypt functions.

author: dodo0822
61 changes: 61 additions & 0 deletions src/stdlib/decrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use crate::value::Value;
use aes::cipher::{
AsyncStreamCipher, BlockDecryptMut, KeyIvInit, StreamCipher,
block_padding::{AnsiX923, Iso7816, Iso10126, Pkcs7},
consts::{U12, U16},
generic_array::GenericArray,
};
use aes_gcm::{Aes128Gcm, Aes256Gcm, AesGcm};
use aes_siv::{Aes128SivAead, Aes256SivAead};
use cfb_mode::Decryptor as Cfb;
use chacha20poly1305::{ChaCha20Poly1305, KeyInit, XChaCha20Poly1305, aead::Aead};
Expand All @@ -18,6 +20,12 @@ type Aes128Cbc = cbc::Decryptor<aes::Aes128>;
type Aes192Cbc = cbc::Decryptor<aes::Aes192>;
type Aes256Cbc = cbc::Decryptor<aes::Aes256>;

type Aes192Gcm = AesGcm<aes::Aes192, U12>;

type Aes128Gcm16 = AesGcm<aes::Aes128, U16>;
type Aes192Gcm16 = AesGcm<aes::Aes192, U16>;
type Aes256Gcm16 = AesGcm<aes::Aes256, U16>;

macro_rules! decrypt {
($algorithm:ty, $ciphertext:expr_2021, $key:expr_2021, $iv:expr_2021) => {{
let mut buffer = vec![0; $ciphertext.len()];
Expand Down Expand Up @@ -63,6 +71,17 @@ macro_rules! decrypt_stream {
}};
}

macro_rules! decrypt_gcm {
($algorithm:ty, $ciphertext:expr_2021, $key:expr_2021, $iv:expr_2021) => {{
<$algorithm>::new(&GenericArray::from(get_key_bytes($key)?))
.decrypt(
&GenericArray::from(get_iv_bytes($iv)?),
$ciphertext.as_ref(),
)
.map_err(|e| format!("Decryption failed: {e}"))?
}};
}

fn decrypt(ciphertext: Value, algorithm: &str, key: Value, iv: Value) -> Resolved {
let ciphertext = ciphertext.try_bytes()?;

Expand Down Expand Up @@ -99,6 +118,12 @@ fn decrypt(ciphertext: Value, algorithm: &str, key: Value, iv: Value) -> Resolve
"AES-128-CBC-ISO10126" => decrypt_padded!(Aes128Cbc, Iso10126, ciphertext, key, iv),
"AES-128-SIV" => decrypt_stream!(Aes128SivAead, ciphertext, key, iv),
"AES-256-SIV" => decrypt_stream!(Aes256SivAead, ciphertext, key, iv),
"AES-128-GCM" => decrypt_gcm!(Aes128Gcm, ciphertext, key, iv),
"AES-192-GCM" => decrypt_gcm!(Aes192Gcm, ciphertext, key, iv),
"AES-256-GCM" => decrypt_gcm!(Aes256Gcm, ciphertext, key, iv),
"AES-128-GCM-16" => decrypt_gcm!(Aes128Gcm16, ciphertext, key, iv),
"AES-192-GCM-16" => decrypt_gcm!(Aes192Gcm16, ciphertext, key, iv),
"AES-256-GCM-16" => decrypt_gcm!(Aes256Gcm16, ciphertext, key, iv),
"CHACHA20-POLY1305" => decrypt_stream!(ChaCha20Poly1305, ciphertext, key, iv),
"XCHACHA20-POLY1305" => decrypt_stream!(XChaCha20Poly1305, ciphertext, key, iv),
"XSALSA20-POLY1305" => decrypt_stream!(XSalsa20Poly1305, ciphertext, key, iv),
Expand Down Expand Up @@ -447,6 +472,42 @@ mod tests {
tdef: TypeDef::bytes().fallible(),
}

aes_128_gcm {
args: func_args![ciphertext: value!(b"\xc2\xf1\x8b\t\xd5\x0c\xad/B\x08W\xcb\x13\xdb\xe2$\x96A\xcc\xb8T`+\x99f\x0cc/\x08B\x083\xb1m\xb8\x05"), algorithm: "AES-128-GCM", key: b"16_bytes_xxxxxxx", iv: b"12_bytes_xxx"],
want: Ok(value!("morethan1blockofdata")),
tdef: TypeDef::bytes().fallible(),
}

aes_192_gcm {
args: func_args![ciphertext: value!(b",\x8fI\xe6\x15\x8c\xeb\x95lq}\xe52\xfc\x0e\x808\x8b@\xca\\\xe5\xd0uR\x9cS\x02\xf6\xad\xa1\xb2W\xf47\xe2"), algorithm: "AES-192-GCM", key: b"24_bytes_xxxxxxxxxxxxxxx", iv: b"12_bytes_xxx"],
want: Ok(value!("morethan1blockofdata")),
tdef: TypeDef::bytes().fallible(),
}

aes_256_gcm {
args: func_args![ciphertext: value!(b"\xc7\x03\xe0\xbd\xf7=N\x8cg\xc5\x94\xa3[\xa0\x1b<yF\xe9\xe7\xab{\xbc5\xc3\xcb\xc6Em\xb8\x02\xa8\x1ej\x86L"), algorithm: "AES-256-GCM", key: b"32_bytes_xxxxxxxxxxxxxxxxxxxxxxx", iv: b"12_bytes_xxx"],
want: Ok(value!("morethan1blockofdata")),
tdef: TypeDef::bytes().fallible(),
}

aes_128_gcm_16 {
args: func_args![ciphertext: value!(b"PW{y.\x07\xa2.6\x93\x0b\x03z\xe1\xccI\x90\x98A\xb9\xe1\x1d\xc2\xb2Q\xbbl\xf2XX\xe1\x15|\xebKh"), algorithm: "AES-128-GCM-16", key: b"16_bytes_xxxxxxx", iv: b"16_bytes_xxxxxxx"],
want: Ok(value!("morethan1blockofdata")),
tdef: TypeDef::bytes().fallible(),
}

aes_192_gcm_16 {
args: func_args![ciphertext: value!(b"\x01\xb7\xcc\xb14\xb4rM\x1b\xab\x96&~9p~\x038\xcd\xafN\xed\x1f#&\xc5C\xec\xf3\xc4\xc6iA\x07\xa6\xaa"), algorithm: "AES-192-GCM-16", key: b"24_bytes_xxxxxxxxxxxxxxx", iv: b"16_bytes_xxxxxxx"],
want: Ok(value!("morethan1blockofdata")),
tdef: TypeDef::bytes().fallible(),
}

aes_256_gcm_16 {
args: func_args![ciphertext: value!(b"\xd0\xe9@m\r\xc0b/Qg)\x10\x86\x91\xfb\xe7\x86\xa3\xc9C\xff0\xd3\x99\xdb3\xf0\xc3\xce\xf4\x05\xbb\xcc\xa0\x97B"), algorithm: "AES-256-GCM-16", key: b"32_bytes_xxxxxxxxxxxxxxxxxxxxxxx", iv: b"16_bytes_xxxxxxx"],
want: Ok(value!("morethan1blockofdata")),
tdef: TypeDef::bytes().fallible(),
}

chacha20_poly1305 {
args: func_args![ciphertext: value!(b"\x14m\xe3\xc9\xbc!\xafu\xe31\xb9\x17\x8f\x9bOo0}n\xf4{$\x95\x0f\xa0\x820\xb7R\xe3.{\xd7?\x96\x10"), algorithm: "CHACHA20-POLY1305", key: "32_bytes_xxxxxxxxxxxxxxxxxxxxxxx", iv: "12_bytes_xxx"],
want: Ok(value!("morethan1blockofdata")),
Expand Down
64 changes: 64 additions & 0 deletions src/stdlib/encrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ use crate::compiler::prelude::*;
use aes::cipher::{
AsyncStreamCipher, BlockEncryptMut, KeyIvInit, StreamCipher,
block_padding::{AnsiX923, Iso7816, Iso10126, Pkcs7},
consts::{U12, U16},
generic_array::GenericArray,
};
use aes_gcm::{Aes128Gcm, Aes256Gcm, AesGcm};
use aes_siv::{Aes128SivAead, Aes256SivAead};
use cfb_mode::Encryptor as Cfb;
use chacha20poly1305::{ChaCha20Poly1305, KeyInit, XChaCha20Poly1305, aead::Aead};
Expand All @@ -15,6 +17,12 @@ type Aes128Cbc = cbc::Encryptor<aes::Aes128>;
type Aes192Cbc = cbc::Encryptor<aes::Aes192>;
type Aes256Cbc = cbc::Encryptor<aes::Aes256>;

type Aes192Gcm = AesGcm<aes::Aes192, U12>;

type Aes128Gcm16 = AesGcm<aes::Aes128, U16>;
type Aes192Gcm16 = AesGcm<aes::Aes192, U16>;
type Aes256Gcm16 = AesGcm<aes::Aes256, U16>;

pub(crate) fn get_key_bytes<const N: usize>(key: Value) -> ExpressionResult<[u8; N]> {
let bytes = key.try_bytes()?;
if bytes.len() != N {
Expand Down Expand Up @@ -89,6 +97,14 @@ macro_rules! encrypt_stream {
}};
}

macro_rules! encrypt_gcm {
($algorithm:ty, $plaintext:expr_2021, $key:expr_2021, $iv:expr_2021) => {{
<$algorithm>::new(&GenericArray::from(get_key_bytes($key)?))
.encrypt(&GenericArray::from(get_iv_bytes($iv)?), $plaintext.as_ref())
.map_err(|e| format!("Encryption failed: {e}"))?
}};
}

pub(crate) fn is_valid_algorithm(algorithm: &str) -> bool {
matches!(
algorithm,
Expand Down Expand Up @@ -121,6 +137,12 @@ pub(crate) fn is_valid_algorithm(algorithm: &str) -> bool {
| "AES-128-CBC-ISO10126"
| "AES-128-SIV"
| "AES-256-SIV"
| "AES-128-GCM"
| "AES-192-GCM"
| "AES-256-GCM"
| "AES-128-GCM-16"
| "AES-192-GCM-16"
| "AES-256-GCM-16"
| "CHACHA20-POLY1305"
| "XCHACHA20-POLY1305"
| "XSALSA20-POLY1305"
Expand Down Expand Up @@ -162,6 +184,12 @@ fn encrypt(plaintext: Value, algorithm: &str, key: Value, iv: Value) -> Resolved
"AES-128-CBC-ISO10126" => encrypt_padded!(Aes128Cbc, Iso10126, plaintext, key, iv),
"AES-128-SIV" => encrypt_stream!(Aes128SivAead, plaintext, key, iv),
"AES-256-SIV" => encrypt_stream!(Aes256SivAead, plaintext, key, iv),
"AES-128-GCM" => encrypt_gcm!(Aes128Gcm, plaintext, key, iv),
"AES-192-GCM" => encrypt_gcm!(Aes192Gcm, plaintext, key, iv),
"AES-256-GCM" => encrypt_gcm!(Aes256Gcm, plaintext, key, iv),
"AES-128-GCM-16" => encrypt_gcm!(Aes128Gcm16, plaintext, key, iv),
"AES-192-GCM-16" => encrypt_gcm!(Aes192Gcm16, plaintext, key, iv),
"AES-256-GCM-16" => encrypt_gcm!(Aes256Gcm16, plaintext, key, iv),
"CHACHA20-POLY1305" => encrypt_stream!(ChaCha20Poly1305, plaintext, key, iv),
"XCHACHA20-POLY1305" => encrypt_stream!(XChaCha20Poly1305, plaintext, key, iv),
"XSALSA20-POLY1305" => encrypt_stream!(XSalsa20Poly1305, plaintext, key, iv),
Expand Down Expand Up @@ -509,6 +537,42 @@ mod tests {
tdef: TypeDef::bytes().fallible(),
}

aes_128_gcm {
args: func_args![plaintext: value!("morethan1blockofdata"), algorithm: "AES-128-GCM", key: b"16_bytes_xxxxxxx", iv: b"12_bytes_xxx"],
want: Ok(value!(b"\xc2\xf1\x8b\t\xd5\x0c\xad/B\x08W\xcb\x13\xdb\xe2$\x96A\xcc\xb8T`+\x99f\x0cc/\x08B\x083\xb1m\xb8\x05")),
tdef: TypeDef::bytes().fallible(),
}

aes_192_gcm {
args: func_args![plaintext: value!("morethan1blockofdata"), algorithm: "AES-192-GCM", key: b"24_bytes_xxxxxxxxxxxxxxx", iv: b"12_bytes_xxx"],
want: Ok(value!(b",\x8fI\xe6\x15\x8c\xeb\x95lq}\xe52\xfc\x0e\x808\x8b@\xca\\\xe5\xd0uR\x9cS\x02\xf6\xad\xa1\xb2W\xf47\xe2")),
tdef: TypeDef::bytes().fallible(),
}

aes_256_gcm {
args: func_args![plaintext: value!("morethan1blockofdata"), algorithm: "AES-256-GCM", key: b"32_bytes_xxxxxxxxxxxxxxxxxxxxxxx", iv: b"12_bytes_xxx"],
want: Ok(value!(b"\xc7\x03\xe0\xbd\xf7=N\x8cg\xc5\x94\xa3[\xa0\x1b<yF\xe9\xe7\xab{\xbc5\xc3\xcb\xc6Em\xb8\x02\xa8\x1ej\x86L")),
tdef: TypeDef::bytes().fallible(),
}

aes_128_gcm_16 {
args: func_args![plaintext: value!("morethan1blockofdata"), algorithm: "AES-128-GCM-16", key: b"16_bytes_xxxxxxx", iv: b"16_bytes_xxxxxxx"],
want: Ok(value!(b"PW{y.\x07\xa2.6\x93\x0b\x03z\xe1\xccI\x90\x98A\xb9\xe1\x1d\xc2\xb2Q\xbbl\xf2XX\xe1\x15|\xebKh")),
tdef: TypeDef::bytes().fallible(),
}

aes_192_gcm_16 {
args: func_args![plaintext: value!("morethan1blockofdata"), algorithm: "AES-192-GCM-16", key: b"24_bytes_xxxxxxxxxxxxxxx", iv: b"16_bytes_xxxxxxx"],
want: Ok(value!(b"\x01\xb7\xcc\xb14\xb4rM\x1b\xab\x96&~9p~\x038\xcd\xafN\xed\x1f#&\xc5C\xec\xf3\xc4\xc6iA\x07\xa6\xaa")),
tdef: TypeDef::bytes().fallible(),
}

aes_256_gcm_16 {
args: func_args![plaintext: value!("morethan1blockofdata"), algorithm: "AES-256-GCM-16", key: b"32_bytes_xxxxxxxxxxxxxxxxxxxxxxx", iv: b"16_bytes_xxxxxxx"],
want: Ok(value!(b"\xd0\xe9@m\r\xc0b/Qg)\x10\x86\x91\xfb\xe7\x86\xa3\xc9C\xff0\xd3\x99\xdb3\xf0\xc3\xce\xf4\x05\xbb\xcc\xa0\x97B")),
tdef: TypeDef::bytes().fallible(),
}

chacha20_poly1305 {
args: func_args![plaintext: value!("morethan1blockofdata"), algorithm: "CHACHA20-POLY1305", key: "32_bytes_xxxxxxxxxxxxxxxxxxxxxxx", iv: "12_bytes_xxx"],
want: Ok(value!(b"\x14m\xe3\xc9\xbc!\xafu\xe31\xb9\x17\x8f\x9bOo0}n\xf4{$\x95\x0f\xa0\x820\xb7R\xe3.{\xd7?\x96\x10")),
Expand Down