From: Jason Ish Date: Tue, 22 Dec 2020 18:35:45 +0000 (-0600) Subject: rust: add ffi module for sha256, sha1 and md5 X-Git-Tag: suricata-7.0.0-beta1~1907 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=46ceb13c08f8ff731ba15b53a47b3bad77c1defd;p=thirdparty%2Fsuricata.git rust: add ffi module for sha256, sha1 and md5 Add a Rust module that exposes Rust implementations of sha256, sha1 and md5 from the RustCrypto project. This is an experiment in replacing the libnss hash functions with pure Rust versions that will allow us to remove nss as a compile time option. Initial tests are good, even with a 10% or so performance improvement when being called from C. Also trying a module naming scheme where modules under the ffi modules are purely for exports to C, as it doesn't make any sense to use this new hashing module directly from Rust. --- diff --git a/rust/Cargo.toml.in b/rust/Cargo.toml.in index b098c90cc3..e9b178ad38 100644 --- a/rust/Cargo.toml.in +++ b/rust/Cargo.toml.in @@ -40,6 +40,10 @@ snmp-parser = "0.6" tls-parser = "0.9" x509-parser = "0.6.5" libc = "0.2.67" +sha2 = "0.9.2" +digest = "0.9.0" +sha-1 = "0.9.2" +md5c = { package = "md-5", version = "0.9.1" } [dev-dependencies] test-case = "1.0" diff --git a/rust/src/ffi/hashing.rs b/rust/src/ffi/hashing.rs new file mode 100644 index 0000000000..c5c5b4166a --- /dev/null +++ b/rust/src/ffi/hashing.rs @@ -0,0 +1,147 @@ +/* Copyright (C) 2020 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. + */ + +use std::os::raw::c_char; +use digest::Digest; +use md5c::Md5; +use sha1::Sha1; +use sha2::Sha256; + +pub const SC_SHA256_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 +// with .0. +pub struct SCSha256(Sha256); + +#[no_mangle] +pub extern "C" fn SCSha256New() -> *mut SCSha256 { + let hasher = Box::new(SCSha256(Sha256::new())); + Box::into_raw(hasher) +} + +#[no_mangle] +pub unsafe extern "C" fn SCSha256Update(hasher: &mut SCSha256, bytes: *const u8, len: u32) { + update(&mut hasher.0, bytes, len); +} + +#[no_mangle] +pub unsafe extern "C" fn SCSha256Finalize(hasher: &mut SCSha256, out: *mut u8, len: u32) { + let hasher: Box = Box::from_raw(hasher); + finalize(hasher.0, out, len); +} + +/// C function to finalize the Sha256 hasher to a hex string. +/// +/// Notes: +/// - There is probably room for optimization here, by iterating the result and writing +/// the output directly to the output buffer. +/// +/// 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) { + let out = &mut *(out as *mut u8); + let hasher: Box = Box::from_raw(hasher); + let result = hasher.0.finalize(); + let hex = format!("{:x}", &result); + let output = std::slice::from_raw_parts_mut(out, len as usize); + + // This will panic if the sizes differ. + output[0..len as usize - 1].copy_from_slice(&hex.as_bytes()); + + // Terminate the string. + output[output.len() - 1] = 0; +} + +/// Free an unfinalized Sha256 context. +#[no_mangle] +pub unsafe extern "C" fn SCSha256Free(hasher: &mut SCSha256) { + // Drop. + let _: Box = Box::from_raw(hasher); +} + +// Start of SHA1 C bindings. + +pub struct SCSha1(Sha1); + +#[no_mangle] +pub extern "C" fn SCSha1New() -> *mut SCSha1 { + let hasher = Box::new(SCSha1(Sha1::new())); + Box::into_raw(hasher) +} + +#[no_mangle] +pub unsafe extern "C" fn SCSha1Update(hasher: &mut SCSha1, bytes: *const u8, len: u32) { + update(&mut hasher.0, bytes, len); +} + +#[no_mangle] +pub unsafe extern "C" fn SCSha1Finalize(hasher: &mut SCSha1, out: *mut u8, len: u32) { + let hasher: Box = Box::from_raw(hasher); + finalize(hasher.0, out, len); +} + +/// Free an unfinalized Sha1 context. +#[no_mangle] +pub unsafe extern "C" fn SCSha1Free(hasher: &mut SCSha1) { + // Drop. + let _: Box = Box::from_raw(hasher); +} + +// Start of MD5 C bindins. + +pub struct SCMd5(Md5); + +#[no_mangle] +pub extern "C" fn SCMd5New() -> *mut SCMd5 { + let hasher = Box::new(SCMd5(Md5::new())); + Box::into_raw(hasher) +} + +#[no_mangle] +pub unsafe extern "C" fn SCMd5Update(hasher: &mut SCMd5, bytes: *const u8, len: u32) { + update(&mut hasher.0, bytes, len); +} + +#[no_mangle] +pub unsafe extern "C" fn SCMd5Finalize(hasher: &mut SCMd5, out: *mut u8, len: u32) { + let hasher: Box = Box::from_raw(hasher); + finalize(hasher.0, out, len); +} + +/// Free an unfinalized Sha1 context. +#[no_mangle] +pub unsafe extern "C" fn SCMd5Free(hasher: &mut SCMd5) { + // Drop. + let _: Box = Box::from_raw(hasher); +} + +// Functions that are generic over Digest. For the most part the C bindings are +// just wrappers around these. + +unsafe fn update(digest: &mut D, bytes: *const u8, len: u32) { + let data = std::slice::from_raw_parts(bytes, len as usize); + digest.update(data); +} + +unsafe fn finalize(digest: D, out: *mut u8, len: u32) { + let result = digest.finalize(); + let output = std::slice::from_raw_parts_mut(out, len as usize); + // This will panic if the sizes differ. + output.copy_from_slice(&result); +} diff --git a/rust/src/ffi/mod.rs b/rust/src/ffi/mod.rs new file mode 100644 index 0000000000..e7b3492134 --- /dev/null +++ b/rust/src/ffi/mod.rs @@ -0,0 +1,18 @@ +/* Copyright (C) 2020 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. + */ + +pub mod hashing; diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 7155d81f80..4d054abad1 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -84,3 +84,4 @@ pub mod ssh; pub mod http2; pub mod plugin; pub mod util; +pub mod ffi;