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