Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement cryptographic hashing via various algorithms #122

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
21d9185
feat: initial crypto library rust-side implementation
CompeyDev Oct 12, 2023
8539177
feat: sha1 & finalized hmac implementation on rust-side
CompeyDev Oct 12, 2023
40f63c9
feat: mostly finish rust-side implementation
CompeyDev Oct 12, 2023
897c48b
refactor: shorten trait bound declarations
CompeyDev Oct 12, 2023
cb5758e
feat: start work on luau-side exports
CompeyDev Oct 13, 2023
9a1fe03
refactor: work on reducing boilerplate
CompeyDev Oct 13, 2023
4db53ea
refactor: simplify code by removing traits n stuff
CompeyDev Oct 13, 2023
3dda088
refactor: refactor some more stuff and finalize, hash still inaccurate
CompeyDev Oct 15, 2023
40cfc59
fix: innaccurate hash
CompeyDev Oct 15, 2023
d33d1d3
feat: finalize sha1, sha256 & sha512 implementations
CompeyDev Oct 15, 2023
bfd33e3
fix: use trait & remove reassignment
CompeyDev Oct 15, 2023
3c2702b
refactor: small changes
CompeyDev Oct 15, 2023
12d23e7
feat: since we have interior mut, remove &Crypto impl
CompeyDev Oct 15, 2023
7fd5e60
feat: reduce boilerplate using macro (thanks, dekkonot\!)
CompeyDev Oct 15, 2023
eedf653
feat: implement md5 hashing algo
CompeyDev Oct 15, 2023
8cafaed
feat: impl Blake2 algo & reduce more boilerplate
CompeyDev Oct 15, 2023
32e7870
feat: change delim from FAT_ARROW to colon
CompeyDev Oct 15, 2023
544b2ef
chore: remove old crypto.rs implementation
CompeyDev Oct 15, 2023
421d9f0
merge: main -> feature/serde-crypto
CompeyDev Oct 15, 2023
8d5854a
fix: remove unneeded `with_table` builder method for `TableBuilder`
CompeyDev Oct 15, 2023
f05e1ca
feat: impl sha3 (256-bit & 512-bit)
CompeyDev Oct 15, 2023
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
71 changes: 71 additions & 0 deletions Cargo.lock

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

13 changes: 13 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,19 @@ serde_json = { version = "1.0", features = ["preserve_order"] }
serde_yaml = "0.9"
toml = { version = "0.8", features = ["preserve_order"] }

paste = "1.0.14"

base64 = "0.21.4"
hex = "0.4.3"
digest = "0.10.7"

md-5 = "0.10.6"
sha1 = "0.10.6"
sha2 = "0.10.8"
sha3 = "0.10.8"
blake2 = "0.10.6"


### NET

hyper = { version = "0.14", features = ["full"] }
Expand Down
153 changes: 153 additions & 0 deletions src/lune/builtins/serde/crypto.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use std::sync::Arc;
use std::sync::Mutex;

use anyhow::Result;
use base64::{engine::general_purpose as Base64, Engine as _};
use digest::Digest as _;
use mlua::prelude::*;

// TODO: Proper error handling, remove unwraps

macro_rules! impl_hash_algo {
($($algo:ident: $Type:ty),*) => {
#[derive(Clone)]
pub enum CryptoAlgo {
$(
$algo(Box<$Type>),
)*
}

impl CryptoAlgo {
pub fn update(&mut self, data: impl AsRef<[u8]>) {
match self {
$(
Self::$algo(hasher) => hasher.update(data),
)*
}
}

pub fn digest(&mut self, encoding: EncodingKind) -> Result<String> {
let computed = match self {
$(
Self::$algo(hasher) => hasher.clone().finalize_reset().to_vec(),
)*
};

match encoding {
EncodingKind::Utf8 => String::from_utf8(computed).map_err(anyhow::Error::from),
EncodingKind::Base64 => Ok(Base64::STANDARD.encode(computed)),
EncodingKind::Hex => Ok(hex::encode(&computed)),
}
}
}

impl Crypto {
$(
paste::item! {
pub fn [<$algo:snake:lower>]<T: ToString>(content: Option<T>) -> Self {
let constructed = Self {
algo: Arc::new(Mutex::new(CryptoAlgo::$algo(Box::new($Type::new())))),
};

match content {
Some(inner) => constructed.update(inner.to_string()).clone(),
None => constructed,
}
}
}
)*
}
}
}

// Macro call creates the CryptoAlgo enum and implementations for it
// It also adds a method corresponding to the enum in the `Crypto` struct
impl_hash_algo! {
Sha1: sha1::Sha1,
Sha256: sha2::Sha256,
Sha512: sha2::Sha512,
Md5: md5::Md5,
Blake2s256: blake2::Blake2s256,
Blake2b512: blake2::Blake2b512,
Sha3_256: sha3::Sha3_256,
Sha3_512: sha3::Sha3_512
}

#[derive(Clone)]
pub struct Crypto {
algo: Arc<Mutex<CryptoAlgo>>,
}

#[derive(PartialOrd, PartialEq, Ord, Eq)]
pub enum EncodingKind {
Utf8,
Base64,
Hex,
}

impl From<usize> for EncodingKind {
fn from(value: usize) -> Self {
match value {
0 => Self::Utf8,
1 => Self::Base64,
2 => Self::Hex,
_ => panic!("invalid value"),
}
}
}

impl From<String> for EncodingKind {
fn from(value: String) -> Self {
match value.to_lowercase().as_str() {
"utf8" => Self::Utf8,
"base64" => Self::Base64,
"hex" => Self::Hex,
&_ => panic!("invalid value"),
}
}
}

impl FromLua<'_> for EncodingKind {
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
match value {
LuaValue::Integer(int) => Ok(EncodingKind::from(int as usize)),
LuaValue::Number(num) => Ok(EncodingKind::from(num as usize)),
LuaValue::String(str) => Ok(EncodingKind::from(str.to_string_lossy().to_string())),

_ => Err(LuaError::FromLuaConversionError {
from: value.type_name(),
to: "EncodingKind",
message: Some("value must be a an Integer, Number or String".to_string()),
}),
}
}
}

trait CryptoResult {
fn update(&self, content: impl AsRef<[u8]>) -> &Self;
fn digest(&self, encoding: EncodingKind) -> Result<String>;
}

impl CryptoResult for Crypto {
fn update(&self, content: impl AsRef<[u8]>) -> &Crypto {
(self.algo.lock().unwrap()).update(content);

self
}

fn digest(&self, encoding: EncodingKind) -> Result<String> {
(*self.algo.lock().unwrap()).digest(encoding)
}
}

impl LuaUserData for Crypto {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("digest", |_, this, encoding| {
this.digest(encoding).map_err(mlua::Error::runtime)
});

methods.add_method("update", |_, this, content: String| {
Ok(this.update(content).clone())
});
}
}
34 changes: 34 additions & 0 deletions src/lune/builtins/serde/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use mlua::prelude::*;

pub(super) mod compress_decompress;
pub(super) mod crypto;
pub(super) mod encode_decode;

use compress_decompress::{compress, decompress, CompressDecompressFormat};
use crypto::Crypto;
use encode_decode::{EncodeDecodeConfig, EncodeDecodeFormat};

use crate::lune::util::TableBuilder;
Expand All @@ -14,6 +16,38 @@ pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
.with_function("decode", serde_decode)?
.with_async_function("compress", serde_compress)?
.with_async_function("decompress", serde_decompress)?
.with_value(
"crypto",
TableBuilder::new(lua)?
.with_function("sha1", |_, content: Option<String>| {
Ok(Crypto::sha1(content))
})?
.with_function("sha256", |_, content: Option<String>| {
Ok(Crypto::sha256(content))
})?
.with_function("sha512", |_, content: Option<String>| {
Ok(Crypto::sha512(content))
})?
.with_function("md5", |_, content: Option<String>| Ok(Crypto::md5(content)))?
.with_function("blake2s256", |_, content: Option<String>| {
Ok(Crypto::blake2s256(content))
})?
.with_function("blake2b512", |_, content: Option<String>| {
Ok(Crypto::blake2b512(content))
})?
.with_function("sha3", |_, (variant, content): (String, Option<String>)| {
match variant.to_string().as_str() {
"256" => Ok(Crypto::sha3_256(content)),
"512" => Ok(Crypto::sha3_512(content)),

&_ => Err(LuaError::runtime(format!(
"Expected sha3 variant to be 256-bit or 512-bit, got {}",
variant
))),
}
})?
.build()?,
)?
.build_readonly()
}

Expand Down