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) {
73  return luaL_error(L, "null userdata");
74  }
75  size_t data_len;
76  const char *data = luaL_checklstring(L, 2, &data_len);
77  SCSha256Update(*hasher, (const uint8_t *)data, data_len);
78  return 0;
79 }
80 
81 static int LuaHashLibSha256Finalize(lua_State *L)
82 {
83  struct SCSha256 **hasher = luaL_checkudata(L, 1, SHA256_MT);
84  if (hasher == NULL) {
85  return luaL_error(L, "null userdata");
86  }
87 
88  uint8_t hash[SC_SHA256_LEN];
89  SCSha256Finalize(*hasher, hash, sizeof(hash));
90  lua_pushlstring(L, (const char *)hash, sizeof(hash));
91 
92  // Finalize consumes the hasher, so set to NULL so its not free'd
93  // during garbage collection.
94  *hasher = NULL;
95 
96  return 1;
97 }
98 
99 static int LuaHashLibSha256FinalizeToHex(lua_State *L)
100 {
101  struct SCSha256 **hasher = luaL_checkudata(L, 1, SHA256_MT);
102  if (hasher == NULL) {
103  return luaL_error(L, "null userdata");
104  }
105 
106  char hash[SC_SHA256_HEX_LEN + 1];
107  if (!SCSha256FinalizeToHex(*hasher, hash, sizeof(hash))) {
108  *hasher = NULL;
109  return luaL_error(L, "sha256 hashing failed");
110  }
111 
112  lua_pushstring(L, (const char *)hash);
113 
114  // Finalize consumes the hasher, so set to NULL so its not free'd
115  // during garbage collection.
116  *hasher = NULL;
117 
118  return 1;
119 }
120 
121 static int LuaHashLibSha256Digest(lua_State *L)
122 {
123  size_t buf_len;
124  const char *input = luaL_checklstring(L, 1, &buf_len);
125 
126  size_t output_len = SC_SHA256_LEN;
127  uint8_t output[output_len];
128  if (!SCSha256HashBuffer((uint8_t *)input, (uint32_t)buf_len, output, output_len)) {
129  return luaL_error(L, "sha256 hashing failed");
130  }
131 
132  lua_pushlstring(L, (const char *)output, output_len);
133 
134  return 1;
135 }
136 
137 static int LuaHashLibSha256HexDigest(lua_State *L)
138 {
139  size_t buf_len;
140  const char *input = luaL_checklstring(L, 1, &buf_len);
141 
142  char output[SC_SHA256_HEX_LEN + 1];
143  if (!SCSha256HashBufferToHex((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) {
144  return luaL_error(L, "sha256 hashing failed");
145  }
146 
147  lua_pushstring(L, (const char *)output);
148  return 1;
149 }
150 
151 static int LuaHashLibSha256Gc(lua_State *L)
152 {
153  struct SCSha256 **hasher = luaL_checkudata(L, 1, SHA256_MT);
154  if (hasher && *hasher) {
155  SCSha256Free(*hasher);
156  }
157  return 0;
158 }
159 
160 static int LuaHashLibSha1New(lua_State *L)
161 {
162  struct SCSha1 **hasher = lua_newuserdata(L, sizeof(struct SCSha1 *));
163  if (hasher == NULL) {
164  return luaL_error(L, "failed to allocate userdata for sha1");
165  }
166  *hasher = SCSha1New();
167  luaL_getmetatable(L, SHA1_MT);
168  lua_setmetatable(L, -2);
169  return 1;
170 }
171 
172 static int LuaHashLibSha1Update(lua_State *L)
173 {
174  struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT);
175  if (hasher == NULL) {
176  return luaL_error(L, "null userdata");
177  }
178 
179  size_t data_len;
180  const char *data = luaL_checklstring(L, 2, &data_len);
181  SCSha1Update(*hasher, (const uint8_t *)data, data_len);
182  return 0;
183 }
184 
185 static int LuaHashLibSha1Finalize(lua_State *L)
186 {
187  struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT);
188  if (hasher == NULL) {
189  return luaL_error(L, "null userdata");
190  }
191 
192  uint8_t hash[SC_SHA1_LEN];
193  SCSha1Finalize(*hasher, hash, sizeof(hash));
194  lua_pushlstring(L, (const char *)hash, sizeof(hash));
195 
196  // Finalize consumes the hasher, so set to NULL so its not free'd
197  // during garbage collection.
198  *hasher = NULL;
199 
200  return 1;
201 }
202 
203 static int LuaHashLibSha1FinalizeToHex(lua_State *L)
204 {
205  struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT);
206  if (hasher == NULL) {
207  return luaL_error(L, "null userdata");
208  }
209 
210  char hash[SC_SHA1_HEX_LEN + 1];
211  if (!SCSha1FinalizeToHex(*hasher, hash, sizeof(hash))) {
212  *hasher = NULL;
213  return luaL_error(L, "sha1 hashing failed");
214  }
215 
216  lua_pushstring(L, (const char *)hash);
217 
218  // Finalize consumes the hasher, so set to NULL so its not free'd
219  // during garbage collection.
220  *hasher = NULL;
221 
222  return 1;
223 }
224 
225 static int LuaHashLibSha1Digest(lua_State *L)
226 {
227  size_t buf_len;
228  const char *input = luaL_checklstring(L, 1, &buf_len);
229 
230  uint8_t output[SC_SHA1_LEN];
231  if (!SCSha1HashBuffer((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) {
232  return luaL_error(L, "sha1 hashing failed");
233  }
234 
235  lua_pushlstring(L, (const char *)output, sizeof(output));
236  return 1;
237 }
238 
239 static int LuaHashLibSha1HexDigest(lua_State *L)
240 {
241  size_t buf_len;
242  const char *input = luaL_checklstring(L, 1, &buf_len);
243 
244  char output[SC_SHA1_HEX_LEN + 1];
245  if (!SCSha1HashBufferToHex((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) {
246  return luaL_error(L, "sha1 hashing failed");
247  }
248 
249  lua_pushstring(L, (const char *)output);
250  return 1;
251 }
252 
253 static int LuaHashLibSha1Gc(lua_State *L)
254 {
255  struct SCSha1 **hasher = luaL_checkudata(L, 1, SHA1_MT);
256  if (hasher && *hasher) {
257  SCSha1Free(*hasher);
258  }
259  return 0;
260 }
261 
262 static int LuaHashLibMd5New(lua_State *L)
263 {
264  struct SCMd5 **hasher = lua_newuserdata(L, sizeof(struct SCMd5 *));
265  if (hasher == NULL) {
266  return luaL_error(L, "failed to allocate userdata for sha1");
267  }
268  *hasher = SCMd5New();
269  luaL_getmetatable(L, MD5_MT);
270  lua_setmetatable(L, -2);
271  return 1;
272 }
273 
274 static int LuaHashLibMd5Update(lua_State *L)
275 {
276  struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT);
277  if (hasher == NULL) {
278  return luaL_error(L, "null userdata");
279  }
280 
281  size_t data_len;
282  const char *data = luaL_checklstring(L, 2, &data_len);
283  SCMd5Update(*hasher, (const uint8_t *)data, data_len);
284  return 0;
285 }
286 
287 static int LuaHashLibMd5Finalize(lua_State *L)
288 {
289  struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT);
290  if (hasher == NULL) {
291  return luaL_error(L, "null userdata");
292  }
293 
294  uint8_t hash[SC_MD5_LEN];
295  SCMd5Finalize(*hasher, hash, sizeof(hash));
296  lua_pushlstring(L, (const char *)hash, sizeof(hash));
297 
298  // Finalize consumes the hasher, so set to NULL so its not free'd
299  // during garbage collection.
300  *hasher = NULL;
301 
302  return 1;
303 }
304 
305 static int LuaHashLibMd5FinalizeToHex(lua_State *L)
306 {
307  struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT);
308  if (hasher == NULL) {
309  return luaL_error(L, "null userdata");
310  }
311 
312  char hash[SC_MD5_HEX_LEN + 1];
313  if (!SCMd5FinalizeToHex(*hasher, hash, sizeof(hash))) {
314  *hasher = NULL;
315  return luaL_error(L, "md5 hashing failed");
316  }
317 
318  lua_pushstring(L, (const char *)hash);
319 
320  // Finalize consumes the hasher, so set to NULL so its not free'd
321  // during garbage collection.
322  *hasher = NULL;
323 
324  return 1;
325 }
326 
327 static int LuaHashLibMd5Digest(lua_State *L)
328 {
329  size_t buf_len;
330  const char *input = luaL_checklstring(L, 1, &buf_len);
331 
332  uint8_t output[SC_MD5_LEN];
333  if (!SCMd5HashBuffer((uint8_t *)input, (uint32_t)buf_len, output, sizeof(output))) {
334  return luaL_error(L, "md5 hashing failed");
335  }
336 
337  lua_pushlstring(L, (const char *)output, sizeof(output));
338  return 1;
339 }
340 
341 static int LuaHashLibMd5HexDigest(lua_State *L)
342 {
343  size_t buf_len;
344  const char *input = luaL_checklstring(L, 1, &buf_len);
345 
346  char output[SC_MD5_HEX_LEN + 1];
347  if (!SCMd5HashBufferToHex((uint8_t *)input, (size_t)buf_len, output, sizeof(output))) {
348  return luaL_error(L, "md5 hashing failed");
349  }
350 
351  lua_pushstring(L, (const char *)output);
352  return 1;
353 }
354 
355 static int LuaHashLibMd5Gc(lua_State *L)
356 {
357  struct SCMd5 **hasher = luaL_checkudata(L, 1, MD5_MT);
358  if (hasher && *hasher) {
359  SCMd5Free(*hasher);
360  }
361  return 0;
362 }
363 
364 static const struct luaL_Reg hashlib[] = {
365  // clang-format off
366  { "sha256_digest", LuaHashLibSha256Digest },
367  { "sha256_hexdigest", LuaHashLibSha256HexDigest },
368  { "sha256", LuaHashLibSha256New },
369  { "sha1_digest", LuaHashLibSha1Digest },
370  { "sha1_hexdigest", LuaHashLibSha1HexDigest },
371  { "sha1", LuaHashLibSha1New },
372  { "md5_digest", LuaHashLibMd5Digest },
373  { "md5_hexdigest", LuaHashLibMd5HexDigest },
374  { "md5", LuaHashLibMd5New },
375  { NULL, NULL },
376  // clang-format on
377 };
378 
379 static const struct luaL_Reg sha256_meta[] = {
380  // clang-format off
381  { "update", LuaHashLibSha256Update },
382  { "finalize", LuaHashLibSha256Finalize },
383  { "finalize_to_hex", LuaHashLibSha256FinalizeToHex },
384  { "__gc", LuaHashLibSha256Gc },
385  { NULL, NULL },
386  // clang-format on
387 };
388 
389 static const struct luaL_Reg sha1_meta[] = {
390  // clang-format off
391  { "update", LuaHashLibSha1Update },
392  { "finalize", LuaHashLibSha1Finalize },
393  { "finalize_to_hex", LuaHashLibSha1FinalizeToHex },
394  { "__gc", LuaHashLibSha1Gc },
395  { NULL, NULL },
396  // clang-format on
397 };
398 
399 static const struct luaL_Reg md5_meta[] = {
400  // clang-format off
401  { "update", LuaHashLibMd5Update },
402  { "finalize", LuaHashLibMd5Finalize },
403  { "finalize_to_hex", LuaHashLibMd5FinalizeToHex },
404  { "__gc", LuaHashLibMd5Gc },
405  { NULL, NULL },
406  // clang-format on
407 };
408 
410 {
411  luaL_newmetatable(L, SHA256_MT);
412  lua_pushvalue(L, -1);
413  lua_setfield(L, -2, "__index");
414  luaL_setfuncs(L, sha256_meta, 0);
415 
416  luaL_newmetatable(L, SHA1_MT);
417  lua_pushvalue(L, -1);
418  lua_setfield(L, -2, "__index");
419  luaL_setfuncs(L, sha1_meta, 0);
420 
421  luaL_newmetatable(L, MD5_MT);
422  lua_pushvalue(L, -1);
423  lua_setfield(L, -2, "__index");
424  luaL_setfuncs(L, md5_meta, 0);
425 
426  luaL_newlib(L, hashlib);
427 
428  return 1;
429 }
SCSha1
struct SCSha1 SCSha1
Definition: util-file.h:39
SC_SHA256_LEN
#define SC_SHA256_LEN
Definition: util-file.h:37
SC_SHA1_LEN
#define SC_SHA1_LEN
Definition: util-file.h:40
SCLuaLoadHashlib
int SCLuaLoadHashlib(lua_State *L)
Definition: util-lua-hashlib.c:409
util-lua-hashlib.h
SCSha256
struct SCSha256 SCSha256
Definition: util-file.h:36
lua_State
struct lua_State lua_State
Definition: suricata-common.h:515
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:43
SCMd5
struct SCMd5 SCMd5
Definition: util-file.h:42