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

lua: expose hash function to lua scripts - v1 #12437

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions doc/userguide/lua/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ Lua support

lua-usage
lua-functions
libs/index
97 changes: 97 additions & 0 deletions doc/userguide/lua/libs/hashlib.rst
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions doc/userguide/lua/libs/index.rst
Original file line number Diff line number Diff line change
@@ -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
86 changes: 71 additions & 15 deletions rust/src/ffi/hashing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<SCSha256> = 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.
Expand All @@ -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);
Expand All @@ -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<SCSha1> = 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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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<SCMd5> = 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.
Expand All @@ -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
Expand Down Expand Up @@ -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"
);
}
}

Expand All @@ -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");
}
}

}
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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 \
Expand Down
Loading
Loading