use crate::seqstring::global_string;
use crate::stack::{Stack, pop, push};
use crate::value::Value;
use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256};
use subtle::ConstantTimeEq;
type HmacSha256 = Hmac<Sha256>;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_sha256(stack: Stack) -> Stack {
assert!(!stack.is_null(), "sha256: stack is empty");
let (stack, value) = unsafe { pop(stack) };
match value {
Value::String(s) => {
let mut hasher = Sha256::new();
hasher.update(s.as_str().as_bytes());
let result = hasher.finalize();
let hex_digest = hex::encode(result);
unsafe { push(stack, Value::String(global_string(hex_digest))) }
}
_ => panic!("sha256: expected String on stack, got {:?}", value),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_hmac_sha256(stack: Stack) -> Stack {
assert!(!stack.is_null(), "hmac-sha256: stack is empty");
let (stack, key_value) = unsafe { pop(stack) };
let (stack, msg_value) = unsafe { pop(stack) };
match (msg_value, key_value) {
(Value::String(msg), Value::String(key)) => {
let mut mac = <HmacSha256 as Mac>::new_from_slice(key.as_str().as_bytes())
.expect("HMAC can take any key");
mac.update(msg.as_str().as_bytes());
let result = mac.finalize();
let hex_sig = hex::encode(result.into_bytes());
unsafe { push(stack, Value::String(global_string(hex_sig))) }
}
(msg, key) => panic!(
"hmac-sha256: expected (String, String) on stack, got ({:?}, {:?})",
msg, key
),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_constant_time_eq(stack: Stack) -> Stack {
assert!(!stack.is_null(), "constant-time-eq: stack is empty");
let (stack, b_value) = unsafe { pop(stack) };
let (stack, a_value) = unsafe { pop(stack) };
match (a_value, b_value) {
(Value::String(a), Value::String(b)) => {
let a_bytes = a.as_str().as_bytes();
let b_bytes = b.as_str().as_bytes();
let eq = a_bytes.ct_eq(b_bytes);
unsafe { push(stack, Value::Bool(bool::from(eq))) }
}
(a, b) => panic!(
"constant-time-eq: expected (String, String) on stack, got ({:?}, {:?})",
a, b
),
}
}