mirror of
https://github.com/lune-org/lune.git
synced 2025-04-10 21:40:54 +01:00
Implement hashing and hmac again
This commit is contained in:
parent
cf513c6724
commit
81f9080893
4 changed files with 287 additions and 0 deletions
48
Cargo.lock
generated
48
Cargo.lock
generated
|
@ -273,6 +273,7 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"constant_time_eq 0.3.0",
|
"constant_time_eq 0.3.0",
|
||||||
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1339,6 +1340,15 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keccak"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
|
||||||
|
dependencies = [
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -1582,13 +1592,20 @@ name = "lune-std-serde"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-compression",
|
"async-compression",
|
||||||
|
"blake3",
|
||||||
"bstr",
|
"bstr",
|
||||||
|
"digest",
|
||||||
|
"hmac",
|
||||||
"lune-utils",
|
"lune-utils",
|
||||||
"lz4",
|
"lz4",
|
||||||
|
"md-5",
|
||||||
"mlua",
|
"mlua",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
"sha1 0.10.6",
|
||||||
|
"sha2",
|
||||||
|
"sha3",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
@ -1666,6 +1683,16 @@ dependencies = [
|
||||||
"regex-automata 0.1.10",
|
"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]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.2"
|
version = "2.7.2"
|
||||||
|
@ -2665,6 +2692,27 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
|
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]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
|
|
@ -29,6 +29,16 @@ serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
serde_yaml = "0.9"
|
serde_yaml = "0.9"
|
||||||
toml = { version = "0.8", features = ["preserve_order"] }
|
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 = [
|
tokio = { version = "1", default-features = false, features = [
|
||||||
"rt",
|
"rt",
|
||||||
"io-util",
|
"io-util",
|
||||||
|
|
216
crates/lune-std-serde/src/hash.rs
Normal file
216
crates/lune-std-serde/src/hash.rs
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
#[must_use = "hashing a message is useless without using the resulting hash"]
|
||||||
|
pub fn hash(self) -> Vec<u8> {
|
||||||
|
use digest::Digest;
|
||||||
|
|
||||||
|
let message = self.message;
|
||||||
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Computes the HMAC for the `message` using whatever `algorithm` and
|
||||||
|
`secret` are contained within this struct.
|
||||||
|
|
||||||
|
# Errors
|
||||||
|
|
||||||
|
If the `secret` is not provided or is otherwise invalid.
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
pub fn hmac(self) -> LuaResult<Vec<u8>> {
|
||||||
|
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);
|
||||||
|
Ok(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);
|
||||||
|
Ok(mac.finalize().into_bytes().to_vec())
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 compress_decompress;
|
||||||
mod encode_decode;
|
mod encode_decode;
|
||||||
|
mod hash;
|
||||||
|
|
||||||
pub use self::compress_decompress::{compress, decompress, CompressDecompressFormat};
|
pub use self::compress_decompress::{compress, decompress, CompressDecompressFormat};
|
||||||
pub use self::encode_decode::{decode, encode, EncodeDecodeConfig, EncodeDecodeFormat};
|
pub use self::encode_decode::{decode, encode, EncodeDecodeConfig, EncodeDecodeFormat};
|
||||||
|
pub use self::hash::HashOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates the `serde` standard library module.
|
Creates the `serde` standard library module.
|
||||||
|
@ -24,6 +26,8 @@ pub fn module(lua: &Lua) -> LuaResult<LuaTable> {
|
||||||
.with_function("decode", serde_decode)?
|
.with_function("decode", serde_decode)?
|
||||||
.with_async_function("compress", serde_compress)?
|
.with_async_function("compress", serde_compress)?
|
||||||
.with_async_function("decompress", serde_decompress)?
|
.with_async_function("decompress", serde_decompress)?
|
||||||
|
.with_function("hash", hash_message)?
|
||||||
|
.with_function("hmac", hmac_message)?
|
||||||
.build_readonly()
|
.build_readonly()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,3 +59,12 @@ async fn serde_decompress(
|
||||||
let bytes = decompress(bs, format).await?;
|
let bytes = decompress(bs, format).await?;
|
||||||
lua.create_string(bytes)
|
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> {
|
||||||
|
let bytes = options.hmac()?;
|
||||||
|
lua.create_string(bytes)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue