1 /*- 2 * Copyright (c) 2024 Netflix, Inc 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <lua.h> 8 #include "lauxlib.h" 9 #include "lhash.h" 10 11 #include <sha256.h> 12 #include <string.h> 13 14 #include "bootstrap.h" 15 16 #define SHA256_META "SHA256 meta table" 17 #define SHA256_DIGEST_LEN 32 18 19 /* 20 * Note C++ comments indicate the before -- after state of the stack, in with a 21 * similar convention to forth's ( ) comments. Lua indexes are from 1 and can be 22 * read left to right (leftmost is 1). Negative are relative to the end (-1 is 23 * rightmost). A '.' indicates a return value left on the stack (all values to 24 * its right). Trivial functions don't do this. 25 */ 26 27 /* 28 * Updates the digest with the new data passed in. Takes 1 argument, which 29 * is converted to a string. 30 */ 31 static int 32 lua_sha256_update(lua_State *L) 33 { 34 size_t len; 35 const unsigned char *data; 36 SHA256_CTX *ctx; 37 38 ctx = luaL_checkudata(L, 1, SHA256_META); 39 data = luaL_checklstring(L, 2, &len); 40 SHA256_Update(ctx, data, len); 41 42 lua_settop(L, 1); 43 44 return (1); 45 } 46 47 /* 48 * Finalizes the digest value and returns it as a 32-byte binary string. The ctx 49 * is zeroed. 50 */ 51 static int 52 lua_sha256_digest(lua_State *L) 53 { 54 SHA256_CTX *ctx; 55 unsigned char digest[SHA256_DIGEST_LEN]; 56 57 ctx = luaL_checkudata(L, 1, SHA256_META); 58 SHA256_Final(digest, ctx); 59 lua_pushlstring(L, digest, sizeof(digest)); 60 61 return (1); 62 } 63 64 /* 65 * Finalizes the digest value and returns it as a 64-byte ascii string of hex 66 * numbers. The ctx is zeroed. 67 */ 68 static int 69 lua_sha256_hexdigest(lua_State *L) 70 { 71 SHA256_CTX *ctx; 72 char buf[SHA256_DIGEST_LEN * 2 + 1]; 73 unsigned char digest[SHA256_DIGEST_LEN]; 74 static const char hex[]="0123456789abcdef"; 75 int i; 76 77 ctx = luaL_checkudata(L, 1, SHA256_META); 78 SHA256_Final(digest, ctx); 79 for (i = 0; i < SHA256_DIGEST_LEN; i++) { 80 buf[i+i] = hex[digest[i] >> 4]; 81 buf[i+i+1] = hex[digest[i] & 0x0f]; 82 } 83 buf[i+i] = '\0'; 84 85 lua_pushstring(L, buf); 86 87 return (1); 88 } 89 90 /* 91 * Zeros out the ctx before garbage collection. Normally this is done in 92 * obj:digest or obj:hexdigest, but if not, it will be wiped here. Lua 93 * manages freeing the ctx memory. 94 */ 95 static int 96 lua_sha256_done(lua_State *L) 97 { 98 SHA256_CTX *ctx; 99 100 ctx = luaL_checkudata(L, 1, SHA256_META); 101 memset(ctx, 0, sizeof(*ctx)); 102 103 return (0); 104 } 105 106 /* 107 * Create object obj which accumulates the state of the sha256 digest 108 * for its contents and any subsequent obj:update call. It takes zero 109 * or 1 arguments. 110 */ 111 static int 112 lua_sha256(lua_State *L) 113 { 114 SHA256_CTX *ctx; 115 int top; 116 117 /* We take 0 or 1 args */ 118 top = lua_gettop(L); // data -- data 119 if (top > 1) { 120 lua_pushnil(L); 121 return (1); 122 } 123 124 ctx = lua_newuserdata(L, sizeof(*ctx)); // data -- data ctx 125 SHA256_Init(ctx); 126 if (top == 1) { 127 size_t len; 128 const unsigned char *data; 129 130 data = luaL_checklstring(L, 1, &len); 131 SHA256_Update(ctx, data, len); 132 } 133 luaL_setmetatable(L, SHA256_META); // data ctx -- data ctx 134 135 return (1); // data . ctx 136 } 137 138 /* 139 * Setup the metatable to manage our userdata that we create in lua_sha256. We 140 * request a finalization call with __gc so we can zero out the ctx buffer so 141 * that we don't leak secrets if obj:digest or obj:hexdigest aren't called. 142 */ 143 static void 144 register_metatable_sha256(lua_State *L) 145 { 146 luaL_newmetatable(L, SHA256_META); // -- meta 147 148 lua_newtable(L); // meta -- meta tbl 149 lua_pushcfunction(L, lua_sha256_update); // meta tbl -- meta tbl fn 150 lua_setfield(L, -2, "update"); // meta tbl fn -- meta tbl 151 lua_pushcfunction(L, lua_sha256_digest); // meta tbl -- meta tbl fn 152 lua_setfield(L, -2, "digest"); // meta tbl fn -- meta tbl 153 lua_pushcfunction(L, lua_sha256_hexdigest); // meta tbl -- meta tbl fn 154 lua_setfield(L, -2, "hexdigest"); // meta tbl fn -- meta tbl 155 156 /* Associate tbl with metatable */ 157 lua_setfield(L, -2, "__index"); // meta tbl -- meta 158 lua_pushcfunction(L, lua_sha256_done); // meta -- meta fn 159 lua_setfield(L, -2, "__gc"); // meta fn -- meta 160 161 lua_pop(L, 1); // meta -- 162 } 163 164 #define REG_SIMPLE(n) { #n, lua_ ## n } 165 static const struct luaL_Reg hashlib[] = { 166 REG_SIMPLE(sha256), 167 { NULL, NULL }, 168 }; 169 #undef REG_SIMPLE 170 171 int 172 luaopen_hash(lua_State *L) 173 { 174 register_metatable_sha256(L); 175 176 luaL_newlib(L, hashlib); 177 178 return 1; 179 } 180 181 #ifndef _STANDALONE 182 FLUA_MODULE(hash); 183 #endif 184