diff options
Diffstat (limited to 'server/resty/hmac.lua')
-rw-r--r-- | server/resty/hmac.lua | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/server/resty/hmac.lua b/server/resty/hmac.lua new file mode 100644 index 0000000..8d94a8b --- /dev/null +++ b/server/resty/hmac.lua @@ -0,0 +1,167 @@ + +local str_util = require "resty.string" +local to_hex = str_util.to_hex +local ffi = require "ffi" +local ffi_new = ffi.new +local ffi_str = ffi.string +local ffi_gc = ffi.gc +local ffi_typeof = ffi.typeof +local C = ffi.C +local setmetatable = setmetatable +local error = error + + +local _M = { _VERSION = '0.04' } + +local mt = { __index = _M } + + +ffi.cdef[[ +typedef struct engine_st ENGINE; +typedef struct evp_pkey_ctx_st EVP_PKEY_CTX; +typedef struct evp_md_ctx_st EVP_MD_CTX; +typedef struct evp_md_st EVP_MD; +typedef struct hmac_ctx_st HMAC_CTX; + +//OpenSSL 1.0 +void HMAC_CTX_init(HMAC_CTX *ctx); +void HMAC_CTX_cleanup(HMAC_CTX *ctx); + +//OpenSSL 1.1 +HMAC_CTX *HMAC_CTX_new(void); +void HMAC_CTX_free(HMAC_CTX *ctx); + +int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, const EVP_MD *md, ENGINE *impl); +int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len); +int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len); + +const EVP_MD *EVP_md5(void); +const EVP_MD *EVP_sha1(void); +const EVP_MD *EVP_sha256(void); +const EVP_MD *EVP_sha512(void); +]] + +local buf = ffi_new("unsigned char[64]") +local res_len = ffi_new("unsigned int[1]") +local hashes = { + MD5 = C.EVP_md5(), + SHA1 = C.EVP_sha1(), + SHA256 = C.EVP_sha256(), + SHA512 = C.EVP_sha512() +} + +local ctx_new, ctx_free +local openssl11, e = pcall(function () + local ctx = C.HMAC_CTX_new() + C.HMAC_CTX_free(ctx) +end) +if openssl11 then + ctx_new = function () + return C.HMAC_CTX_new() + end + ctx_free = function (ctx) + C.HMAC_CTX_free(ctx) + end +else + ffi.cdef [[ + struct evp_md_ctx_st + { + const EVP_MD *digest; + ENGINE *engine; + unsigned long flags; + void *md_data; + EVP_PKEY_CTX *pctx; + int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count); + }; + + struct evp_md_st + { + int type; + int pkey_type; + int md_size; + unsigned long flags; + int (*init)(EVP_MD_CTX *ctx); + int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count); + int (*final)(EVP_MD_CTX *ctx,unsigned char *md); + int (*copy)(EVP_MD_CTX *to,const EVP_MD_CTX *from); + int (*cleanup)(EVP_MD_CTX *ctx); + + int (*sign)(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, void *key); + int (*verify)(int type, const unsigned char *m, unsigned int m_length, const unsigned char *sigbuf, unsigned int siglen, void *key); + int required_pkey_type[5]; + int block_size; + int ctx_size; + int (*md_ctrl)(EVP_MD_CTX *ctx, int cmd, int p1, void *p2); + }; + + struct hmac_ctx_st + { + const EVP_MD *md; + EVP_MD_CTX md_ctx; + EVP_MD_CTX i_ctx; + EVP_MD_CTX o_ctx; + unsigned int key_length; + unsigned char key[128]; + }; + ]] + + local ctx_ptr_type = ffi_typeof("HMAC_CTX[1]") + + ctx_new = function () + local ctx = ffi_new(ctx_ptr_type) + C.HMAC_CTX_init(ctx) + return ctx + end + ctx_free = function (ctx) + C.HMAC_CTX_cleanup(ctx) + end +end + + +_M.ALGOS = hashes + + +function _M.new(self, key, hash_algo) + local ctx = ctx_new() + + local _hash_algo = hash_algo or hashes.MD5 + + if C.HMAC_Init_ex(ctx, key, #key, _hash_algo, nil) == 0 then + return nil + end + + ffi_gc(ctx, ctx_free) + + return setmetatable({ _ctx = ctx }, mt) +end + + +function _M.update(self, s) + return C.HMAC_Update(self._ctx, s, #s) == 1 +end + + +function _M.final(self, s, hex_output) + + if s ~= nil then + if C.HMAC_Update(self._ctx, s, #s) == 0 then + return nil + end + end + + if C.HMAC_Final(self._ctx, buf, res_len) == 1 then + if hex_output == true then + return to_hex(ffi_str(buf, res_len[0])) + end + return ffi_str(buf, res_len[0]) + end + + return nil +end + + +function _M.reset(self) + return C.HMAC_Init_ex(self._ctx, nil, 0, nil, nil) == 1 +end + +return _M |