From 575ef71e9e0cc0a703f4f17d09a111664ec6c24e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 21 Jan 2025 15:21:46 -0600 Subject: [PATCH 1/3] rust/hashing: add more hex variants Make all the hasher's have the same variants: - add hex digest for sha256 - add finalize to hex for sha1 - add hex digest for sha1 --- rust/src/ffi/hashing.rs | 86 ++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/rust/src/ffi/hashing.rs b/rust/src/ffi/hashing.rs index 0a62772c1cf1..b1d1c1d4b458 100644 --- a/rust/src/ffi/hashing.rs +++ b/rust/src/ffi/hashing.rs @@ -21,12 +21,14 @@ use sha1::Sha1; use sha2::Sha256; use std::os::raw::c_char; -pub const SC_SHA1_LEN: usize = 20; pub const SC_SHA256_LEN: usize = 32; +pub const SC_SHA1_LEN: usize = 20; +pub const SC_MD5_LEN: usize = 16; // Length of hex digests without trailing NUL. -pub const SC_MD5_HEX_LEN: usize = 32; pub const SC_SHA256_HEX_LEN: usize = 64; +pub const SC_SHA1_HEX_LEN: usize = 40; +pub const SC_MD5_HEX_LEN: usize = 32; // Wrap the Rust Sha256 in a new type named SCSha256 to give this type // the "SC" prefix. The one drawback is we must access the actual context @@ -59,11 +61,13 @@ pub unsafe extern "C" fn SCSha256Finalize(hasher: &mut SCSha256, out: *mut u8, l /// But even given the notes, this appears to be faster than the equivalent that we /// did in C using NSS. #[no_mangle] -pub unsafe extern "C" fn SCSha256FinalizeToHex(hasher: &mut SCSha256, out: *mut c_char, len: u32) { +pub unsafe extern "C" fn SCSha256FinalizeToHex( + hasher: &mut SCSha256, out: *mut c_char, len: u32, +) -> bool { let hasher: Box = Box::from_raw(hasher); let result = hasher.0.finalize(); let hex = format!("{:x}", &result); - crate::ffi::strings::copy_to_c_char(hex, out, len as usize); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) } /// Free an unfinalized Sha256 context. @@ -87,6 +91,16 @@ pub unsafe extern "C" fn SCSha256HashBuffer( return true; } +#[no_mangle] +pub unsafe extern "C" fn SCSha256HashBufferToHex( + buf: *const u8, buf_len: u32, out: *mut c_char, len: u32, +) -> bool { + let data = std::slice::from_raw_parts(buf, buf_len as usize); + let hash = Sha256::new().chain(data).finalize(); + let hex = format!("{:x}", &hash); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) +} + // Start of SHA1 C bindings. pub struct SCSha1(Sha1); @@ -108,6 +122,16 @@ pub unsafe extern "C" fn SCSha1Finalize(hasher: &mut SCSha1, out: *mut u8, len: finalize(hasher.0, out, len); } +#[no_mangle] +pub unsafe extern "C" fn SCSha1FinalizeToHex( + hasher: &mut SCSha1, out: *mut c_char, len: u32, +) -> bool { + let hasher: Box = Box::from_raw(hasher); + let result = hasher.0.finalize(); + let hex = format!("{:x}", &result); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) +} + /// Free an unfinalized Sha1 context. #[no_mangle] pub unsafe extern "C" fn SCSha1Free(hasher: &mut SCSha1) { @@ -129,6 +153,16 @@ pub unsafe extern "C" fn SCSha1HashBuffer( return true; } +#[no_mangle] +pub unsafe extern "C" fn SCSha1HashBufferToHex( + buf: *const u8, buf_len: u32, out: *mut c_char, len: u32, +) -> bool { + let data = std::slice::from_raw_parts(buf, buf_len as usize); + let hash = Sha1::new().chain(data).finalize(); + let hex = format!("{:x}", &hash); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) +} + // Start of MD5 C bindings. pub struct SCMd5(Md5); @@ -157,11 +191,13 @@ pub unsafe extern "C" fn SCMd5Finalize(hasher: &mut SCMd5, out: *mut u8, len: u3 /// /// Consumes the hash context and cannot be re-used. #[no_mangle] -pub unsafe extern "C" fn SCMd5FinalizeToHex(hasher: &mut SCMd5, out: *mut c_char, len: u32) { +pub unsafe extern "C" fn SCMd5FinalizeToHex( + hasher: &mut SCMd5, out: *mut c_char, len: u32, +) -> bool { let hasher: Box = Box::from_raw(hasher); let result = hasher.0.finalize(); let hex = format!("{:x}", &result); - crate::ffi::strings::copy_to_c_char(hex, out, len as usize); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) } /// Free an unfinalized Sha1 context. @@ -172,22 +208,28 @@ pub unsafe extern "C" fn SCMd5Free(hasher: &mut SCMd5) { } #[no_mangle] -pub unsafe extern "C" fn SCMd5HashBuffer(buf: *const u8, buf_len: u32, out: *mut u8, len: u32) { +pub unsafe extern "C" fn SCMd5HashBuffer( + buf: *const u8, buf_len: u32, out: *mut u8, len: u32, +) -> bool { + if len as usize != SC_MD5_LEN { + return false; + } let data = std::slice::from_raw_parts(buf, buf_len as usize); let output = std::slice::from_raw_parts_mut(out, len as usize); let hash = Md5::new().chain(data).finalize(); output.copy_from_slice(&hash); + true } /// C binding for a function to MD5 hash a single buffer to a hex string. #[no_mangle] pub unsafe extern "C" fn SCMd5HashBufferToHex( buf: *const u8, buf_len: u32, out: *mut c_char, len: u32, -) { +) -> bool { let data = std::slice::from_raw_parts(buf, buf_len as usize); let hash = Md5::new().chain(data).finalize(); let hex = format!("{:x}", &hash); - crate::ffi::strings::copy_to_c_char(hex, out, len as usize); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) } // Functions that are generic over Digest. For the most part the C bindings are @@ -230,9 +272,18 @@ mod test { SCSha256Update(hasher, bytes.as_ptr(), bytes.len() as u32); SCSha256Update(hasher, bytes.as_ptr(), bytes.len() as u32); let hex = [0_u8; SC_SHA256_HEX_LEN + 1]; - SCSha256FinalizeToHex(hasher, hex.as_ptr() as *mut c_char, (SC_SHA256_HEX_LEN + 1) as u32); - let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char).to_str().unwrap(); - assert_eq!(string, "22a48051594c1949deed7040850c1f0f8764537f5191be56732d16a54c1d8153"); + SCSha256FinalizeToHex( + hasher, + hex.as_ptr() as *mut c_char, + (SC_SHA256_HEX_LEN + 1) as u32, + ); + let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char) + .to_str() + .unwrap(); + assert_eq!( + string, + "22a48051594c1949deed7040850c1f0f8764537f5191be56732d16a54c1d8153" + ); } } @@ -250,10 +301,15 @@ mod test { SCMd5Update(hasher, bytes.as_ptr(), bytes.len() as u32); SCMd5Update(hasher, bytes.as_ptr(), bytes.len() as u32); let hex = [0_u8; SC_MD5_HEX_LEN + 1]; - SCMd5FinalizeToHex(hasher, hex.as_ptr() as *mut c_char, (SC_MD5_HEX_LEN + 1) as u32); - let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char).to_str().unwrap(); + SCMd5FinalizeToHex( + hasher, + hex.as_ptr() as *mut c_char, + (SC_MD5_HEX_LEN + 1) as u32, + ); + let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char) + .to_str() + .unwrap(); assert_eq!(string, "5216ddcc58e8dade5256075e77f642da"); } } - } From 82965b6a3f05fc6f2b85fd1714a9dd4a75a0d85e Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 21 Jan 2025 15:23:15 -0600 Subject: [PATCH 2/3] lua: expose hashing functions to lua scripts Expose md5, sha1, and sha256 to Lua scripts with `require("suricata.hashing")`. Ticket: 7073 --- src/Makefile.am | 2 + src/util-lua-hashlib.c | 393 +++++++++++++++++++++++++++++++++++++++++ src/util-lua-hashlib.h | 26 +++ src/util-lua-sandbox.c | 5 +- 4 files changed, 425 insertions(+), 1 deletion(-) create mode 100644 src/util-lua-hashlib.c create mode 100644 src/util-lua-hashlib.h diff --git a/src/Makefile.am b/src/Makefile.am index 615816953542..9065c8d70910 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -512,6 +512,7 @@ noinst_HEADERS = \ util-lua-dnp3-objects.h \ util-lua-dns.h \ util-lua.h \ + util-lua-hashlib.h \ util-lua-hassh.h \ util-lua-http.h \ util-lua-ja3.h \ @@ -1060,6 +1061,7 @@ libsuricata_c_a_SOURCES = \ util-lua-dnp3.c \ util-lua-dnp3-objects.c \ util-lua-dns.c \ + util-lua-hashlib.c \ util-lua-hassh.c \ util-lua-http.c \ util-lua-ja3.c \ diff --git a/src/util-lua-hashlib.c b/src/util-lua-hashlib.c new file mode 100644 index 000000000000..772ff9c54073 --- /dev/null +++ b/src/util-lua-hashlib.c @@ -0,0 +1,393 @@ +/* Copyright (C) 2025 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * Hashing library for Lua. + * + * Usage: + * + * local hashing = require("suricata.hashing") + * + * -- One shot hash + * hash = hashing.sha256_digest("www.suricata.io") + * + * -- Incremental hashing + * hasher = hashing.sha256() + * hasher:update("www.") + * hasher:update("suricata.io") + * hash = hasher:finalize() + * + * Support hashes: + * + * - sha256: sha256(), sha256_digest() + * - sha1: sha1(), sha1_digest() + * - md5: md5(), md5_digest() + */ + +#include "util-lua-hashlib.h" + +#include "lauxlib.h" +#include "rust-bindings.h" + +#define SHA256_MT "suricata:hashlib:sha256" +#define SHA1_MT "suricata:hashlib:sha1" +#define MD5_MT "suricata:hashlib:md5" + +/** + * \brief Create a new SHA-256 hash instance. + */ +static int LuaHashLibSha256New(lua_State *L) +{ + struct SCSha256 **hasher = lua_newuserdata(L, sizeof(struct SCSha256 *)); + *hasher = SCSha256New(); + luaL_getmetatable(L, SHA256_MT); + lua_setmetatable(L, -2); + return 1; +} + +/** + * \brief Add more data to an existing SHA-256 hash instance. + */ +static int LuaHashLibSha256Update(lua_State *L) +{ + struct SCSha256 **hasher = luaL_checkudata(L, 1, SHA256_MT); + size_t data_len; + const char *data = luaL_checklstring(L, 2, &data_len); + SCSha256Update(*hasher, (const uint8_t *)data, data_len); + return 0; +} + +static int LuaHashLibSha256Finalize(lua_State *L) +{ + struct SCSha256 **hasher = luaL_checkudata(L, 1, SHA256_MT); + uint8_t hash[SC_SHA256_LEN]; + + SCSha256Finalize(*hasher, hash, sizeof(hash)); + lua_pushlstring(L, (const char *)hash, sizeof(hash)); + + // Finalize consumes the hasher, so set to NULL so its not free'd + // during garbage collection. + *hasher = NULL; + + return 1; +} + +static int LuaHashLibSha256FinalizeToHex(lua_State *L) +{ + struct SCSha256 **hasher = luaL_checkudata(L, 1, SHA256_MT); + char hash[SC_SHA256_HEX_LEN + 1]; + + if (!SCSha256FinalizeToHex(*hasher, hash, sizeof(hash))) { + *hasher = NULL; + return luaL_error(L, "sha256 hashing failed"); + } + + lua_pushstring(L, (const char *)hash); + + // Finalize consumes the hasher, so set to NULL so its not free'd + // during garbage collection. + *hasher = NULL; + + return 1; +} + +static int LuaHashLibSha256Digest(lua_State *L) +{ + size_t buf_len; + const char *input = luaL_checklstring(L, 1, &buf_len); + + size_t output_len = SC_SHA256_LEN; + uint8_t output[output_len]; + if (!SCSha256HashBuffer((uint8_t *)input, (uint32_t)buf_len, output, output_len)) { + SCLogNotice("ERROR"); + return luaL_error(L, "sha256 hashing failed"); + } + + lua_pushlstring(L, (const char *)output, output_len); + + return 1; +} + +static int LuaHashLibSha256HexDigest(lua_State *L) +{ + size_t buf_len; + const char *input = luaL_checklstring(L, 1, &buf_len); + + char output[SC_SHA256_HEX_LEN + 1]; + if (!SCSha256HashBufferToHex((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) { + return luaL_error(L, "sha256 hashing failed"); + } + + lua_pushstring(L, (const char *)output); + return 1; +} + +static int LuaHashLibSha256Gc(lua_State *L) +{ + struct SCSha256 **hasher = luaL_checkudata(L, 1, SHA256_MT); + if (*hasher) { + SCSha256Free(*hasher); + } + return 0; +} + +static int LuaHashLibSha1New(lua_State *L) +{ + struct SCSha1 **hasher = lua_newuserdata(L, sizeof(struct SCSha1 *)); + *hasher = SCSha1New(); + luaL_getmetatable(L, SHA1_MT); + lua_setmetatable(L, -2); + return 1; +} + +static int LuaHashLibSha1Update(lua_State *L) +{ + struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT); + size_t data_len; + const char *data = luaL_checklstring(L, 2, &data_len); + SCSha1Update(*hasher, (const uint8_t *)data, data_len); + return 0; +} + +static int LuaHashLibSha1Finalize(lua_State *L) +{ + struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT); + uint8_t hash[SC_SHA1_LEN]; + + SCSha1Finalize(*hasher, hash, sizeof(hash)); + lua_pushlstring(L, (const char *)hash, sizeof(hash)); + + // Finalize consumes the hasher, so set to NULL so its not free'd + // during garbage collection. + *hasher = NULL; + + return 1; +} + +static int LuaHashLibSha1FinalizeToHex(lua_State *L) +{ + struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT); + char hash[SC_SHA1_HEX_LEN + 1]; + + if (!SCSha1FinalizeToHex(*hasher, hash, sizeof(hash))) { + *hasher = NULL; + return luaL_error(L, "sha1 hashing failed"); + } + + lua_pushstring(L, (const char *)hash); + + // Finalize consumes the hasher, so set to NULL so its not free'd + // during garbage collection. + *hasher = NULL; + + return 1; +} + +static int LuaHashLibSha1Digest(lua_State *L) +{ + size_t buf_len; + const char *input = luaL_checklstring(L, 1, &buf_len); + + uint8_t output[SC_SHA1_LEN]; + if (!SCSha1HashBuffer((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) { + return luaL_error(L, "sha1 hashing failed"); + } + + lua_pushlstring(L, (const char *)output, sizeof(output)); + return 1; +} + +static int LuaHashLibSha1HexDigest(lua_State *L) +{ + size_t buf_len; + const char *input = luaL_checklstring(L, 1, &buf_len); + + char output[SC_SHA1_HEX_LEN + 1]; + if (!SCSha1HashBufferToHex((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) { + return luaL_error(L, "sha1 hashing failed"); + } + + lua_pushstring(L, (const char *)output); + return 1; +} + +static int LuaHashLibSha1Gc(lua_State *L) +{ + struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT); + if (*hasher) { + SCSha1Free(*hasher); + } + return 0; +} + +static int LuaHashLibMd5New(lua_State *L) +{ + struct SCMd5 **hasher = lua_newuserdata(L, sizeof(struct SCMd5 *)); + *hasher = SCMd5New(); + luaL_getmetatable(L, MD5_MT); + lua_setmetatable(L, -2); + return 1; +} + +static int LuaHashLibMd5Update(lua_State *L) +{ + struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT); + size_t data_len; + const char *data = luaL_checklstring(L, 2, &data_len); + SCMd5Update(*hasher, (const uint8_t *)data, data_len); + return 0; +} + +static int LuaHashLibMd5Finalize(lua_State *L) +{ + struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT); + uint8_t hash[SC_MD5_LEN]; + + SCMd5Finalize(*hasher, hash, sizeof(hash)); + lua_pushlstring(L, (const char *)hash, sizeof(hash)); + + // Finalize consumes the hasher, so set to NULL so its not free'd + // during garbage collection. + *hasher = NULL; + + return 1; +} + +static int LuaHashLibMd5FinalizeToHex(lua_State *L) +{ + struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT); + char hash[SC_MD5_HEX_LEN + 1]; + + if (!SCMd5FinalizeToHex(*hasher, hash, sizeof(hash))) { + *hasher = NULL; + return luaL_error(L, "md5 hashing failed"); + } + + lua_pushstring(L, (const char *)hash); + + // Finalize consumes the hasher, so set to NULL so its not free'd + // during garbage collection. + *hasher = NULL; + + return 1; +} + +static int LuaHashLibMd5Digest(lua_State *L) +{ + size_t buf_len; + const char *input = luaL_checklstring(L, 1, &buf_len); + + uint8_t output[SC_MD5_LEN]; + if (!SCMd5HashBuffer((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) { + return luaL_error(L, "md5 hashing failed"); + } + + lua_pushlstring(L, (const char *)output, sizeof(output)); + return 1; +} + +static int LuaHashLibMd5HexDigest(lua_State *L) +{ + size_t buf_len; + const char *input = luaL_checklstring(L, 1, &buf_len); + + char output[SC_MD5_HEX_LEN + 1]; + if (!SCMd5HashBufferToHex((uint8_t *)input, (size_t)buf_len, output, sizeof(output))) { + return luaL_error(L, "md5 hashing failed"); + } + + lua_pushstring(L, (const char *)output); + return 1; +} + +static int LuaHashLibMd5Gc(lua_State *L) +{ + struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT); + if (*hasher) { + SCMd5Free(*hasher); + } + return 0; +} + +static const struct luaL_Reg hashlib[] = { + // clang-format off + { "sha256_digest", LuaHashLibSha256Digest }, + { "sha256_hexdigest", LuaHashLibSha256HexDigest }, + { "sha256", LuaHashLibSha256New }, + { "sha1_digest", LuaHashLibSha1Digest }, + { "sha1_hexdigest", LuaHashLibSha1HexDigest }, + { "sha1", LuaHashLibSha1New }, + { "md5_digest", LuaHashLibMd5Digest }, + { "md5_hexdigest", LuaHashLibMd5HexDigest }, + { "md5", LuaHashLibMd5New }, + { NULL, NULL }, + // clang-format on +}; + +static const struct luaL_Reg sha256_meta[] = { + // clang-format off + { "update", LuaHashLibSha256Update }, + { "finalize", LuaHashLibSha256Finalize }, + { "finalize_to_hex", LuaHashLibSha256FinalizeToHex }, + { "__gc", LuaHashLibSha256Gc }, + { NULL, NULL }, + // clang-format on +}; + +static const struct luaL_Reg sha1_meta[] = { + // clang-format off + { "update", LuaHashLibSha1Update }, + { "finalize", LuaHashLibSha1Finalize }, + { "finalize_to_hex", LuaHashLibSha1FinalizeToHex }, + { "__gc", LuaHashLibSha1Gc }, + { NULL, NULL }, + // clang-format on +}; + +static const struct luaL_Reg md5_meta[] = { + // clang-format off + { "update", LuaHashLibMd5Update }, + { "finalize", LuaHashLibMd5Finalize }, + { "finalize_to_hex", LuaHashLibMd5FinalizeToHex }, + { "__gc", LuaHashLibMd5Gc }, + { NULL, NULL }, + // clang-format on +}; + +int SCLuaLoadHashlib(lua_State *L) +{ + luaL_newmetatable(L, SHA256_MT); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, sha256_meta, 0); + + luaL_newmetatable(L, SHA1_MT); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, sha1_meta, 0); + + luaL_newmetatable(L, MD5_MT); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, md5_meta, 0); + + luaL_newlib(L, hashlib); + + return 1; +} diff --git a/src/util-lua-hashlib.h b/src/util-lua-hashlib.h new file mode 100644 index 000000000000..3686840b8b95 --- /dev/null +++ b/src/util-lua-hashlib.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2025 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef SURICATA_UTIL_LUA_HASHLIB_H +#define SURICATA_UTIL_LUA_HASHLIB_H + +#include "rust.h" +#include "lua.h" + +int SCLuaLoadHashlib(lua_State *l); + +#endif /* SURICATA_UTIL_LUA_HASHLIB_H */ diff --git a/src/util-lua-sandbox.c b/src/util-lua-sandbox.c index 4c4838418f39..8f63ed0ff74b 100644 --- a/src/util-lua-sandbox.c +++ b/src/util-lua-sandbox.c @@ -29,9 +29,9 @@ #include "util-debug.h" #include "util-debug.h" -#include "util-validate.h" #include "util-lua-sandbox.h" #include "util-lua-dataset.h" +#include "util-lua-hashlib.h" #define SANDBOX_CTX "SANDBOX_CTX" @@ -267,6 +267,9 @@ static int SCLuaSbRequire(lua_State *L) if (strcmp(module_name, "suricata.dataset") == 0) { LuaLoadDatasetLib(L); return 1; + } else if (strcmp(module_name, "suricata.hashlib") == 0) { + SCLuaLoadHashlib(L); + return 1; } return luaL_error(L, "Module not found: %s", module_name); From a8b9e2d9202445f8b03e61d64311fda19afc51c7 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 21 Jan 2025 16:57:31 -0600 Subject: [PATCH 3/3] doc/userguide: document lua hashlib --- doc/userguide/lua/index.rst | 1 + doc/userguide/lua/libs/hashlib.rst | 97 ++++++++++++++++++++++++++++++ doc/userguide/lua/libs/index.rst | 11 ++++ src/util-lua-hashlib.c | 9 ++- 4 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 doc/userguide/lua/libs/hashlib.rst create mode 100644 doc/userguide/lua/libs/index.rst diff --git a/doc/userguide/lua/index.rst b/doc/userguide/lua/index.rst index d6bbf70964bd..fcb558408f10 100644 --- a/doc/userguide/lua/index.rst +++ b/doc/userguide/lua/index.rst @@ -5,3 +5,4 @@ Lua support lua-usage lua-functions + libs/index diff --git a/doc/userguide/lua/libs/hashlib.rst b/doc/userguide/lua/libs/hashlib.rst new file mode 100644 index 000000000000..9b6acb944b7b --- /dev/null +++ b/doc/userguide/lua/libs/hashlib.rst @@ -0,0 +1,97 @@ +Hashing +------- + +Hashing functions are expose to Lua scripts with ``suricata.hashing`` +library. For example:: + + local hashing = require("suricata.hashing") + +SHA-256 +~~~~~~~ + +``sha256_digest(string)`` +^^^^^^^^^^^^^^^^^^^^^^^^^ + +SHA-256 hash the provided string returning the digest as bytes. + +``sha256_hex_digest(string)`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +SHA-256 hash the provided string returning the digest as a hex string. + +``sha256()`` +^^^^^^^^^^^^ + +Returns a SHA-256 hasher that can updated multiple times, for example:: + + local hashing = require("suricata.hashing") + hasher = hashing.sha256() + hasher.update("www.suricata") + hasher.update(".io") + hash = hasher.finalize_to_hex() + +The methods on the hasher object include: + +* ``update(string)``: Add more data to the hasher +* ``finalize()``: Finalize the hash returning the hash as a byte string +* ``finalize_to_hex()``: Finalize the hash returning the has as a hex string + +SHA-1 +~~~~~ + +``sha1_digest(string)`` +^^^^^^^^^^^^^^^^^^^^^^^ + +SHA-1 hash the provided string returning the digest as bytes. + +``sha1_hex_digest(string)`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +SHA-1 hash the provided string returning the digest as a hex string. + +``sha1()`` +^^^^^^^^^^ + +Returns a SHA-1 hasher that can updated multiple times, for example:: + + local hashing = require("suricata.hashing") + hasher = hashing.sha1() + hasher.update("www.suricata") + hasher.update(".io") + hash = hasher.finalize_to_hex() + +The methods on the hasher object include: + +* ``update(string)``: Add more data to the hasher +* ``finalize()``: Finalize the hash returning the hash as a byte string +* ``finalize_to_hex()``: Finalize the hash returning the has as a hex string + +MD5 +~~~ + +``md5_digest(string)`` +^^^^^^^^^^^^^^^^^^^^^^ + +MD5 hash the provided string returning the digest as bytes. + +``md5_hex_digest(string)`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +MD5 hash the provided string returning the digest as a hex string. + +``md5()`` +^^^^^^^^^ + +Returns a MD5 hasher that can updated multiple times, for example:: + + local hashing = require("suricata.hashing") + hasher = hashing.md5() + hasher.update("www.suricata") + hasher.update(".io") + hash = hasher.finalize_to_hex() + +The methods on the hasher object include: + +* ``update(string)``: Add more data to the hasher +* ``finalize()``: Finalize the hash returning the hash as a byte string +* ``finalize_to_hex()``: Finalize the hash returning the has as a hex string diff --git a/doc/userguide/lua/libs/index.rst b/doc/userguide/lua/libs/index.rst new file mode 100644 index 000000000000..55273d7bf818 --- /dev/null +++ b/doc/userguide/lua/libs/index.rst @@ -0,0 +1,11 @@ +Lua Libraries +============= + +Suricata provides Lua extensions, or libraries to Lua scripts with the +``require`` keyword. These extensions are particular important in Lua +rules as Lua rules are executed in a restricted sandbox environment +without access to additional modules. + +.. toctree:: + + hashlib diff --git a/src/util-lua-hashlib.c b/src/util-lua-hashlib.c index 772ff9c54073..8ea6b2e42bc3 100644 --- a/src/util-lua-hashlib.c +++ b/src/util-lua-hashlib.c @@ -27,17 +27,16 @@ * -- One shot hash * hash = hashing.sha256_digest("www.suricata.io") * + * -- One shot hash to hex + * hash = hashing.sha256_hexdigest("www.suricata.io") + * * -- Incremental hashing * hasher = hashing.sha256() * hasher:update("www.") * hasher:update("suricata.io") * hash = hasher:finalize() * - * Support hashes: - * - * - sha256: sha256(), sha256_digest() - * - sha1: sha1(), sha1_digest() - * - md5: md5(), md5_digest() + * Support hashes: sha256, sha1, md5 */ #include "util-lua-hashlib.h"