/src/suricata8/rust/src/detect/transforms/hash.rs
Line | Count | Source |
1 | | /* Copyright (C) 2024 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | use crate::detect::SIGMATCH_NOOPT; |
19 | | use suricata_sys::sys::{ |
20 | | DetectEngineCtx, DetectEngineThreadCtx, InspectionBuffer, SCDetectHelperTransformRegister, |
21 | | SCDetectSignatureAddTransform, SCTransformTableElmt, Signature, SCInspectionBufferCheckAndExpand, |
22 | | SCInspectionBufferTruncate, |
23 | | }; |
24 | | |
25 | | use crate::ffi::hashing::{G_DISABLE_HASHING, SC_SHA1_LEN, SC_SHA256_LEN}; |
26 | | use digest::{Digest, Update}; |
27 | | use md5::Md5; |
28 | | use sha1::Sha1; |
29 | | use sha2::Sha256; |
30 | | |
31 | | use std::os::raw::{c_int, c_void}; |
32 | | use std::ptr; |
33 | | |
34 | | static mut G_TRANSFORM_MD5_ID: c_int = 0; |
35 | | static mut G_TRANSFORM_SHA1_ID: c_int = 0; |
36 | | static mut G_TRANSFORM_SHA256_ID: c_int = 0; |
37 | | |
38 | | const SC_MD5_LEN: usize = 16; |
39 | | |
40 | 313 | unsafe extern "C" fn md5_setup( |
41 | 313 | _de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char, |
42 | 313 | ) -> c_int { |
43 | 313 | if G_DISABLE_HASHING { |
44 | 0 | SCLogError!("MD5 hashing has been disabled, needed for to_md5 keyword"); |
45 | 0 | return -1; |
46 | 313 | } |
47 | 313 | return SCDetectSignatureAddTransform(s, G_TRANSFORM_MD5_ID, ptr::null_mut()); |
48 | 313 | } |
49 | | |
50 | 0 | fn md5_transform_do(input: &[u8], output: &mut [u8]) { |
51 | 0 | Md5::new().chain(input).finalize_into(output.into()); |
52 | 0 | } |
53 | | |
54 | 0 | unsafe extern "C" fn md5_transform( |
55 | 0 | _det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, _ctx: *mut c_void, |
56 | 0 | ) { |
57 | 0 | let input = (*buffer).inspect; |
58 | 0 | let input_len = (*buffer).inspect_len; |
59 | 0 | if input.is_null() || input_len == 0 { |
60 | 0 | return; |
61 | 0 | } |
62 | 0 | let input = build_slice!(input, input_len as usize); |
63 | | |
64 | 0 | let output = SCInspectionBufferCheckAndExpand(buffer, SC_MD5_LEN as u32); |
65 | 0 | if output.is_null() { |
66 | | // allocation failure |
67 | 0 | return; |
68 | 0 | } |
69 | 0 | let output = std::slice::from_raw_parts_mut(output, SC_MD5_LEN); |
70 | | |
71 | 0 | md5_transform_do(input, output); |
72 | | |
73 | 0 | SCInspectionBufferTruncate(buffer, SC_MD5_LEN as u32); |
74 | 0 | } |
75 | | |
76 | | #[no_mangle] |
77 | 39 | pub unsafe extern "C" fn DetectTransformMd5Register() { |
78 | 39 | let kw = SCTransformTableElmt { |
79 | 39 | name: b"to_md5\0".as_ptr() as *const libc::c_char, |
80 | 39 | desc: b"convert to md5 hash of the buffer\0".as_ptr() as *const libc::c_char, |
81 | 39 | url: b"/rules/transforms.html#to-md5\0".as_ptr() as *const libc::c_char, |
82 | 39 | Setup: Some(md5_setup), |
83 | 39 | flags: SIGMATCH_NOOPT, |
84 | 39 | Transform: Some(md5_transform), |
85 | 39 | Free: None, |
86 | 39 | TransformValidate: None, |
87 | 39 | TransformId: None, |
88 | 39 | }; |
89 | 39 | G_TRANSFORM_MD5_ID = SCDetectHelperTransformRegister(&kw); |
90 | 39 | if G_TRANSFORM_MD5_ID < 0 { |
91 | 0 | SCLogWarning!("Failed registering transform md5"); |
92 | 39 | } |
93 | 39 | } |
94 | | |
95 | 639 | unsafe extern "C" fn sha1_setup( |
96 | 639 | _de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char, |
97 | 639 | ) -> c_int { |
98 | 639 | if G_DISABLE_HASHING { |
99 | 0 | SCLogError!("SHA1 hashing has been disabled, needed for to_sha1 keyword"); |
100 | 0 | return -1; |
101 | 639 | } |
102 | 639 | return SCDetectSignatureAddTransform(s, G_TRANSFORM_SHA1_ID, ptr::null_mut()); |
103 | 639 | } |
104 | | |
105 | 0 | fn sha1_transform_do(input: &[u8], output: &mut [u8]) { |
106 | 0 | Sha1::new().chain(input).finalize_into(output.into()); |
107 | 0 | } |
108 | | |
109 | 0 | unsafe extern "C" fn sha1_transform( |
110 | 0 | _det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, _ctx: *mut c_void, |
111 | 0 | ) { |
112 | 0 | let input = (*buffer).inspect; |
113 | 0 | let input_len = (*buffer).inspect_len; |
114 | 0 | if input.is_null() || input_len == 0 { |
115 | 0 | return; |
116 | 0 | } |
117 | 0 | let input = build_slice!(input, input_len as usize); |
118 | | |
119 | 0 | let output = SCInspectionBufferCheckAndExpand(buffer, SC_SHA1_LEN as u32); |
120 | 0 | if output.is_null() { |
121 | | // allocation failure |
122 | 0 | return; |
123 | 0 | } |
124 | 0 | let output = std::slice::from_raw_parts_mut(output, SC_SHA1_LEN); |
125 | | |
126 | 0 | sha1_transform_do(input, output); |
127 | | |
128 | 0 | SCInspectionBufferTruncate(buffer, SC_SHA1_LEN as u32); |
129 | 0 | } |
130 | | |
131 | | #[no_mangle] |
132 | 39 | pub unsafe extern "C" fn DetectTransformSha1Register() { |
133 | 39 | let kw = SCTransformTableElmt { |
134 | 39 | name: b"to_sha1\0".as_ptr() as *const libc::c_char, |
135 | 39 | desc: b"convert to sha1 hash of the buffer\0".as_ptr() as *const libc::c_char, |
136 | 39 | url: b"/rules/transforms.html#to-sha1\0".as_ptr() as *const libc::c_char, |
137 | 39 | Setup: Some(sha1_setup), |
138 | 39 | flags: SIGMATCH_NOOPT, |
139 | 39 | Transform: Some(sha1_transform), |
140 | 39 | Free: None, |
141 | 39 | TransformValidate: None, |
142 | 39 | TransformId: None, |
143 | 39 | }; |
144 | 39 | G_TRANSFORM_SHA1_ID = SCDetectHelperTransformRegister(&kw); |
145 | 39 | if G_TRANSFORM_SHA1_ID < 0 { |
146 | 0 | SCLogWarning!("Failed registering transform sha1"); |
147 | 39 | } |
148 | 39 | } |
149 | | |
150 | 277 | unsafe extern "C" fn sha256_setup( |
151 | 277 | _de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char, |
152 | 277 | ) -> c_int { |
153 | 277 | if G_DISABLE_HASHING { |
154 | 0 | SCLogError!("SHA256 hashing has been disabled, needed for to_sha256 keyword"); |
155 | 0 | return -1; |
156 | 277 | } |
157 | 277 | return SCDetectSignatureAddTransform(s, G_TRANSFORM_SHA256_ID, ptr::null_mut()); |
158 | 277 | } |
159 | | |
160 | 0 | fn sha256_transform_do(input: &[u8], output: &mut [u8]) { |
161 | 0 | Sha256::new().chain(input).finalize_into(output.into()); |
162 | 0 | } |
163 | | |
164 | 0 | unsafe extern "C" fn sha256_transform( |
165 | 0 | _det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, _ctx: *mut c_void, |
166 | 0 | ) { |
167 | 0 | let input = (*buffer).inspect; |
168 | 0 | let input_len = (*buffer).inspect_len; |
169 | 0 | if input.is_null() || input_len == 0 { |
170 | 0 | return; |
171 | 0 | } |
172 | 0 | let input = build_slice!(input, input_len as usize); |
173 | | |
174 | 0 | let output = SCInspectionBufferCheckAndExpand(buffer, SC_SHA256_LEN as u32); |
175 | 0 | if output.is_null() { |
176 | | // allocation failure |
177 | 0 | return; |
178 | 0 | } |
179 | 0 | let output = std::slice::from_raw_parts_mut(output, SC_SHA256_LEN); |
180 | | |
181 | 0 | sha256_transform_do(input, output); |
182 | | |
183 | 0 | SCInspectionBufferTruncate(buffer, SC_SHA256_LEN as u32); |
184 | 0 | } |
185 | | |
186 | | #[no_mangle] |
187 | 39 | pub unsafe extern "C" fn DetectTransformSha256Register() { |
188 | 39 | let kw = SCTransformTableElmt { |
189 | 39 | name: b"to_sha256\0".as_ptr() as *const libc::c_char, |
190 | 39 | desc: b"convert to sha256 hash of the buffer\0".as_ptr() as *const libc::c_char, |
191 | 39 | url: b"/rules/transforms.html#to-sha256\0".as_ptr() as *const libc::c_char, |
192 | 39 | Setup: Some(sha256_setup), |
193 | 39 | flags: SIGMATCH_NOOPT, |
194 | 39 | Transform: Some(sha256_transform), |
195 | 39 | Free: None, |
196 | 39 | TransformValidate: None, |
197 | 39 | TransformId: None, |
198 | 39 | }; |
199 | 39 | G_TRANSFORM_SHA256_ID = SCDetectHelperTransformRegister(&kw); |
200 | 39 | if G_TRANSFORM_SHA256_ID < 0 { |
201 | 0 | SCLogWarning!("Failed registering transform sha256"); |
202 | 39 | } |
203 | 39 | } |
204 | | |
205 | | #[cfg(test)] |
206 | | mod tests { |
207 | | use super::*; |
208 | | |
209 | | #[test] |
210 | | fn test_md5_transform() { |
211 | | let buf = b" A B C D "; |
212 | | let mut out = vec![0; SC_MD5_LEN]; |
213 | | md5_transform_do(buf, &mut out); |
214 | | assert_eq!( |
215 | | out, |
216 | | b"\xe0\x59\xf8\x30\x43\x69\x58\xb6\x45\x82\x8c\xc2\x33\xc2\x47\x13" |
217 | | ); |
218 | | } |
219 | | |
220 | | #[test] |
221 | | fn test_sha1_transform() { |
222 | | let buf = b" A B C D "; |
223 | | let mut out = vec![0; SC_SHA1_LEN]; |
224 | | sha1_transform_do(buf, &mut out); |
225 | | assert_eq!( |
226 | | out, |
227 | | b"\xc8\xdc\x44\x97\xf7\xe0\x55\xf8\x6b\x88\x90\x52\x08\x2c\x0c\x7b\xdc\xc9\xc8\x89" |
228 | | ); |
229 | | } |
230 | | |
231 | | #[test] |
232 | | fn test_sha256_transform() { |
233 | | let mut buf = Vec::with_capacity(SC_SHA256_LEN); |
234 | | buf.extend_from_slice(b" A B C D "); |
235 | | let mut out = vec![0; SC_SHA256_LEN]; |
236 | | sha256_transform_do(&buf, &mut out); |
237 | | assert_eq!(out, b"\xd6\xbf\x7d\x8d\x69\x53\x02\x4d\x0d\x84\x5c\x99\x9b\xae\x93\xcc\xac\x68\xea\xab\x9a\xc9\x77\xd0\xfd\x30\x6a\xf5\x9a\x3d\xe4\x3a"); |
238 | | // test in place |
239 | | let still_buf = unsafe { std::slice::from_raw_parts(buf.as_ptr(), buf.len()) }; |
240 | | buf.resize(SC_SHA256_LEN, 0); |
241 | | sha256_transform_do(still_buf, &mut buf); |
242 | | assert_eq!(&buf, b"\xd6\xbf\x7d\x8d\x69\x53\x02\x4d\x0d\x84\x5c\x99\x9b\xae\x93\xcc\xac\x68\xea\xab\x9a\xc9\x77\xd0\xfd\x30\x6a\xf5\x9a\x3d\xe4\x3a"); |
243 | | } |
244 | | } |