· 8 years ago · Mar 02, 2018, 06:58 PM
1/** @file
2 *
3 * This code implements wraps and exports the OpenSSL hashing functions to Lua.
4 *
5 * To use this code arrange for it to be loaded by your Lua interpreter either
6 * by compiling it in or loading a shared library. You'll need to pass various
7 * flags to your compiler to get it to use the OpenSSL libraries, etc. I used
8 * something like this:
9 *
10 * gcc `pkg-config openssl --cflags --libs` -c lhash.c
11 *
12 * Once loaded, this library defines a table called hash which, by the magic of
13 * meta-tables, give access to any hashing function your OpenSSL. Simply access
14 * the functions as members of the table:
15 *
16 * print(hash.md5("Foo"))
17 *
18 * t = hash.sha1("Some data", "Some more data")
19 *
20 * pw = hash.sha1("salt", io.read())
21 *
22 * Comments, questions, and suggestions are welcome and should be addressed to
23 *
24 * Thomas Sutton
25 * <me@thomas-sutton.id.au>
26 *
27 * -----------------------------------------------------------------------------
28 *
29 * Copyright (c) 2009 Thomas Sutton
30 *
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions are met:
35 *
36 * 1. Redistributions of source code must retain the above copyright notice,
37 * this list of conditions and the following disclaimer.
38 *
39 * 2. Redistributions in binary form must reproduce the above copyright notice,
40 * this list of conditions and the following disclaimer in the documentation
41 * and/or other materials provided with the distribution.
42 *
43 * 3. Neither the name of the author nor the names of his contributors may be
44 * used to endorse or promote products derived from this software without
45 * specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
48 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
49 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
50 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
52 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
53 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
54 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
55 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
56 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 */
58
59#include <stdlib.h>
60#include <openssl/evp.h>
61
62#define lhash_c
63#define LUA_LIB
64
65#include "lua.h"
66
67/**
68 * Hash all arguments passed to the function using the algorithm named in
69 * the closure.
70 */
71static int hash_hash (lua_State *L) {
72 EVP_MD_CTX mdctx;
73 const EVP_MD *md;
74 unsigned char md_value[EVP_MAX_MD_SIZE];
75 char *algorithm = NULL;
76 char *digest = NULL;
77 char *cur = NULL;
78 unsigned int md_len = 0;
79 unsigned int arguments = 0;
80 unsigned int i = 0;
81 size_t msg_len = 0;
82
83 // Get the algorithm name from the closure
84 algorithm = (char *)lua_tostring(L, lua_upvalueindex(1));
85
86 // Get the number of stack arguments
87 arguments = lua_gettop(L);
88
89 // Get the digest
90 md = EVP_get_digestbyname(algorithm);
91 if (! md ) {
92 lua_pushfstring(L, "No such hash algorithm: %s", algorithm);
93 return lua_error(L);
94 }
95
96 // Initialise the hash context
97 EVP_MD_CTX_init(&mdctx);
98 EVP_DigestInit_ex(&mdctx, md, NULL);
99
100 // Add the arguments to the hash.
101 for ( i = 1; i <= arguments; i++ ) {
102 cur = (char *)lua_tolstring(L, i, &msg_len);
103 EVP_DigestUpdate(&mdctx, cur, msg_len);
104 }
105
106 // Finalise the hash
107 EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
108 EVP_MD_CTX_cleanup(&mdctx);
109
110 // Convert to a string and push it on the Lua stack
111 msg_len = 1 + 2 * md_len;
112 cur = digest = (char*)malloc(msg_len);
113 for (i=0;i<md_len;i++) {
114 snprintf(cur, 3, "%02x", md_value[i]);
115 cur = cur + 2;
116 }
117 cur[0] = '\0';
118 // fprintf(stderr, "Hash was: %s\n", digest);
119 lua_pushstring(L, digest);
120 free(digest);
121
122 return(1);
123}
124
125/**
126 * Create a closure of hash_hash() and an algorithm name.
127 */
128static int hash_index (lua_State *L) {
129 const EVP_MD *md;
130 char *algorithm = NULL;
131
132 // Get the algorithm name
133 algorithm = (char *)lua_tostring(L, 2);
134
135 // Check that the algorithm exists
136 md = EVP_get_digestbyname(algorithm);
137 if (! md ) {
138 lua_pushfstring(L, "No such hash algorithm: %s", algorithm);
139 return lua_error(L);
140 }
141
142 // Push a closure of algorithm name with hash_hash()
143 lua_pushstring(L, algorithm);
144 lua_pushcclosure(L, hash_hash, 1);
145
146 return 1;
147}
148
149/**
150 * Register the library's tables.
151 */
152LUALIB_API int luaopen_hash (lua_State *L) {
153 // Initialize OpenSSL hashing stuff
154 OpenSSL_add_all_digests();
155
156 // Create the 'hash' table
157 lua_createtable(L, 0, 0);
158
159 // Create the meta-table
160 lua_createtable(L, 0, 1);
161
162 // Add hash as __index
163 lua_pushcfunction(L, hash_index);
164 lua_setfield(L, -2, "__index");
165
166 // Set metatable
167 lua_setmetatable(L, -2);
168 // Set global field "hash"
169 lua_setfield(L, LUA_GLOBALSINDEX, "hash");
170
171 return 0;
172};