mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 04:50:36 +00:00
Implement hashing algorithms + HMac support (#193)
This commit is contained in:
parent
cf513c6724
commit
5a292aabc5
9 changed files with 457 additions and 0 deletions
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -8,6 +8,24 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Added a builtin API for hashing and calculating HMACs as part of the `serde` library
|
||||
|
||||
Basic usage:
|
||||
|
||||
```lua
|
||||
local serde = require("@lune/serde")
|
||||
local hash = serde.hash("sha256", "a message to hash")
|
||||
local hmac = serde.hmac("sha256", "a message to hash", "a secret string")
|
||||
|
||||
print(hash)
|
||||
print(hmac)
|
||||
```
|
||||
|
||||
The returned hashes are sequences of lowercase hexadecimal digits. The following algorithms are supported:
|
||||
`md5`, `sha1`, `sha224`, `sha256`, `sha384`, `sha512`, `sha3-224`, `sha3-256`, `sha3-384`, `sha3-512`, `blake3`
|
||||
|
||||
## `0.8.5` - June 1st, 2024
|
||||
|
||||
### Changed
|
||||
|
|
48
Cargo.lock
generated
48
Cargo.lock
generated
|
@ -273,6 +273,7 @@ dependencies = [
|
|||
"cc",
|
||||
"cfg-if",
|
||||
"constant_time_eq 0.3.0",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1339,6 +1340,15 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keccak"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
|
||||
dependencies = [
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -1582,13 +1592,20 @@ name = "lune-std-serde"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"blake3",
|
||||
"bstr",
|
||||
"digest",
|
||||
"hmac",
|
||||
"lune-utils",
|
||||
"lz4",
|
||||
"md-5",
|
||||
"mlua",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sha1 0.10.6",
|
||||
"sha2",
|
||||
"sha3",
|
||||
"tokio",
|
||||
"toml",
|
||||
]
|
||||
|
@ -1666,6 +1683,16 @@ dependencies = [
|
|||
"regex-automata 0.1.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.2"
|
||||
|
@ -2665,6 +2692,27 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha3"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
|
|
|
@ -29,6 +29,16 @@ serde_json = { version = "1.0", features = ["preserve_order"] }
|
|||
serde_yaml = "0.9"
|
||||
toml = { version = "0.8", features = ["preserve_order"] }
|
||||
|
||||
digest = "0.10.7"
|
||||
hmac = "0.12.1"
|
||||
md-5 = "0.10.6"
|
||||
sha1 = "0.10.6"
|
||||
sha2 = "0.10.8"
|
||||
sha3 = "0.10.8"
|
||||
# This feature MIGHT break due to the unstable nature of the digest crate.
|
||||
# Check before updating it.
|
||||
blake3 = { version = "1.5.0", features = ["traits-preview"] }
|
||||
|
||||
tokio = { version = "1", default-features = false, features = [
|
||||
"rt",
|
||||
"io-util",
|
||||
|
|
234
crates/lune-std-serde/src/hash.rs
Normal file
234
crates/lune-std-serde/src/hash.rs
Normal file
|
@ -0,0 +1,234 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use bstr::BString;
|
||||
use md5::Md5;
|
||||
use mlua::prelude::*;
|
||||
|
||||
use blake3::Hasher as Blake3;
|
||||
use sha1::Sha1;
|
||||
use sha2::{Sha224, Sha256, Sha384, Sha512};
|
||||
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
|
||||
|
||||
pub struct HashOptions {
|
||||
algorithm: HashAlgorithm,
|
||||
message: BString,
|
||||
secret: Option<BString>,
|
||||
// seed: Option<BString>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum HashAlgorithm {
|
||||
Md5,
|
||||
Sha1,
|
||||
// SHA-2 variants
|
||||
Sha2_224,
|
||||
Sha2_256,
|
||||
Sha2_384,
|
||||
Sha2_512,
|
||||
// SHA-3 variants
|
||||
Sha3_224,
|
||||
Sha3_256,
|
||||
Sha3_384,
|
||||
Sha3_512,
|
||||
// Blake3
|
||||
Blake3,
|
||||
}
|
||||
|
||||
impl HashAlgorithm {
|
||||
pub fn list_all_as_string() -> String {
|
||||
[
|
||||
"md5", "sha1", "sha224", "sha256", "sha384", "sha512", "sha3-224", "sha3-256",
|
||||
"sha3-384", "sha3-512", "blake3",
|
||||
]
|
||||
.join(", ")
|
||||
}
|
||||
}
|
||||
|
||||
impl HashOptions {
|
||||
/**
|
||||
Computes the hash for the `message` using whatever `algorithm` is
|
||||
contained within this struct and returns it as a string of hex digits.
|
||||
*/
|
||||
#[inline]
|
||||
#[must_use = "hashing a message is useless without using the resulting hash"]
|
||||
pub fn hash(self) -> String {
|
||||
use digest::Digest;
|
||||
|
||||
let message = self.message;
|
||||
let bytes = match self.algorithm {
|
||||
HashAlgorithm::Md5 => Md5::digest(message).to_vec(),
|
||||
HashAlgorithm::Sha1 => Sha1::digest(message).to_vec(),
|
||||
HashAlgorithm::Sha2_224 => Sha224::digest(message).to_vec(),
|
||||
HashAlgorithm::Sha2_256 => Sha256::digest(message).to_vec(),
|
||||
HashAlgorithm::Sha2_384 => Sha384::digest(message).to_vec(),
|
||||
HashAlgorithm::Sha2_512 => Sha512::digest(message).to_vec(),
|
||||
|
||||
HashAlgorithm::Sha3_224 => Sha3_224::digest(message).to_vec(),
|
||||
HashAlgorithm::Sha3_256 => Sha3_256::digest(message).to_vec(),
|
||||
HashAlgorithm::Sha3_384 => Sha3_384::digest(message).to_vec(),
|
||||
HashAlgorithm::Sha3_512 => Sha3_512::digest(message).to_vec(),
|
||||
|
||||
HashAlgorithm::Blake3 => Blake3::digest(message).to_vec(),
|
||||
};
|
||||
|
||||
// We don't want to return raw binary data generally, since that's not
|
||||
// what most people want a hash for. So we have to make a hex string.
|
||||
bytes
|
||||
.iter()
|
||||
.fold(String::with_capacity(bytes.len() * 2), |mut output, b| {
|
||||
let _ = write!(output, "{b:02x}");
|
||||
output
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
Computes the HMAC for the `message` using whatever `algorithm` and
|
||||
`secret` are contained within this struct. The computed value is
|
||||
returned as a string of hex digits.
|
||||
|
||||
# Errors
|
||||
|
||||
If the `secret` is not provided or is otherwise invalid.
|
||||
*/
|
||||
#[inline]
|
||||
pub fn hmac(self) -> LuaResult<String> {
|
||||
use hmac::{Hmac, Mac, SimpleHmac};
|
||||
|
||||
let secret = self
|
||||
.secret
|
||||
.ok_or_else(|| LuaError::FromLuaConversionError {
|
||||
from: "nil",
|
||||
to: "string or buffer",
|
||||
message: Some("Argument #3 missing or nil".to_string()),
|
||||
})?;
|
||||
|
||||
/*
|
||||
These macros exist to remove what would ultimately be dozens of
|
||||
repeating lines. Essentially, there's several step to processing
|
||||
HMacs, which expands into the 3 lines you see below. However,
|
||||
the Hmac struct is specialized towards eager block-based processes.
|
||||
In order to support anything else, like blake3, there's a second
|
||||
type named `SimpleHmac`. This results in duplicate macros like
|
||||
there are below.
|
||||
*/
|
||||
macro_rules! hmac {
|
||||
($Type:ty) => {{
|
||||
let mut mac: Hmac<$Type> = Hmac::new_from_slice(&secret).into_lua_err()?;
|
||||
mac.update(&self.message);
|
||||
mac.finalize().into_bytes().to_vec()
|
||||
}};
|
||||
}
|
||||
macro_rules! hmac_no_blocks {
|
||||
($Type:ty) => {{
|
||||
let mut mac: SimpleHmac<$Type> =
|
||||
SimpleHmac::new_from_slice(&secret).into_lua_err()?;
|
||||
mac.update(&self.message);
|
||||
mac.finalize().into_bytes().to_vec()
|
||||
}};
|
||||
}
|
||||
|
||||
let bytes = match self.algorithm {
|
||||
HashAlgorithm::Md5 => hmac!(Md5),
|
||||
HashAlgorithm::Sha1 => hmac!(Sha1),
|
||||
|
||||
HashAlgorithm::Sha2_224 => hmac!(Sha224),
|
||||
HashAlgorithm::Sha2_256 => hmac!(Sha256),
|
||||
HashAlgorithm::Sha2_384 => hmac!(Sha384),
|
||||
HashAlgorithm::Sha2_512 => hmac!(Sha512),
|
||||
|
||||
HashAlgorithm::Sha3_224 => hmac!(Sha3_224),
|
||||
HashAlgorithm::Sha3_256 => hmac!(Sha3_256),
|
||||
HashAlgorithm::Sha3_384 => hmac!(Sha3_384),
|
||||
HashAlgorithm::Sha3_512 => hmac!(Sha3_512),
|
||||
|
||||
HashAlgorithm::Blake3 => hmac_no_blocks!(Blake3),
|
||||
};
|
||||
Ok(bytes
|
||||
.iter()
|
||||
.fold(String::with_capacity(bytes.len() * 2), |mut output, b| {
|
||||
let _ = write!(output, "{b:02x}");
|
||||
output
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for HashAlgorithm {
|
||||
fn from_lua(value: LuaValue<'lua>, _lua: &'lua Lua) -> LuaResult<Self> {
|
||||
if let LuaValue::String(str) = value {
|
||||
/*
|
||||
Casing tends to vary for algorithms, so rather than force
|
||||
people to remember it we'll just accept any casing.
|
||||
*/
|
||||
let str = str.to_str()?.to_ascii_lowercase();
|
||||
match str.as_str() {
|
||||
"md5" => Ok(Self::Md5),
|
||||
"sha1" => Ok(Self::Sha1),
|
||||
|
||||
"sha224" => Ok(Self::Sha2_224),
|
||||
"sha256" => Ok(Self::Sha2_256),
|
||||
"sha384" => Ok(Self::Sha2_384),
|
||||
"sha512" => Ok(Self::Sha2_512),
|
||||
|
||||
"sha3-224" => Ok(Self::Sha3_224),
|
||||
"sha3-256" => Ok(Self::Sha3_256),
|
||||
"sha3-384" => Ok(Self::Sha3_384),
|
||||
"sha3-512" => Ok(Self::Sha3_512),
|
||||
|
||||
"blake3" => Ok(Self::Blake3),
|
||||
|
||||
_ => Err(LuaError::FromLuaConversionError {
|
||||
from: "string",
|
||||
to: "HashAlgorithm",
|
||||
message: Some(format!(
|
||||
"Invalid hashing algorithm '{str}', valid kinds are:\n{}",
|
||||
HashAlgorithm::list_all_as_string()
|
||||
)),
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
Err(LuaError::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "HashAlgorithm",
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLuaMulti<'lua> for HashOptions {
|
||||
fn from_lua_multi(mut values: LuaMultiValue<'lua>, lua: &'lua Lua) -> LuaResult<Self> {
|
||||
let algorithm = values
|
||||
.pop_front()
|
||||
.map(|value| HashAlgorithm::from_lua(value, lua))
|
||||
.transpose()?
|
||||
.ok_or_else(|| LuaError::FromLuaConversionError {
|
||||
from: "nil",
|
||||
to: "HashAlgorithm",
|
||||
message: Some("Argument #1 missing or nil".to_string()),
|
||||
})?;
|
||||
let message = values
|
||||
.pop_front()
|
||||
.map(|value| BString::from_lua(value, lua))
|
||||
.transpose()?
|
||||
.ok_or_else(|| LuaError::FromLuaConversionError {
|
||||
from: "nil",
|
||||
to: "string or buffer",
|
||||
message: Some("Argument #2 missing or nil".to_string()),
|
||||
})?;
|
||||
let secret = values
|
||||
.pop_front()
|
||||
.map(|value| BString::from_lua(value, lua))
|
||||
.transpose()?;
|
||||
// let seed = values
|
||||
// .pop_front()
|
||||
// .map(|value| BString::from_lua(value, lua))
|
||||
// .transpose()?;
|
||||
|
||||
Ok(HashOptions {
|
||||
algorithm,
|
||||
message,
|
||||
secret,
|
||||
// seed,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -7,9 +7,11 @@ use lune_utils::TableBuilder;
|
|||
|
||||
mod compress_decompress;
|
||||
mod encode_decode;
|
||||
mod hash;
|
||||
|
||||
pub use self::compress_decompress::{compress, decompress, CompressDecompressFormat};
|
||||
pub use self::encode_decode::{decode, encode, EncodeDecodeConfig, EncodeDecodeFormat};
|
||||
pub use self::hash::HashOptions;
|
||||
|
||||
/**
|
||||
Creates the `serde` standard library module.
|
||||
|
@ -24,6 +26,8 @@ pub fn module(lua: &Lua) -> LuaResult<LuaTable> {
|
|||
.with_function("decode", serde_decode)?
|
||||
.with_async_function("compress", serde_compress)?
|
||||
.with_async_function("decompress", serde_decompress)?
|
||||
.with_function("hash", hash_message)?
|
||||
.with_function("hmac", hmac_message)?
|
||||
.build_readonly()
|
||||
}
|
||||
|
||||
|
@ -55,3 +59,11 @@ async fn serde_decompress(
|
|||
let bytes = decompress(bs, format).await?;
|
||||
lua.create_string(bytes)
|
||||
}
|
||||
|
||||
fn hash_message(lua: &Lua, options: HashOptions) -> LuaResult<LuaString> {
|
||||
lua.create_string(options.hash())
|
||||
}
|
||||
|
||||
fn hmac_message(lua: &Lua, options: HashOptions) -> LuaResult<LuaString> {
|
||||
lua.create_string(options.hmac()?)
|
||||
}
|
||||
|
|
|
@ -230,6 +230,8 @@ create_tests! {
|
|||
serde_json_encode: "serde/json/encode",
|
||||
serde_toml_decode: "serde/toml/decode",
|
||||
serde_toml_encode: "serde/toml/encode",
|
||||
serde_hashing_hash: "serde/hashing/hash",
|
||||
serde_hashing_hmac: "serde/hashing/hmac",
|
||||
}
|
||||
|
||||
#[cfg(feature = "std-stdio")]
|
||||
|
|
48
tests/serde/hashing/hash.luau
Normal file
48
tests/serde/hashing/hash.luau
Normal file
|
@ -0,0 +1,48 @@
|
|||
local serde = require("@lune/serde")
|
||||
|
||||
local TEST_INPUT =
|
||||
"Luau is a fast, small, safe, gradually typed embeddable scripting language derived from Lua."
|
||||
|
||||
local function test_case_hash(algorithm: serde.HashAlgorithm, expected: string)
|
||||
assert(
|
||||
serde.hash(algorithm, TEST_INPUT) == expected,
|
||||
`hashing algorithm '{algorithm}' did not hash test string correctly`
|
||||
)
|
||||
assert(
|
||||
serde.hash(algorithm, buffer.fromstring(TEST_INPUT)) == expected,
|
||||
`hashing algorithm '{algorithm}' did not hash test buffer correctly`
|
||||
)
|
||||
end
|
||||
|
||||
test_case_hash("blake3", "eccfe3a6696b2a1861c64cc78663cff51301058e5dc22bb6249e7e1e0173d7fe")
|
||||
test_case_hash("md5", "2aed9e020b49d219dc383884c5bd7acd")
|
||||
test_case_hash("sha1", "9dce74190857f36e6d3f5e8eb7fe704a74060726")
|
||||
test_case_hash("sha224", "f7ccd8a5f2697df8470b66f03824e073075292a1fab40d3a2ddc2e83")
|
||||
test_case_hash("sha256", "f1d149bfd1ea38833ae6abf2a6fece1531532283820d719272e9cf3d9344efea")
|
||||
test_case_hash(
|
||||
"sha384",
|
||||
"f6da4b47846c6016a9b32f01b861e45195cf1fa6fc5c9dd2257f7dc1c14092f11001839ec1223c30ab7adb7370812863"
|
||||
)
|
||||
test_case_hash(
|
||||
"sha512",
|
||||
"49fd834fdf3d4eaf4d4aff289acfc24d649f81cee7a5a7940e5c86854e04816f0a97c53f2ca4908969a512ec5ad1dc466422e3928f5ce3da9913959315df807c"
|
||||
)
|
||||
test_case_hash("sha3-224", "56a4dd1ff1bd9baff7f8bbe380dbf2c75b073161693f94ebf91aeee5")
|
||||
test_case_hash("sha3-256", "ee01be10e0dc133cd702999e854b396f40b039d5ba6ddec9d04bf8623ba04dd7")
|
||||
test_case_hash(
|
||||
"sha3-384",
|
||||
"e992f31e638b47802f33a4327c0a951823e32491ddcef5af9ce18cff84475c98ced23928d47ef51a8a4299dfe2ece361"
|
||||
)
|
||||
test_case_hash(
|
||||
"sha3-512",
|
||||
"08bd02aca3052b7740de80b8e8b9969dc9059a4bfae197095430e0aa204fbd3afb11731b127559b90c2f7e295835ea844ddbb29baf2fdb1d823046052c120fc9"
|
||||
)
|
||||
|
||||
local failed = pcall(serde.hash, "a random string" :: any, "input that shouldn't be hashed")
|
||||
assert(failed == false, "serde.hash shouldn't allow invalid algorithms passed to it!")
|
||||
|
||||
assert(
|
||||
serde.hash("sha256", "\0oh no invalid utf-8\127\0\255")
|
||||
== "c18ed3188f9e93f9ecd3582d7398c45120b0b30a0e26243809206228ab711b78",
|
||||
"serde.hash should hash invalid UTF-8 just fine"
|
||||
)
|
60
tests/serde/hashing/hmac.luau
Normal file
60
tests/serde/hashing/hmac.luau
Normal file
|
@ -0,0 +1,60 @@
|
|||
local serde = require("@lune/serde")
|
||||
|
||||
local INPUT_STRING = "important data to verify the integrity of"
|
||||
|
||||
-- if you read this string, you're obligated to keep it a secret! :-)
|
||||
local SECRET_STRING = "don't read this we operate on the honor system"
|
||||
|
||||
local function test_case_hmac(algorithm: serde.HashAlgorithm, expected: string)
|
||||
assert(
|
||||
serde.hmac(algorithm, INPUT_STRING, SECRET_STRING) == expected,
|
||||
`HMAC test for algorithm '{algorithm}' was not correct with string input and string secret`
|
||||
)
|
||||
assert(
|
||||
serde.hmac(algorithm, INPUT_STRING, buffer.fromstring(SECRET_STRING)) == expected,
|
||||
`HMAC test for algorithm '{algorithm}' was not correct with string input and buffer secret`
|
||||
)
|
||||
assert(
|
||||
serde.hmac(algorithm, buffer.fromstring(INPUT_STRING), SECRET_STRING) == expected,
|
||||
`HMAC test for algorithm '{algorithm}' was not correct with buffer input and string secret`
|
||||
)
|
||||
assert(
|
||||
serde.hmac(algorithm, buffer.fromstring(INPUT_STRING), buffer.fromstring(SECRET_STRING))
|
||||
== expected,
|
||||
`HMAC test for algorithm '{algorithm}' was not correct with buffer input and buffer secret`
|
||||
)
|
||||
end
|
||||
|
||||
test_case_hmac("blake3", "1d9c1b9405567fc565c2c3c6d6c0e170be72a2623d29911f43cb2ce42a373c01")
|
||||
test_case_hmac("md5", "525379669c93ab5f59d2201024145b79")
|
||||
test_case_hmac("sha1", "75227c11ed65133788feab0ce7eb8efc8c1f0517")
|
||||
test_case_hmac("sha224", "47a4857d7d7e1070f47f76558323e03471a918facaf3667037519c29")
|
||||
test_case_hmac("sha256", "4a4816ab8d4b780a8cf131e34a3df25e4c7bc4eba453cd86e50271aab4e95f45")
|
||||
test_case_hmac(
|
||||
"sha384",
|
||||
"6b24aeae78d0f84ec8a4669b24bda1131205535233c344f4262c1f90f29af04c5537612c269bbab8aaca9d8293f4a280"
|
||||
)
|
||||
test_case_hmac(
|
||||
"sha512",
|
||||
"9fffa071241e2f361f8a47a97d251c1d4aae37498efbc49745bf9916d8431f1f361080d350067ed65744d3da42956da33ec57b04901a5fd63a891381a1485ef7"
|
||||
)
|
||||
test_case_hmac("sha3-224", "ea102dfaa74aa285555bdba29a04429dfd4e997fa40322459094929f")
|
||||
test_case_hmac("sha3-256", "17bde287e4692e5b7f281e444efefe92e00696a089570bd6814fd0e03d7763d2")
|
||||
test_case_hmac(
|
||||
"sha3-384",
|
||||
"24f68401653d25f36e7ee8635831215f8b46710d4e133c9d1e091e5972c69b0f1d0cb80f5507522fa174d5c4746963c1"
|
||||
)
|
||||
test_case_hmac(
|
||||
"sha3-512",
|
||||
"d2566d156c254ced0101159f97187dbf48d900b8361fa5ebdd7e81409856b1b6a21d93a1fb6e8f700e75620d244ab9e894454030da12d158e9362ffe090d2669"
|
||||
)
|
||||
|
||||
local failed =
|
||||
pcall(serde.hmac, "a random string" :: any, "input that shouldn't be hashed", "not a secret")
|
||||
assert(failed == false, "serde.hmac shouldn't allow invalid algorithms passed to it!")
|
||||
|
||||
assert(
|
||||
serde.hmac("sha256", "\0oh no invalid utf-8\127\0\255", SECRET_STRING)
|
||||
== "1f0d7f65016e9e4c340e3ba23da2483a7dc101ce8a9405f834c23f2e19232c3d",
|
||||
"serde.hmac should hash invalid UTF-8 just fine"
|
||||
)
|
|
@ -2,6 +2,19 @@ export type EncodeDecodeFormat = "json" | "yaml" | "toml"
|
|||
|
||||
export type CompressDecompressFormat = "brotli" | "gzip" | "lz4" | "zlib"
|
||||
|
||||
export type HashAlgorithm =
|
||||
"md5"
|
||||
| "sha1"
|
||||
| "sha224"
|
||||
| "sha256"
|
||||
| "sha384"
|
||||
| "sha512"
|
||||
| "sha3-224"
|
||||
| "sha3-256"
|
||||
| "sha3-384"
|
||||
| "sha3-512"
|
||||
| "blake3"
|
||||
|
||||
--[=[
|
||||
@class Serde
|
||||
|
||||
|
@ -120,4 +133,16 @@ function serde.decompress(format: CompressDecompressFormat, s: buffer | string):
|
|||
return nil :: any
|
||||
end
|
||||
|
||||
function serde.hash(algorithm: HashAlgorithm, message: string | buffer): string
|
||||
return nil :: any
|
||||
end
|
||||
|
||||
function serde.hmac(
|
||||
algorithm: HashAlgorithm,
|
||||
message: string | buffer,
|
||||
secret: string | buffer
|
||||
): string
|
||||
return nil :: any
|
||||
end
|
||||
|
||||
return serde
|
||||
|
|
Loading…
Reference in a new issue