Skip to content

Commit

Permalink
crypto builtins (microsoft#57)
Browse files Browse the repository at this point in the history

Signed-off-by: Anand Krishnamoorthi <[email protected]>
  • Loading branch information
anakrish authored Dec 6, 2023
1 parent ab968c2 commit 70bf371
Show file tree
Hide file tree
Showing 14 changed files with 341 additions and 35 deletions.
32 changes: 27 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,47 @@ edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
default = ["full-opa"]

crypto = ["dep:constant_time_eq", "dep:hmac", "dep:hex", "dep:md-5", "dep:sha1", "dep:sha2"]
deprecated = []
glob = ["dep:wax"]
regex = ["dep:regex"]
semver = ["dep:semver"]
yaml = ["serde_yaml"]
full-opa = ["crypto", "deprecated", "glob", "regex", "semver", "yaml"]

[dependencies]
anyhow = "1.0.66"
semver = "1.0.20"
serde = {version = "1.0.150", features = ["derive", "rc"] }
serde_json = {version = "1.0.89", features = ["arbitrary_precision"] }
serde_yaml = "0.9.16"
serde_yaml = {version = "0.9.16", optional = true }
log = "0.4.17"
env_logger="0.10.0"
lazy_static = "1.4.0"
rand = "0.8.5"
data-encoding = "2.4.0"
regex = "1.10.2"
num = "0.4.1"
rust_decimal = { version = "1.33.1", features = ["serde-with-arbitrary-precision"] }
glob = "0.3.1"
wax = { version = "0.6.0", features = [], default-features = false }



# Crypto
constant_time_eq = {version = "0.3.0", optional = true}
hmac = {version = "0.12.1", optional = true}
sha2 = {version= "0.10.8", optional = true}
hex = {version = "0.4.3", optional = true}
sha1 = {version = "0.10.6", optional = true}
md-5 = {version = "0.10.6", optional = true}

regex = {version = "1.10.2", optional = true}
semver = {version = "1.0.20", optional = true}
wax = { version = "0.6.0", features = [], default-features = false, optional = true }

[dev-dependencies]
clap = { version = "4.4.7", features = ["derive"] }
serde_yaml = "0.9.16"
test-generator = "0.3.1"
walkdir = "2.3.2"

Expand All @@ -38,6 +59,7 @@ debug = true
name="opa"
harness=false
test=false
required-features = ["full-opa"]

[[test]]
name="aci"
Expand Down
148 changes: 148 additions & 0 deletions src/builtins/crypto.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use crate::ast::{Expr, Ref};
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_string};
use crate::lexer::Span;
use crate::value::Value;

use std::collections::HashMap;

use anyhow::{bail, Result};
use constant_time_eq::constant_time_eq;
use hmac::{Hmac, Mac};
use md5::{Digest, Md5};
use sha1::Sha1;
use sha2::{Sha256, Sha512};

pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("crypto.hmac.equal", (hmac_equal_fixed_time, 2));
m.insert("crypto.hmac.md5", (hmac_md5, 2));
m.insert("crypto.hmac.sha1", (hmac_sha1, 2));
m.insert("crypto.hmac.sha256", (hmac_sha256, 2));
m.insert("crypto.hmac.sha512", (hmac_sha512, 2));

m.insert("crypto.md5", (crypto_md5, 1));
m.insert("crypto.sha1", (crypto_sha1, 1));
m.insert("crypto.sha256", (crypto_sha256, 1));
}

fn hmac_equal_fixed_time(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "crypto.hmac.equal";
ensure_args_count(span, name, params, args, 2)?;

let hmac1 = ensure_string(name, &params[0], &args[0])?;
let hmac2 = ensure_string(name, &params[1], &args[1])?;

Ok(Value::Bool(constant_time_eq(
hmac1.as_bytes(),
hmac2.as_bytes(),
)))
}

fn hmac_md5(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "crypto.hmac.md5";
ensure_args_count(span, name, params, args, 2)?;

let x = ensure_string(name, &params[0], &args[0])?;
let key = ensure_string(name, &params[1], &args[1])?;

let mut hmac = Hmac::<Md5>::new_from_slice(key.as_bytes())
.or_else(|_| bail!(span.error("failed to create hmac instance")))?;

hmac.update(x.as_bytes());
let result = hmac.finalize();

Ok(Value::String(hex::encode(result.into_bytes()).into()))
}

fn hmac_sha1(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "crypto.hmac.sha1";
ensure_args_count(span, name, params, args, 2)?;

let x = ensure_string(name, &params[0], &args[0])?;
let key = ensure_string(name, &params[1], &args[1])?;

let mut hmac = Hmac::<Sha1>::new_from_slice(key.as_bytes())
.or_else(|_| bail!(span.error("failed to create hmac instance")))?;

hmac.update(x.as_bytes());
let result = hmac.finalize();

Ok(Value::String(hex::encode(result.into_bytes()).into()))
}

fn hmac_sha256(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "crypto.hmac.sha256";
ensure_args_count(span, name, params, args, 2)?;

let x = ensure_string(name, &params[0], &args[0])?;
let key = ensure_string(name, &params[1], &args[1])?;

let mut hmac = Hmac::<Sha256>::new_from_slice(key.as_bytes())
.or_else(|_| bail!(span.error("failed to create hmac instance")))?;

hmac.update(x.as_bytes());
let result = hmac.finalize();

Ok(Value::String(hex::encode(result.into_bytes()).into()))
}

fn hmac_sha512(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "crypto.hmac.sha512";
ensure_args_count(span, name, params, args, 2)?;

let x = ensure_string(name, &params[0], &args[0])?;
let key = ensure_string(name, &params[1], &args[1])?;

let mut hmac = Hmac::<Sha512>::new_from_slice(key.as_bytes())
.or_else(|_| bail!(span.error("failed to create hmac instance")))?;

hmac.update(x.as_bytes());
let result = hmac.finalize();

Ok(Value::String(hex::encode(result.into_bytes()).into()))
}

fn crypto_md5(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "crypto.md5";
ensure_args_count(span, name, params, args, 1)?;

let x = ensure_string(name, &params[0], &args[0])?;

let mut h = Md5::new();

h.update(x.as_bytes());
let result = h.finalize();

Ok(Value::String(hex::encode(result).into()))
}

fn crypto_sha1(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "crypto.sha1";
ensure_args_count(span, name, params, args, 1)?;

let x = ensure_string(name, &params[0], &args[0])?;

let mut h = Sha1::new();

h.update(x.as_bytes());
let result = h.finalize();

Ok(Value::String(hex::encode(result).into()))
}

fn crypto_sha256(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "crypto.sha256";
ensure_args_count(span, name, params, args, 1)?;

let x = ensure_string(name, &params[0], &args[0])?;

let mut h = Sha256::new();

h.update(x.as_bytes());
let result = h.finalize();

Ok(Value::String(hex::encode(result).into()))
}
2 changes: 2 additions & 0 deletions src/builtins/deprecated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ lazy_static! {
m.insert("all", (all, 1));
m.insert("any", (any, 1));
m.insert("set_diff", (set_diff, 2));

#[cfg(feature = "crypto")]
m.insert("re_match", (regex_match, 2));
m
};
Expand Down
13 changes: 10 additions & 3 deletions src/builtins/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("json.is_valid", (json_is_valid, 1));
m.insert("json.marshal", (json_marshal, 1));
m.insert("jsonunmarshal", (json_unmarshal, 1));
m.insert("yaml.is_valid", (yaml_is_valid, 1));
m.insert("yaml.marshal", (yaml_marshal, 1));
m.insert("yaml.unmarshal", (yaml_unmarshal, 1));

#[cfg(feature = "yaml")]
{
m.insert("yaml.is_valid", (yaml_is_valid, 1));
m.insert("yaml.marshal", (yaml_marshal, 1));
m.insert("yaml.unmarshal", (yaml_unmarshal, 1));
}
}

fn base64_decode(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
Expand All @@ -33,6 +37,7 @@ fn base64_decode(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Va
))
}

#[cfg(feature = "yaml")]
fn yaml_is_valid(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "yaml.is_valid";
ensure_args_count(span, name, params, args, 1)?;
Expand All @@ -41,6 +46,7 @@ fn yaml_is_valid(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Va
Ok(Value::Bool(Value::from_yaml_str(&yaml_str).is_ok()))
}

#[cfg(feature = "yaml")]
fn yaml_marshal(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "yaml.marshal";
ensure_args_count(span, name, params, args, 1)?;
Expand All @@ -51,6 +57,7 @@ fn yaml_marshal(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Val
))
}

#[cfg(feature = "yaml")]
fn yaml_unmarshal(span: &Span, params: &[Ref<Expr>], args: &[Value]) -> Result<Value> {
let name = "yaml.unmarshal";
ensure_args_count(span, name, params, args, 1)?;
Expand Down
19 changes: 17 additions & 2 deletions src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@ mod arrays;
mod bitwise;
pub mod comparison;
mod conversions;

#[cfg(feature = "crypto")]
mod crypto;
mod debugging;
#[cfg(feature = "deprecated")]
pub mod deprecated;

mod encoding;
#[cfg(feature = "glob")]
mod glob;
pub mod numbers;
mod objects;
#[cfg(feature = "regex")]
mod regex;
#[cfg(feature = "semver")]
mod semver;
pub mod sets;
mod strings;
Expand All @@ -34,6 +40,7 @@ use lazy_static::lazy_static;

pub type BuiltinFcn = (fn(&Span, &[Ref<Expr>], &[Value]) -> Result<Value>, u8);

#[cfg(feature = "deprecated")]
pub use deprecated::DEPRECATED;

#[rustfmt::skip]
Expand All @@ -48,8 +55,13 @@ lazy_static! {
sets::register(&mut m);
objects::register(&mut m);
strings::register(&mut m);

#[cfg(feature = "regex")]
regex::register(&mut m);

#[cfg(feature = "glob")]
glob::register(&mut m);

bitwise::register(&mut m);
conversions::register(&mut m);
//units::register(&mut m);
Expand All @@ -58,12 +70,15 @@ lazy_static! {
//token_signing::register(&mut m);
//token_verification::register(&mut m);
time::register(&mut m);
//cryptography::register(&mut m);

#[cfg(feature = "crypto")]
crypto::register(&mut m);
//graphs::register(&mut m);
//graphql::register(&mut m);
//http::register(&mut m);
//net::register(&mut m);
//uuid::register(&mut m);
#[cfg(feature = "semver")]
semver::register(&mut m);
//rego::register(&mut m);
//opa::register(&mut m);
Expand Down
Loading

0 comments on commit 70bf371

Please sign in to comment.