| /* | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you under the Apache License, Version 2.0 (the | |
| "License"); you may not use this file except in compliance | |
| with the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| #include <openssl/md5.h> | |
| #include <openssl/sha.h> | |
| #include <openssl/hmac.h> | |
| #include "ts_lua_string.h" | |
| #include "ts_lua_util.h" | |
| #define TS_LUA_MD5_DIGEST_LENGTH 16 | |
| #define TS_LUA_SHA1_DIGEST_LENGTH 20 | |
| #define TS_LUA_SHA256_DIGEST_LENGTH 32 | |
| static int ts_lua_md5(lua_State *L); | |
| static int ts_lua_md5_bin(lua_State *L); | |
| static int ts_lua_sha1(lua_State *L); | |
| static int ts_lua_sha1_bin(lua_State *L); | |
| static int ts_lua_sha256(lua_State *L); | |
| static int ts_lua_sha256_bin(lua_State *L); | |
| static int ts_lua_hmac_md5(lua_State *L); | |
| static int ts_lua_hmac_sha1(lua_State *L); | |
| static int ts_lua_hmac_sha256(lua_State *L); | |
| static int ts_lua_base64_encode(lua_State *L); | |
| static int ts_lua_base64_decode(lua_State *L); | |
| static int ts_lua_escape_uri(lua_State *L); | |
| static int ts_lua_unescape_uri(lua_State *L); | |
| void | |
| ts_lua_inject_crypto_api(lua_State *L) | |
| { | |
| /* ts.md5() */ | |
| lua_pushcfunction(L, ts_lua_md5); | |
| lua_setfield(L, -2, "md5"); | |
| /* ts.md5_bin(...) */ | |
| lua_pushcfunction(L, ts_lua_md5_bin); | |
| lua_setfield(L, -2, "md5_bin"); | |
| /* ts.sha1(...) */ | |
| lua_pushcfunction(L, ts_lua_sha1); | |
| lua_setfield(L, -2, "sha1"); | |
| /* ts.sha1_bin(...) */ | |
| lua_pushcfunction(L, ts_lua_sha1_bin); | |
| lua_setfield(L, -2, "sha1_bin"); | |
| /* ts.sha256(...) */ | |
| lua_pushcfunction(L, ts_lua_sha256); | |
| lua_setfield(L, -2, "sha256"); | |
| /* ts.sha256_bin(...) */ | |
| lua_pushcfunction(L, ts_lua_sha256_bin); | |
| lua_setfield(L, -2, "sha256_bin"); | |
| /* ts.hmac_md5(...) */ | |
| lua_pushcfunction(L, ts_lua_hmac_md5); | |
| lua_setfield(L, -2, "hmac_md5"); | |
| /* ts.hmac_sha1(...) */ | |
| lua_pushcfunction(L, ts_lua_hmac_sha1); | |
| lua_setfield(L, -2, "hmac_sha1"); | |
| /* ts.hmac_sha256(...) */ | |
| lua_pushcfunction(L, ts_lua_hmac_sha256); | |
| lua_setfield(L, -2, "hmac_sha256"); | |
| /* ts.base64_encode(...) */ | |
| lua_pushcfunction(L, ts_lua_base64_encode); | |
| lua_setfield(L, -2, "base64_encode"); | |
| /* ts.base64_decode(...) */ | |
| lua_pushcfunction(L, ts_lua_base64_decode); | |
| lua_setfield(L, -2, "base64_decode"); | |
| /* ts.escape_uri(...) */ | |
| lua_pushcfunction(L, ts_lua_escape_uri); | |
| lua_setfield(L, -2, "escape_uri"); | |
| /* ts.unescape_uri(...) */ | |
| lua_pushcfunction(L, ts_lua_unescape_uri); | |
| lua_setfield(L, -2, "unescape_uri"); | |
| } | |
| static int | |
| ts_lua_md5(lua_State *L) | |
| { | |
| u_char *src; | |
| size_t slen; | |
| MD5_CTX md5_ctx; | |
| u_char md5_buf[TS_LUA_MD5_DIGEST_LENGTH]; | |
| u_char hex_buf[2 * sizeof(md5_buf)]; | |
| if (lua_gettop(L) != 1) { | |
| return luaL_error(L, "expecting one argument"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| src = (u_char *)""; | |
| slen = 0; | |
| } else { | |
| src = (u_char *)luaL_checklstring(L, 1, &slen); | |
| } | |
| MD5_Init(&md5_ctx); | |
| MD5_Update(&md5_ctx, src, slen); | |
| MD5_Final(md5_buf, &md5_ctx); | |
| ts_lua_hex_dump(hex_buf, md5_buf, sizeof(md5_buf)); | |
| lua_pushlstring(L, (char *)hex_buf, sizeof(hex_buf)); | |
| return 1; | |
| } | |
| static int | |
| ts_lua_md5_bin(lua_State *L) | |
| { | |
| u_char *src; | |
| size_t slen; | |
| MD5_CTX md5_ctx; | |
| u_char md5_buf[TS_LUA_MD5_DIGEST_LENGTH]; | |
| if (lua_gettop(L) != 1) { | |
| return luaL_error(L, "expecting one argument"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| src = (u_char *)""; | |
| slen = 0; | |
| } else { | |
| src = (u_char *)luaL_checklstring(L, 1, &slen); | |
| } | |
| MD5_Init(&md5_ctx); | |
| MD5_Update(&md5_ctx, src, slen); | |
| MD5_Final(md5_buf, &md5_ctx); | |
| lua_pushlstring(L, (char *)md5_buf, sizeof(md5_buf)); | |
| return 1; | |
| } | |
| static int | |
| ts_lua_sha1(lua_State *L) | |
| { | |
| u_char *src; | |
| size_t slen; | |
| SHA_CTX sha; | |
| u_char sha_buf[TS_LUA_SHA1_DIGEST_LENGTH]; | |
| u_char hex_buf[2 * sizeof(sha_buf)]; | |
| if (lua_gettop(L) != 1) { | |
| return luaL_error(L, "expecting one argument"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| src = (u_char *)""; | |
| slen = 0; | |
| } else { | |
| src = (u_char *)luaL_checklstring(L, 1, &slen); | |
| } | |
| SHA1_Init(&sha); | |
| SHA1_Update(&sha, src, slen); | |
| SHA1_Final(sha_buf, &sha); | |
| ts_lua_hex_dump(hex_buf, sha_buf, sizeof(sha_buf)); | |
| lua_pushlstring(L, (char *)hex_buf, sizeof(hex_buf)); | |
| return 1; | |
| } | |
| static int | |
| ts_lua_sha1_bin(lua_State *L) | |
| { | |
| u_char *src; | |
| size_t slen; | |
| SHA_CTX sha; | |
| u_char sha_buf[TS_LUA_SHA1_DIGEST_LENGTH]; | |
| if (lua_gettop(L) != 1) { | |
| return luaL_error(L, "expecting one argument"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| src = (u_char *)""; | |
| slen = 0; | |
| } else { | |
| src = (u_char *)luaL_checklstring(L, 1, &slen); | |
| } | |
| SHA1_Init(&sha); | |
| SHA1_Update(&sha, src, slen); | |
| SHA1_Final(sha_buf, &sha); | |
| lua_pushlstring(L, (char *)sha_buf, sizeof(sha_buf)); | |
| return 1; | |
| } | |
| static int | |
| ts_lua_sha256(lua_State *L) | |
| { | |
| u_char *src; | |
| size_t slen; | |
| SHA256_CTX sha; | |
| u_char sha_buf[TS_LUA_SHA256_DIGEST_LENGTH]; | |
| u_char hex_buf[2 * sizeof(sha_buf)]; | |
| if (lua_gettop(L) != 1) { | |
| return luaL_error(L, "expecting one argument"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| src = (u_char *)""; | |
| slen = 0; | |
| } else { | |
| src = (u_char *)luaL_checklstring(L, 1, &slen); | |
| } | |
| SHA256_Init(&sha); | |
| SHA256_Update(&sha, src, slen); | |
| SHA256_Final(sha_buf, &sha); | |
| ts_lua_hex_dump(hex_buf, sha_buf, sizeof(sha_buf)); | |
| lua_pushlstring(L, (char *)hex_buf, sizeof(hex_buf)); | |
| return 1; | |
| } | |
| static int | |
| ts_lua_sha256_bin(lua_State *L) | |
| { | |
| u_char *src; | |
| size_t slen; | |
| SHA256_CTX sha; | |
| u_char sha_buf[TS_LUA_SHA256_DIGEST_LENGTH]; | |
| if (lua_gettop(L) != 1) { | |
| return luaL_error(L, "expecting one argument"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| src = (u_char *)""; | |
| slen = 0; | |
| } else { | |
| src = (u_char *)luaL_checklstring(L, 1, &slen); | |
| } | |
| SHA256_Init(&sha); | |
| SHA256_Update(&sha, src, slen); | |
| SHA256_Final(sha_buf, &sha); | |
| lua_pushlstring(L, (char *)sha_buf, sizeof(sha_buf)); | |
| return 1; | |
| } | |
| static int | |
| ts_lua_hmac_md5(lua_State *L) | |
| { | |
| u_char *key; | |
| u_char *src; | |
| size_t klen; | |
| size_t slen; | |
| unsigned char *key_bin; | |
| unsigned int key_bin_len; | |
| u_char sha_buf[TS_LUA_MD5_DIGEST_LENGTH] = {0}; | |
| u_char hex_buf[2 * sizeof(sha_buf)] = {0}; | |
| unsigned int output_length; | |
| if (lua_gettop(L) != 2) { | |
| return luaL_error(L, "expecting two arguments"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| key = (u_char *)""; | |
| klen = 0; | |
| } else { | |
| key = (u_char *)luaL_checklstring(L, 1, &klen); | |
| } | |
| if (lua_isnil(L, 2)) { | |
| src = (u_char *)""; | |
| slen = 0; | |
| } else { | |
| src = (u_char *)luaL_checklstring(L, 2, &slen); | |
| } | |
| key_bin = TSRalloc<unsigned char>((klen / 2) + 1); | |
| if (key_bin == nullptr) { | |
| Dbg(dbg_ctl, "unable to allocate buffer for hex to binary conversion"); | |
| return luaL_error(L, "unable to allocate buffer for hex to binary conversion"); | |
| } | |
| if (ts_lua_hex_to_bin(key_bin, key, klen) == nullptr) { | |
| TSfree(key_bin); | |
| return luaL_error(L, "hex to binary conversion failed"); | |
| } | |
| key_bin_len = klen / 2; | |
| HMAC(EVP_md5(), key_bin, key_bin_len, src, slen, sha_buf, &output_length); | |
| ts_lua_hex_dump(hex_buf, sha_buf, sizeof(sha_buf)); | |
| lua_pushlstring(L, (char *)hex_buf, sizeof(hex_buf)); | |
| TSfree(key_bin); | |
| return 1; | |
| } | |
| static int | |
| ts_lua_hmac_sha1(lua_State *L) | |
| { | |
| u_char *key; | |
| u_char *src; | |
| size_t klen; | |
| size_t slen; | |
| unsigned char *key_bin; | |
| unsigned int key_bin_len; | |
| u_char sha_buf[TS_LUA_SHA1_DIGEST_LENGTH] = {0}; | |
| u_char hex_buf[2 * sizeof(sha_buf)] = {0}; | |
| unsigned int output_length; | |
| if (lua_gettop(L) != 2) { | |
| return luaL_error(L, "expecting two arguments"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| key = (u_char *)""; | |
| klen = 0; | |
| } else { | |
| key = (u_char *)luaL_checklstring(L, 1, &klen); | |
| } | |
| if (lua_isnil(L, 2)) { | |
| src = (u_char *)""; | |
| slen = 0; | |
| } else { | |
| src = (u_char *)luaL_checklstring(L, 2, &slen); | |
| } | |
| key_bin = TSRalloc<unsigned char>((klen / 2) + 1); | |
| if (key_bin == nullptr) { | |
| Dbg(dbg_ctl, "unable to allocate buffer for hex to binary conversion"); | |
| return luaL_error(L, "unable to allocate buffer for hex to binary conversion"); | |
| } | |
| if (ts_lua_hex_to_bin(key_bin, key, klen) == nullptr) { | |
| TSfree(key_bin); | |
| return luaL_error(L, "hex to binary conversion failed"); | |
| } | |
| key_bin_len = klen / 2; | |
| HMAC(EVP_sha1(), key_bin, key_bin_len, src, slen, sha_buf, &output_length); | |
| ts_lua_hex_dump(hex_buf, sha_buf, sizeof(sha_buf)); | |
| lua_pushlstring(L, (char *)hex_buf, sizeof(hex_buf)); | |
| TSfree(key_bin); | |
| return 1; | |
| } | |
| static int | |
| ts_lua_hmac_sha256(lua_State *L) | |
| { | |
| u_char *key; | |
| u_char *src; | |
| size_t klen; | |
| size_t slen; | |
| unsigned char *key_bin; | |
| unsigned int key_bin_len; | |
| u_char sha_buf[TS_LUA_SHA256_DIGEST_LENGTH] = {0}; | |
| u_char hex_buf[2 * sizeof(sha_buf)] = {0}; | |
| unsigned int output_length; | |
| if (lua_gettop(L) != 2) { | |
| return luaL_error(L, "expecting two arguments"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| key = (u_char *)""; | |
| klen = 0; | |
| } else { | |
| key = (u_char *)luaL_checklstring(L, 1, &klen); | |
| } | |
| if (lua_isnil(L, 2)) { | |
| src = (u_char *)""; | |
| slen = 0; | |
| } else { | |
| src = (u_char *)luaL_checklstring(L, 2, &slen); | |
| } | |
| key_bin = TSRalloc<unsigned char>((klen / 2) + 1); | |
| if (key_bin == nullptr) { | |
| Dbg(dbg_ctl, "unable to allocate buffer for hex to binary conversion"); | |
| return luaL_error(L, "unable to allocate buffer for hex to binary conversion"); | |
| } | |
| if (ts_lua_hex_to_bin(key_bin, key, klen) == nullptr) { | |
| TSfree(key_bin); | |
| return luaL_error(L, "hex to binary conversion failed"); | |
| } | |
| key_bin_len = klen / 2; | |
| HMAC(EVP_sha256(), key_bin, key_bin_len, src, slen, sha_buf, &output_length); | |
| ts_lua_hex_dump(hex_buf, sha_buf, sizeof(sha_buf)); | |
| lua_pushlstring(L, (char *)hex_buf, sizeof(hex_buf)); | |
| TSfree(key_bin); | |
| return 1; | |
| } | |
| static int | |
| ts_lua_base64_encode(lua_State *L) | |
| { | |
| u_char *src; | |
| u_char *dst; | |
| size_t slen; | |
| size_t dlen; | |
| size_t length; | |
| if (lua_gettop(L) != 1) { | |
| return luaL_error(L, "expecting one argument"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| src = (u_char *)""; | |
| slen = 0; | |
| } else { | |
| src = (u_char *)luaL_checklstring(L, 1, &slen); | |
| } | |
| dlen = TS_LUA_MAX_STR_LENGTH; | |
| dst = static_cast<u_char *>(lua_newuserdata(L, dlen)); | |
| if (TS_SUCCESS == TSBase64Encode((const char *)src, slen, (char *)dst, dlen, &length)) { | |
| lua_pushlstring(L, (char *)dst, length); | |
| return 1; | |
| } else { | |
| return luaL_error(L, "base64 encoding error"); | |
| } | |
| } | |
| static int | |
| ts_lua_base64_decode(lua_State *L) | |
| { | |
| u_char *src; | |
| u_char *dst; | |
| size_t slen; | |
| size_t dlen; | |
| size_t length; | |
| if (lua_gettop(L) != 1) { | |
| return luaL_error(L, "expecting one argument"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| src = (u_char *)""; | |
| slen = 0; | |
| } else { | |
| src = (u_char *)luaL_checklstring(L, 1, &slen); | |
| } | |
| dlen = TS_LUA_MAX_STR_LENGTH; | |
| dst = static_cast<u_char *>(lua_newuserdata(L, dlen)); | |
| if (TS_SUCCESS == TSBase64Decode((const char *)src, slen, (unsigned char *)dst, dlen, &length)) { | |
| lua_pushlstring(L, (char *)dst, length); | |
| return 1; | |
| } else { | |
| return luaL_error(L, "base64 decoding error"); | |
| } | |
| } | |
| static int | |
| ts_lua_escape_uri(lua_State *L) | |
| { | |
| size_t len, dlen; | |
| u_char *src, *dst; | |
| size_t length; | |
| if (lua_gettop(L) != 1) { | |
| return luaL_error(L, "expecting one argument for ts.escape_uri(...)"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| lua_pushliteral(L, ""); | |
| return 1; | |
| } | |
| src = (u_char *)luaL_checklstring(L, 1, &len); | |
| if (len == 0) { | |
| return 1; | |
| } | |
| dlen = TS_LUA_MAX_STR_LENGTH; | |
| dst = static_cast<u_char *>(lua_newuserdata(L, dlen)); | |
| if (TS_SUCCESS == TSStringPercentEncode((const char *)src, len, (char *)dst, dlen, &length, nullptr)) { | |
| lua_pushlstring(L, (char *)dst, length); | |
| return 1; | |
| } else { | |
| return luaL_error(L, "percent encoding error"); | |
| } | |
| } | |
| static int | |
| ts_lua_unescape_uri(lua_State *L) | |
| { | |
| size_t len, dlen; | |
| u_char *src, *dst; | |
| size_t length; | |
| if (lua_gettop(L) != 1) { | |
| return luaL_error(L, "expecting one argument for ts.unescape_uri(...)"); | |
| } | |
| if (lua_isnil(L, 1)) { | |
| lua_pushliteral(L, ""); | |
| return 1; | |
| } | |
| src = (u_char *)luaL_checklstring(L, 1, &len); | |
| if (len == 0) { | |
| return 1; | |
| } | |
| /* the unescaped string can not be larger, but need to account for terminating null. */ | |
| dlen = len + 1; | |
| dst = static_cast<u_char *>(lua_newuserdata(L, dlen)); | |
| if (TS_SUCCESS == TSStringPercentDecode((const char *)src, len, (char *)dst, dlen, &length)) { | |
| lua_pushlstring(L, (char *)dst, length); | |
| return 1; | |
| } else { | |
| return luaL_error(L, "percent decoding error"); | |
| } | |
| } |