• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/lib/digest.c

  1 /*
  2  * Copyright (C) 2024 Sebastian Ertz <sebastian.ertz@gmx.de>
  3  *
  4  * Permission to use, copy, modify, and/or distribute this software for any
  5  * purpose with or without fee is hereby granted, provided that the above
  6  * copyright notice and this permission notice appear in all copies.
  7  *
  8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15  */
 16 
 17 /**
 18  * # Digest Functions
 19  *
 20  * The `digest` module bundles various digest functions.
 21  *
 22  * @module digest
 23  */
 24 
 25 #include <md5.h>
 26 #include <sha1.h>
 27 #include <sha2.h>
 28 
 29 #ifdef HAVE_DIGEST_EXTENDED
 30 #include <md2.h>
 31 #include <md4.h>
 32 #endif
 33 
 34 #include "ucode/module.h"
 35 
 36 
 37 static uc_value_t *
 38 uc_digest_calc_data(uc_value_t *str, char *(*fn)(const uint8_t *,size_t,char *))
 39 {
 40         char buf[SHA512_DIGEST_STRING_LENGTH];
 41 
 42         if( ucv_type(str) != UC_STRING )
 43                 return NULL;
 44 
 45         if( fn((const uint8_t *)ucv_string_get(str), ucv_string_length(str), buf) )
 46                 return ucv_string_new(buf);
 47 
 48         return NULL;
 49 }
 50 
 51 static uc_value_t *
 52 uc_digest_calc_file(uc_value_t *path, char *(fn)(const char *,char *))
 53 {
 54         char buf[SHA512_DIGEST_STRING_LENGTH];
 55 
 56         if( ucv_type(path) != UC_STRING )
 57                 return NULL;
 58 
 59         if( fn(ucv_string_get(path), buf) )
 60                 return ucv_string_new(buf);
 61 
 62         return NULL;
 63 }
 64 
 65 static char *
 66 uc_digest_fnv1a64_data_hash(const uint8_t *data, size_t len, char *out)
 67 {
 68         static const char hex[] = "0123456789abcdef";
 69         uint64_t hash = 0xCBF29CE484222325;
 70 
 71         for (size_t i = 0; i < len; i++) {
 72                 hash ^= data[i];
 73                 hash *= 0x00000100000001B3;
 74         }
 75 
 76         for (int i = 0; i < 8; i++) {
 77                 uint8_t byte = (hash >> ((7 - i) * 8)) & 0xFF;
 78                 out[i * 2]     = hex[byte >> 4];
 79                 out[i * 2 + 1] = hex[byte & 0xF];
 80         }
 81 
 82         out[16] = '\0';
 83         return out;
 84 }
 85 
 86 static char *
 87 uc_digest_fnv1a64_file_hash(const char *path, char *out)
 88 {
 89         FILE *f = fopen(path, "rb");
 90         if (!f)
 91                 return NULL;
 92 
 93         static const char hex[] = "0123456789abcdef";
 94         uint64_t hash = 0xCBF29CE484222325;
 95         unsigned char buf[4096];
 96         size_t n;
 97 
 98         while ((n = fread(buf, 1, sizeof(buf), f)) > 0) {
 99                 for (size_t i = 0; i < n; i++) {
100                         hash ^= buf[i];
101                         hash *= 0x00000100000001B3;
102                 }
103         }
104 
105         if (ferror(f)) {
106                 fclose(f);
107                 return NULL;
108         }
109 
110         fclose(f);
111 
112         for (int i = 0; i < 8; i++) {
113                 uint8_t byte = (hash >> ((7 - i) * 8)) & 0xFF;
114                 out[i * 2]     = hex[byte >> 4];
115                 out[i * 2 + 1] = hex[byte & 0xF];
116         }
117 
118         out[16] = '\0';
119         return out;
120 }
121 
122 /**
123  * Calculates the MD5 hash of string and returns that hash.
124  *
125  * Returns `null` if a non-string argument is given.
126  *
127  * @function module:digest#md5
128  *
129  * @param {string} str
130  * The string to hash.
131  *
132  * @returns {?string}
133  *
134  * @example
135  * md5("This is a test");  // Returns "ce114e4501d2f4e2dcea3e17b546f339"
136  * md5(123);               // Returns null
137  */
138 static uc_value_t *
139 uc_digest_md5(uc_vm_t *vm, size_t nargs)
140 {
141         return uc_digest_calc_data(uc_fn_arg(0), MD5Data);
142 }
143 
144 /**
145  * Calculates the SHA1 hash of string and returns that hash.
146  *
147  * Returns `null` if a non-string argument is given.
148  *
149  * @function module:digest#sha1
150  *
151  * @param {string} str
152  * The string to hash.
153  *
154  * @returns {?string}
155  *
156  * @example
157  * sha1("This is a test");  // Returns "a54d88e06612d820bc3be72877c74f257b561b19"
158  * sha1(123);               // Returns null
159  */
160 static uc_value_t *
161 uc_digest_sha1(uc_vm_t *vm, size_t nargs)
162 {
163         return uc_digest_calc_data(uc_fn_arg(0), SHA1Data);
164 }
165 
166 /**
167  * Calculates the SHA256 hash of string and returns that hash.
168  *
169  * Returns `null` if a non-string argument is given.
170  *
171  * @function module:digest#sha256
172  *
173  * @param {string} str
174  * The string to hash.
175  *
176  * @returns {?string}
177  *
178  * @example
179  * sha256("This is a test");  // Returns "c7be1ed902fb8dd4d48997c6452f5d7e509fbcdbe2808b16bcf4edce4c07d14e"
180  * sha256(123);               // Returns null
181  */
182 static uc_value_t *
183 uc_digest_sha256(uc_vm_t *vm, size_t nargs)
184 {
185         return uc_digest_calc_data(uc_fn_arg(0), SHA256Data);
186 }
187 
188 /**
189  * Calculates the 64-bit FNV-1a non-cryptographic hash of string and returns
190  * that hash.
191  *
192  * Returns `null` if a non-string argument is given.
193  *
194  * @function module:digest#fnv1a64
195  *
196  * @param {string} str
197  * The string to hash.
198  *
199  * @returns {?string}
200  *
201  * @example
202  * fnv1a64("This is a test");  // Returns "25f0b040ca8b4ce0"
203  * fnv1a64(123);               // Returns null
204  */
205 static uc_value_t *
206 uc_digest_fnv1a64(uc_vm_t *vm, size_t nargs)
207 {
208         return uc_digest_calc_data(uc_fn_arg(0), uc_digest_fnv1a64_data_hash);
209 }
210 
211 /**
212  * Calculates the 64-bit FNV-1a non-cryptographic hash of a given file and
213  * returns that hash.
214  *
215  * Returns `null` if an error occurred.
216  *
217  * @function module:digest#fnv1a64_file
218  *
219  * @param {string} path
220  * The path to the file.
221  *
222  * @returns {?string}
223  */
224 static uc_value_t *
225 uc_digest_fnv1a64_file(uc_vm_t *vm, size_t nargs)
226 {
227         return uc_digest_calc_file(uc_fn_arg(0), uc_digest_fnv1a64_file_hash);
228 }
229 
230 #ifdef HAVE_DIGEST_EXTENDED
231 /**
232  * Calculates the MD2 hash of string and returns that hash.
233  *
234  * Returns `null` if a non-string argument is given.
235  *
236  * @function module:digest#md2
237  *
238  * @param {string} str
239  * The string to hash.
240  *
241  * @returns {?string}
242  *
243  * @example
244  * md2("This is a test");  // Returns "dc378580fd0722e56b82666a6994c718"
245  * md2(123);               // Returns null
246  */
247 static uc_value_t *
248 uc_digest_md2(uc_vm_t *vm, size_t nargs)
249 {
250         return uc_digest_calc_data(uc_fn_arg(0), MD2Data);
251 }
252 
253 /**
254  * Calculates the MD4 hash of string and returns that hash.
255  *
256  * Returns `null` if a non-string argument is given.
257  *
258  * @function module:digest#md4
259  *
260  * @param {string} str
261  * The string to hash.
262  *
263  * @returns {?string}
264  *
265  * @example
266  * md4("This is a test");  // Returns "3b487cf6856af7e330bc4b1b7d977ef8"
267  * md4(123);               // Returns null
268  */
269 static uc_value_t *
270 uc_digest_md4(uc_vm_t *vm, size_t nargs)
271 {
272         return uc_digest_calc_data(uc_fn_arg(0), MD4Data);
273 }
274 
275 /**
276  * Calculates the SHA384 hash of string and returns that hash.
277  *
278  * Returns `null` if a non-string argument is given.
279  *
280  * @function module:digest#sha384
281  *
282  * @param {string} str
283  * The string to hash.
284  *
285  * @returns {?string}
286  *
287  * @example
288  * sha384("This is a test");  // Returns "a27c7667e58200d4c0688ea136968404a0da366b1a9fc19bb38a0c7a609a1eef2bcc82837f4f4d92031a66051494b38c"
289  * sha384(123);               // Returns null
290  */
291 static uc_value_t *
292 uc_digest_sha384(uc_vm_t *vm, size_t nargs)
293 {
294         return uc_digest_calc_data(uc_fn_arg(0), SHA384Data);
295 }
296 
297 /**
298  * Calculates the SHA512 hash of string and returns that hash.
299  *
300  * Returns `null` if a non-string argument is given.
301  *
302  * @function module:digest#sha512
303  *
304  * @param {string} str
305  * The string to hash.
306  *
307  * @returns {?string}
308  *
309  * @example
310  * sha512("This is a test");  // Returns "a028d4f74b602ba45eb0a93c9a4677240dcf281a1a9322f183bd32f0bed82ec72de9c3957b2f4c9a1ccf7ed14f85d73498df38017e703d47ebb9f0b3bf116f69"
311  * sha512(123);               // Returns null
312  */
313 static uc_value_t *
314 uc_digest_sha512(uc_vm_t *vm, size_t nargs)
315 {
316         return uc_digest_calc_data(uc_fn_arg(0), SHA512Data);
317 }
318 #endif
319 
320 /**
321  * Calculates the MD5 hash of a given file and returns that hash.
322  *
323  * Returns `null` if an error occurred.
324  *
325  * @function module:digest#md5_file
326  *
327  * @param {string} path
328  * The path to the file.
329  *
330  * @returns {?string}
331  */
332 static uc_value_t *
333 uc_digest_md5_file(uc_vm_t *vm, size_t nargs)
334 {
335         return uc_digest_calc_file(uc_fn_arg(0), MD5File);
336 }
337 
338 /**
339  * Calculates the SHA1 hash of a given file and returns that hash.
340  *
341  * Returns `null` if an error occurred.
342  *
343  * @function module:digest#sha1_file
344  *
345  * @param {string} path
346  * The path to the file.
347  *
348  * @returns {?string}
349  */
350 static uc_value_t *
351 uc_digest_sha1_file(uc_vm_t *vm, size_t nargs)
352 {
353         return uc_digest_calc_file(uc_fn_arg(0), SHA1File);
354 }
355 
356 /**
357  * Calculates the SHA256 hash of a given file and returns that hash.
358  *
359  * Returns `null` if an error occurred.
360  *
361  * @function module:digest#sha256_file
362  *
363  * @param {string} path
364  * The path to the file.
365  *
366  * @returns {?string}
367  */
368 static uc_value_t *
369 uc_digest_sha256_file(uc_vm_t *vm, size_t nargs)
370 {
371         return uc_digest_calc_file(uc_fn_arg(0), SHA256File);
372 }
373 
374 #ifdef HAVE_DIGEST_EXTENDED
375 /**
376  * Calculates the MD2 hash of a given file and returns that hash.
377  *
378  * Returns `null` if an error occurred.
379  *
380  * @function module:digest#md2_file
381  *
382  * @param {string} path
383  * The path to the file.
384  *
385  * @returns {?string}
386  */
387 static uc_value_t *
388 uc_digest_md2_file(uc_vm_t *vm, size_t nargs)
389 {
390         return uc_digest_calc_file(uc_fn_arg(0), MD2File);
391 }
392 
393 /**
394  * Calculates the MD4 hash of a given file and returns that hash.
395  *
396  * Returns `null` if an error occurred.
397  *
398  * @function module:digest#md4_file
399  *
400  * @param {string} path
401  * The path to the file.
402  *
403  * @returns {?string}
404  */
405 static uc_value_t *
406 uc_digest_md4_file(uc_vm_t *vm, size_t nargs)
407 {
408         return uc_digest_calc_file(uc_fn_arg(0), MD4File);
409 }
410 
411 /**
412  * Calculates the SHA384 hash of a given file and returns that hash.
413  *
414  * Returns `null` if an error occurred.
415  *
416  * @function module:digest#sha384_file
417  *
418  * @param {string} path
419  * The path to the file.
420  *
421  * @returns {?string}
422  */
423 static uc_value_t *
424 uc_digest_sha384_file(uc_vm_t *vm, size_t nargs)
425 {
426         return uc_digest_calc_file(uc_fn_arg(0), SHA384File);
427 }
428 
429 /**
430  * Calculates the SHA512 hash of a given file and returns that hash.
431  *
432  * Returns `null` if an error occurred.
433  *
434  * @function module:digest#sha512_file
435  *
436  * @param {string} path
437  * The path to the file.
438  *
439  * @returns {?string}
440  */
441 static uc_value_t *
442 uc_digest_sha512_file(uc_vm_t *vm, size_t nargs)
443 {
444         return uc_digest_calc_file(uc_fn_arg(0), SHA512File);
445 }
446 #endif
447 
448 
449 static const uc_function_list_t global_fns[] = {
450         { "md5",         uc_digest_md5         },
451         { "sha1",        uc_digest_sha1        },
452         { "sha256",      uc_digest_sha256      },
453         { "fnv1a64",     uc_digest_fnv1a64     },
454         { "md5_file",    uc_digest_md5_file    },
455         { "sha1_file",   uc_digest_sha1_file   },
456         { "sha256_file", uc_digest_sha256_file },
457         { "fnv1a64_file",uc_digest_fnv1a64_file},
458 #ifdef HAVE_DIGEST_EXTENDED
459         { "md2",         uc_digest_md2         },
460         { "md4",         uc_digest_md4         },
461         { "sha384",      uc_digest_sha384      },
462         { "sha512",      uc_digest_sha512      },
463         { "md2_file",    uc_digest_md2_file    },
464         { "md4_file",    uc_digest_md4_file    },
465         { "sha384_file", uc_digest_sha384_file },
466         { "sha512_file", uc_digest_sha512_file },
467 #endif
468 };
469 
470 void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
471 {
472         uc_function_list_register(scope, global_fns);
473 }
474 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt