suricata
util-lua-hashlib.c
Go to the documentation of this file.
1 /* Copyright (C) 2025 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 /**
19  * \file
20  *
21  * Hashing library for Lua.
22  *
23  * Usage:
24  *
25  * local hashing = require("suricata.hashing")
26  *
27  * -- One shot hash
28  * hash = hashing.sha256_digest("www.suricata.io")
29  *
30  * -- One shot hash to hex
31  * hash = hashing.sha256_hexdigest("www.suricata.io")
32  *
33  * -- Incremental hashing
34  * hasher = hashing.sha256()
35  * hasher:update("www.")
36  * hasher:update("suricata.io")
37  * hash = hasher:finalize()
38  *
39  * Support hashes: sha256, sha1, md5
40  */
41 
42 #include "util-lua-hashlib.h"
43 
44 #include "lauxlib.h"
45 #include "rust-bindings.h"
46 
47 #define SHA256_MT "suricata:hashlib:sha256"
48 #define SHA1_MT "suricata:hashlib:sha1"
49 #define MD5_MT "suricata:hashlib:md5"
50 
51 /**
52  * \brief Create a new SHA-256 hash instance.
53  */
54 static int LuaHashLibSha256New(lua_State *L)
55 {
56  struct SCSha256 **hasher = lua_newuserdata(L, sizeof(struct SCSha256 *));
57  if (hasher == NULL) {
58  return luaL_error(L, "failed to allocate userdata for sha256");
59  }
60  *hasher = SCSha256New();
61  luaL_getmetatable(L, SHA256_MT);
62  lua_setmetatable(L, -2);
63  return 1;
64 }
65 
66 /**
67  * \brief Add more data to an existing SHA-256 hash instance.
68  */
69 static int LuaHashLibSha256Update(lua_State *L)
70 {
71  struct SCSha256 **hasher = luaL_checkudata(L, 1, SHA256_MT);
72  if (hasher == NULL || *hasher == NULL) {
73  return luaL_error(L, "invalid sha256 hash context");
74  }
75  if (*hasher == NULL) {
76  return luaL_error(L, "sha256 hasher already finalized");
77  }
78  size_t data_len;
79  const char *data = luaL_checklstring(L, 2, &data_len);
80  SCSha256Update(*hasher, (const uint8_t *)data, (uint32_t)data_len);
81  return 0;
82 }
83 
84 static int LuaHashLibSha256Finalize(lua_State *L)
85 {
86  struct SCSha256 **hasher = luaL_checkudata(L, 1, SHA256_MT);
87  if (hasher == NULL || *hasher == NULL) {
88  return luaL_error(L, "invalid sha256 hash context");
89  }
90  if (*hasher == NULL) {
91  return luaL_error(L, "sha256 hasher already finalized");
92  }
93 
94  uint8_t hash[SC_SHA256_LEN];
95  struct SCSha256 *ctx = *hasher;
96  *hasher = NULL;
97  SCSha256Finalize(ctx, hash, sizeof(hash));
98  lua_pushlstring(L, (const char *)hash, sizeof(hash));
99 
100  return 1;
101 }
102 
103 static int LuaHashLibSha256FinalizeToHex(lua_State *L)
104 {
105  struct SCSha256 **hasher = luaL_checkudata(L, 1, SHA256_MT);
106  if (hasher == NULL || *hasher == NULL) {
107  return luaL_error(L, "invalid sha256 hash context");
108  }
109  if (*hasher == NULL) {
110  return luaL_error(L, "sha256 hasher already finalized");
111  }
112 
113  char hash[SC_SHA256_HEX_LEN + 1];
114  struct SCSha256 *ctx = *hasher;
115  *hasher = NULL;
116  if (!SCSha256FinalizeToHex(ctx, hash, sizeof(hash))) {
117  return luaL_error(L, "sha256 hashing failed");
118  }
119 
120  lua_pushstring(L, (const char *)hash);
121 
122  return 1;
123 }
124 
125 static int LuaHashLibSha256Digest(lua_State *L)
126 {
127  size_t buf_len;
128  const char *input = luaL_checklstring(L, 1, &buf_len);
129 
130  uint8_t output[SC_SHA256_LEN];
131  if (!SCSha256HashBuffer((uint8_t *)input, (uint32_t)buf_len, output, SC_SHA256_LEN)) {
132  return luaL_error(L, "sha256 hashing failed");
133  }
134 
135  lua_pushlstring(L, (const char *)output, SC_SHA256_LEN);
136 
137  return 1;
138 }
139 
140 static int LuaHashLibSha256HexDigest(lua_State *L)
141 {
142  size_t buf_len;
143  const char *input = luaL_checklstring(L, 1, &buf_len);
144 
145  char output[SC_SHA256_HEX_LEN + 1];
146  if (!SCSha256HashBufferToHex((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) {
147  return luaL_error(L, "sha256 hashing failed");
148  }
149 
150  lua_pushstring(L, (const char *)output);
151  return 1;
152 }
153 
154 static int LuaHashLibSha256Gc(lua_State *L)
155 {
156  struct SCSha256 **hasher = luaL_checkudata(L, 1, SHA256_MT);
157  if (hasher && *hasher) {
158  struct SCSha256 *ctx = *hasher;
159  *hasher = NULL;
160  SCSha256Free(ctx);
161  }
162  return 0;
163 }
164 
165 static int LuaHashLibSha1New(lua_State *L)
166 {
167  struct SCSha1 **hasher = lua_newuserdata(L, sizeof(struct SCSha1 *));
168  if (hasher == NULL) {
169  return luaL_error(L, "failed to allocate userdata for sha1");
170  }
171  *hasher = SCSha1New();
172  luaL_getmetatable(L, SHA1_MT);
173  lua_setmetatable(L, -2);
174  return 1;
175 }
176 
177 static int LuaHashLibSha1Update(lua_State *L)
178 {
179  struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT);
180  if (hasher == NULL || *hasher == NULL) {
181  return luaL_error(L, "invalid sha1 hash context");
182  }
183  if (*hasher == NULL) {
184  return luaL_error(L, "sha1 hasher already finalized");
185  }
186 
187  size_t data_len;
188  const char *data = luaL_checklstring(L, 2, &data_len);
189  SCSha1Update(*hasher, (const uint8_t *)data, (uint32_t)data_len);
190  return 0;
191 }
192 
193 static int LuaHashLibSha1Finalize(lua_State *L)
194 {
195  struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT);
196  if (hasher == NULL || *hasher == NULL) {
197  return luaL_error(L, "invalid sha1 hash context");
198  }
199  if (*hasher == NULL) {
200  return luaL_error(L, "sha1 hasher already finalized");
201  }
202 
203  uint8_t hash[SC_SHA1_LEN];
204  struct SCSha1 *ctx = *hasher;
205  *hasher = NULL;
206  SCSha1Finalize(ctx, hash, sizeof(hash));
207  lua_pushlstring(L, (const char *)hash, sizeof(hash));
208 
209  return 1;
210 }
211 
212 static int LuaHashLibSha1FinalizeToHex(lua_State *L)
213 {
214  struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT);
215  if (hasher == NULL || *hasher == NULL) {
216  return luaL_error(L, "invalid sha1 hash context");
217  }
218  if (*hasher == NULL) {
219  return luaL_error(L, "sha1 hasher already finalized");
220  }
221 
222  char hash[SC_SHA1_HEX_LEN + 1];
223  struct SCSha1 *ctx = *hasher;
224  *hasher = NULL;
225  if (!SCSha1FinalizeToHex(ctx, hash, sizeof(hash))) {
226  return luaL_error(L, "sha1 hashing failed");
227  }
228 
229  lua_pushstring(L, (const char *)hash);
230 
231  return 1;
232 }
233 
234 static int LuaHashLibSha1Digest(lua_State *L)
235 {
236  size_t buf_len;
237  const char *input = luaL_checklstring(L, 1, &buf_len);
238 
239  uint8_t output[SC_SHA1_LEN];
240  if (!SCSha1HashBuffer((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) {
241  return luaL_error(L, "sha1 hashing failed");
242  }
243 
244  lua_pushlstring(L, (const char *)output, sizeof(output));
245  return 1;
246 }
247 
248 static int LuaHashLibSha1HexDigest(lua_State *L)
249 {
250  size_t buf_len;
251  const char *input = luaL_checklstring(L, 1, &buf_len);
252 
253  char output[SC_SHA1_HEX_LEN + 1];
254  if (!SCSha1HashBufferToHex((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) {
255  return luaL_error(L, "sha1 hashing failed");
256  }
257 
258  lua_pushstring(L, (const char *)output);
259  return 1;
260 }
261 
262 static int LuaHashLibSha1Gc(lua_State *L)
263 {
264  struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT);
265  if (hasher && *hasher) {
266  struct SCSha1 *ctx = *hasher;
267  *hasher = NULL;
268  SCSha1Free(ctx);
269  }
270  return 0;
271 }
272 
273 static int LuaHashLibMd5New(lua_State *L)
274 {
275  struct SCMd5 **hasher = lua_newuserdata(L, sizeof(struct SCMd5 *));
276  if (hasher == NULL) {
277  return luaL_error(L, "failed to allocate userdata for sha1");
278  }
279  *hasher = SCMd5New();
280  luaL_getmetatable(L, MD5_MT);
281  lua_setmetatable(L, -2);
282  return 1;
283 }
284 
285 static int LuaHashLibMd5Update(lua_State *L)
286 {
287  struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT);
288  if (hasher == NULL || *hasher == NULL) {
289  return luaL_error(L, "invalid md5 hash context");
290  }
291  if (*hasher == NULL) {
292  return luaL_error(L, "md5 hasher already finalized");
293  }
294 
295  size_t data_len;
296  const char *data = luaL_checklstring(L, 2, &data_len);
297  SCMd5Update(*hasher, (const uint8_t *)data, (uint32_t)data_len);
298  return 0;
299 }
300 
301 static int LuaHashLibMd5Finalize(lua_State *L)
302 {
303  struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT);
304  if (hasher == NULL || *hasher == NULL) {
305  return luaL_error(L, "invalid md5 hash context");
306  }
307  if (*hasher == NULL) {
308  return luaL_error(L, "md5 hasher already finalized");
309  }
310 
311  uint8_t hash[SC_MD5_LEN];
312  struct SCMd5 *ctx = *hasher;
313  *hasher = NULL;
314  SCMd5Finalize(ctx, hash, sizeof(hash));
315  lua_pushlstring(L, (const char *)hash, sizeof(hash));
316 
317  return 1;
318 }
319 
320 static int LuaHashLibMd5FinalizeToHex(lua_State *L)
321 {
322  struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT);
323  if (hasher == NULL || *hasher == NULL) {
324  return luaL_error(L, "invalid md5 hash context");
325  }
326  if (*hasher == NULL) {
327  return luaL_error(L, "md5 hasher already finalized");
328  }
329 
330  char hash[SC_MD5_HEX_LEN + 1];
331  struct SCMd5 *ctx = *hasher;
332  *hasher = NULL;
333  if (!SCMd5FinalizeToHex(ctx, hash, sizeof(hash))) {
334  return luaL_error(L, "md5 hashing failed");
335  }
336 
337  lua_pushstring(L, (const char *)hash);
338 
339  return 1;
340 }
341 
342 static int LuaHashLibMd5Digest(lua_State *L)
343 {
344  size_t buf_len;
345  const char *input = luaL_checklstring(L, 1, &buf_len);
346 
347  uint8_t output[SC_MD5_LEN];
348  if (!SCMd5HashBuffer((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) {
349  return luaL_error(L, "md5 hashing failed");
350  }
351 
352  lua_pushlstring(L, (const char *)output, sizeof(output));
353  return 1;
354 }
355 
356 static int LuaHashLibMd5HexDigest(lua_State *L)
357 {
358  size_t buf_len;
359  const char *input = luaL_checklstring(L, 1, &buf_len);
360 
361  char output[SC_MD5_HEX_LEN + 1];
362  if (!SCMd5HashBufferToHex((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) {
363  return luaL_error(L, "md5 hashing failed");
364  }
365 
366  lua_pushstring(L, (const char *)output);
367  return 1;
368 }
369 
370 static int LuaHashLibMd5Gc(lua_State *L)
371 {
372  struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT);
373  if (hasher && *hasher) {
374  struct SCMd5 *ctx = *hasher;
375  *hasher = NULL;
376  SCMd5Free(ctx);
377  }
378  return 0;
379 }
380 
381 static const struct luaL_Reg hashlib[] = {
382  // clang-format off
383  { "sha256_digest", LuaHashLibSha256Digest },
384  { "sha256_hexdigest", LuaHashLibSha256HexDigest },
385  { "sha256", LuaHashLibSha256New },
386  { "sha1_digest", LuaHashLibSha1Digest },
387  { "sha1_hexdigest", LuaHashLibSha1HexDigest },
388  { "sha1", LuaHashLibSha1New },
389  { "md5_digest", LuaHashLibMd5Digest },
390  { "md5_hexdigest", LuaHashLibMd5HexDigest },
391  { "md5", LuaHashLibMd5New },
392  { NULL, NULL },
393  // clang-format on
394 };
395 
396 static const struct luaL_Reg sha256_methods[] = {
397  // clang-format off
398  { "update", LuaHashLibSha256Update },
399  { "finalize", LuaHashLibSha256Finalize },
400  { "finalize_to_hex", LuaHashLibSha256FinalizeToHex },
401  { NULL, NULL },
402  // clang-format on
403 };
404 
405 static const struct luaL_Reg sha1_methods[] = {
406  // clang-format off
407  { "update", LuaHashLibSha1Update },
408  { "finalize", LuaHashLibSha1Finalize },
409  { "finalize_to_hex", LuaHashLibSha1FinalizeToHex },
410  { NULL, NULL },
411  // clang-format on
412 };
413 
414 static const struct luaL_Reg md5_methods[] = {
415  // clang-format off
416  { "update", LuaHashLibMd5Update },
417  { "finalize", LuaHashLibMd5Finalize },
418  { "finalize_to_hex", LuaHashLibMd5FinalizeToHex },
419  { NULL, NULL },
420  // clang-format on
421 };
422 
424 {
425  luaL_newmetatable(L, SHA256_MT);
426  lua_pushcfunction(L, LuaHashLibSha256Gc);
427  lua_setfield(L, -2, "__gc");
428  luaL_newlib(L, sha256_methods);
429  lua_setfield(L, -2, "__index");
430 
431  luaL_newmetatable(L, SHA1_MT);
432  lua_pushcfunction(L, LuaHashLibSha1Gc);
433  lua_setfield(L, -2, "__gc");
434  luaL_newlib(L, sha1_methods);
435  lua_setfield(L, -2, "__index");
436 
437  luaL_newmetatable(L, MD5_MT);
438  lua_pushcfunction(L, LuaHashLibMd5Gc);
439  lua_setfield(L, -2, "__gc");
440  luaL_newlib(L, md5_methods);
441  lua_setfield(L, -2, "__index");
442 
443  luaL_newlib(L, hashlib);
444 
445  return 1;
446 }
SCSha1
struct SCSha1 SCSha1
Definition: util-file.h:106
SC_SHA256_LEN
#define SC_SHA256_LEN
Definition: util-file.h:104
SC_SHA1_LEN
#define SC_SHA1_LEN
Definition: util-file.h:107
ctx
struct Thresholds ctx
SCLuaLoadHashlib
int SCLuaLoadHashlib(lua_State *L)
Definition: util-lua-hashlib.c:423
util-lua-hashlib.h
SCSha256
struct SCSha256 SCSha256
Definition: util-file.h:103
lua_State
struct lua_State lua_State
Definition: suricata-common.h:530
MD5_MT
#define MD5_MT
Definition: util-lua-hashlib.c:49
SHA256_MT
#define SHA256_MT
Definition: util-lua-hashlib.c:47
SHA1_MT
#define SHA1_MT
Definition: util-lua-hashlib.c:48
SC_MD5_LEN
#define SC_MD5_LEN
Definition: util-file.h:110
SCMd5
struct SCMd5 SCMd5
Definition: util-file.h:109