├── .github └── workflows │ ├── ci.yml │ └── publish.yml ├── .gitignore ├── Dockerfile ├── Makefile ├── README.markdown ├── dist.ini ├── docker-compose.yml ├── lib └── resty │ └── hmac.lua ├── rockspec └── lua-resty-hmac-ffi-0.06-1.rockspec ├── t ├── hmac.t └── version.t └── valgrind.suppress /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Unit test 11 | run: docker-compose up 12 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: LuaRocks publish 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | luarocks-release: 9 | runs-on: ubuntu-latest 10 | name: LuaRocks upload 11 | environment: release 12 | 13 | steps: 14 | - uses: actions/checkout@master 15 | 16 | - uses: leafo/gh-actions-lua@v10 17 | with: 18 | luaVersion: "5.1.5" 19 | 20 | - uses: leafo/gh-actions-luarocks@v4 21 | 22 | - name: publish 23 | run: | 24 | luarocks install lua-cjson 25 | luarocks install luasec 26 | luarocks upload rockspec/lua-resty-hmac-ffi-${{ github.ref_name }}.rockspec --api-key=$LUAROCKS_API_KEY 27 | env: 28 | LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }} 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | *~ 4 | go 5 | t/servroot/ 6 | reindex 7 | resty_modules -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openresty/openresty:bullseye-fat 2 | 3 | WORKDIR /app 4 | 5 | RUN apt-get update && apt-get install -y make cpanminus && cpanm -n Test::Nginx && apt-get clean 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr/local/openresty 2 | LUA_LIB_DIR ?= $(PREFIX)/lualib 3 | INSTALL ?= install 4 | VALGRIND ?= 0 5 | CHECK_LEAK ?= 0 6 | MODULES ?= 7 | 8 | .PHONY: all test install 9 | 10 | all: 11 | @$(INSTALL) -d resty_modules/lualib/resty 12 | @test -f resty_modules/lualib/resty/string.lua || curl -s -o resty_modules/lualib/resty/string.lua https://raw.githubusercontent.com/openresty/lua-resty-string/master/lib/resty/string.lua 13 | 14 | install: all 15 | $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/resty 16 | $(INSTALL) resty_modules/lualib/resty/*.lua $(DESTDIR)$(LUA_LIB_DIR)/resty 17 | $(INSTALL) lib/resty/*.lua $(DESTDIR)$(LUA_LIB_DIR)/resty 18 | 19 | test: install 20 | LUA_PATH="$(DESTDIR)$(LUA_LIB_DIR)/?.lua;;" TEST_NGINX_USE_VALGRIND=$(VALGRIND) TEST_NGINX_CHECK_LEAK=$(CHECK_LEAK) TEST_NGINX_LOAD_MODULES="$(MODULES)" prove -I../test-nginx/lib -r t 21 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Name 2 | ==== 3 | 4 | lua-resty-hmac - HMAC functions for ngx_lua and LuaJIT 5 | 6 | Table of Contents 7 | ================= 8 | 9 | * [Name](#name) 10 | * [Status](#status) 11 | * [Description](#description) 12 | * [Synopsis](#synopsis) 13 | * [Methods](#methods) 14 | * [new](#new) 15 | * [update](#update) 16 | * [final](#final) 17 | * [reset](#reset) 18 | * [Prerequisites](#prerequisites) 19 | * [Installation](#installation) 20 | * [Copyright and License](#copyright-and-license) 21 | * [See Also](#see-also) 22 | 23 | Status 24 | ====== 25 | 26 | This library is still under active development and is considered production ready. 27 | 28 | Description 29 | =========== 30 | 31 | This library requires an nginx build with OpenSSL, 32 | the [ngx_lua module](http://wiki.nginx.org/HttpLuaModule), and [LuaJIT 2.0](http://luajit.org/luajit.html). 33 | 34 | Synopsis 35 | ======== 36 | 37 | ```lua 38 | # nginx.conf: 39 | 40 | lua_package_path "/path/to/lua-resty-hmac/lib/?.lua;;"; 41 | 42 | server { 43 | location = /test { 44 | content_by_lua_file conf/test.lua; 45 | } 46 | } 47 | 48 | -- conf/test.lua: 49 | 50 | local hmac = require "resty.hmac" 51 | 52 | local hmac_sha1 = hmac:new("secret_key", hmac.ALGOS.SHA1) 53 | if not hmac_sha1 then 54 | ngx.say("failed to create the hmac_sha1 object") 55 | return 56 | end 57 | 58 | local ok = hmac_sha1:update("he") 59 | if not ok then 60 | ngx.say("failed to add data") 61 | return 62 | end 63 | 64 | ok = hmac_sha1:update("llo") 65 | if not ok then 66 | ngx.say("failed to add data") 67 | return 68 | end 69 | 70 | local mac = hmac_sha1:final() -- binary mac 71 | 72 | local str = require "resty.string" 73 | ngx.say("hmac_sha1: ", str.to_hex(mac)) 74 | -- output: "hmac_sha1: aee4b890b574ea8fa4f6a66aed96c3e590e5925a" 75 | 76 | -- dont forget to reset after final! 77 | if not hmac_sha1:reset() then 78 | ngx.say("failed to reset hmac_sha1") 79 | return 80 | end 81 | 82 | -- short version 83 | ngx.say("hmac_sha1: ", hmac_sha1:final("world", true)) 84 | -- output: "hmac_sha1: 4e9538f1efbe565c522acfb72fce6092ea6b15e0" 85 | ``` 86 | 87 | [Back to TOC](#table-of-contents) 88 | 89 | Methods 90 | ======= 91 | 92 | To load this library, 93 | 94 | 1. you need to specify this library's path in ngx_lua's [lua_package_path](https://github.com/openresty/lua-nginx-module#lua_package_path) directive. For example, `lua_package_path "/path/to/lua-resty-hmac/lib/?.lua;;";`. 95 | 2. you use `require` to load the library into a local Lua variable: 96 | 97 | ```lua 98 | local hmac = require "resty.hmac" 99 | ``` 100 | 101 | [Back to TOC](#table-of-contents) 102 | 103 | new 104 | --- 105 | `syntax: local hmac_sha256 = hmac:new(key [, hash_algorithm])` 106 | 107 | Creates a new hmac instance. If failed, returns `nil`. 108 | 109 | The `key` argument specifies the key to use when calculating the message authentication code (MAC). 110 | `key` is a lua string which may contain printable characters or binary data. 111 | 112 | The `hash_algorithm` argument specifies which hashing algorithm to use (`hmac.ALGOS.MD5`, `hmac.ALGOS.SHA1`, `hmac.ALGOS.SHA256`, `hmac.ALGOS.SHA512`). 113 | The default value is `hmac.ALGOS.MD5`. 114 | 115 | [Back to TOC](#table-of-contents) 116 | 117 | update 118 | --- 119 | `syntax: hmac_sha256:update(data)` 120 | 121 | Updates the MAC calculation to include new data. If failed, returns `false`. 122 | 123 | The `data` argument specifies the additional data to include in the MAC. 124 | `data` is a lua string which may contain printable characters or binary data. 125 | 126 | [Back to TOC](#table-of-contents) 127 | 128 | final 129 | --- 130 | `syntax: local mac = hmac_sha256:final([data, output_hex])` 131 | 132 | Finalizes the MAC calculation and returns the final MAC value. If failed, returns `nil`. 133 | When `output_hex` is not `true` returns a lua string containing the raw, binary MAC. When `output_hex` is `true` returns a lua string containing the hexadecimal representation of the MAC. 134 | 135 | The `data` argument specifies the additional data to include in the MAC before finalizing the calculation. 136 | The default value is `nil`. 137 | 138 | The `output_hex` argument specifies wether the MAC should be returned as hex or binary. If `true` the MAC will be returned as hex. 139 | The default value is `false`. 140 | 141 | [Back to TOC](#table-of-contents) 142 | 143 | reset 144 | ------ 145 | `syntax: hmac_sha256:reset()` 146 | 147 | Resets the internal hmac context so it can be re-used to calculate a new MAC. If failed, returns `false`. 148 | If successful, the `key` and `hash_algorithm` remain the same but all other information is cleared. 149 | 150 | This MUST be called after `hmac_sha256:final()` in order to calculate a new MAC using the same hmac instance. 151 | 152 | [Back to TOC](#table-of-contents) 153 | 154 | Prerequisites 155 | ============= 156 | 157 | * [LuaJIT](http://luajit.org) 2.0+ 158 | * [ngx_lua module](http://wiki.nginx.org/HttpLuaModule) 159 | * [lua-resty-string](https://github.com/openresty/lua-resty-string) 0.8+ 160 | * [OpenSSL](https://www.openssl.org/) 1.0.0+ 161 | 162 | [Back to TOC](#table-of-contents) 163 | 164 | Installation 165 | ============ 166 | 167 | It is recommended to use the latest [ngx_openresty bundle](http://openresty.org) directly. You'll need to enable LuaJIT when building your ngx_openresty 168 | bundle by passing the `--with-luajit` option to its `./configure` script. 169 | 170 | Also, You need to configure 171 | the [lua_package_path](https://github.com/openresty/lua-nginx-module#lua_package_path) directive to 172 | add the path of your lua-resty-hmac source tree to ngx_lua's Lua module search path, as in 173 | 174 | ```nginx 175 | # nginx.conf 176 | http { 177 | lua_package_path "/path/to/lua-resty-hmac/lib/?.lua;;"; 178 | ... 179 | } 180 | ``` 181 | 182 | and then load the library in Lua: 183 | 184 | ```lua 185 | local hmac = require "resty.hmac" 186 | ``` 187 | 188 | [Back to TOC](#table-of-contents) 189 | 190 | Copyright and License 191 | ===================== 192 | 193 | This module is licensed under the BSD license. 194 | 195 | Copyright (C) 2012-2023, Thought Foundry Inc. 196 | 197 | All rights reserved. 198 | 199 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 200 | 201 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 202 | 203 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 204 | 205 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 206 | 207 | [Back to TOC](#table-of-contents) 208 | 209 | See Also 210 | ======== 211 | * the ngx_lua module: http://wiki.nginx.org/HttpLuaModule 212 | 213 | [Back to TOC](#table-of-contents) 214 | 215 | -------------------------------------------------------------------------------- /dist.ini: -------------------------------------------------------------------------------- 1 | # distribution config for opm packaging 2 | name = lua-resty-hmac 3 | abstract = HMAC functions for ngx_lua and LuaJIT 4 | author = Jon Keys 5 | is_original = yes 6 | license = 2bsd 7 | lib_dir = lib 8 | repo_link = https://github.com/jkeys089/lua-resty-hmac 9 | main_module = lib/resty/hmac.lua 10 | requires = luajit >= 2.0.0, openresty/lua-resty-string >= 0.08 -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | 3 | services: 4 | lua-resty-hmac: 5 | build: 6 | context: . 7 | volumes: 8 | - ".:/app" 9 | image: lua-resty-hmac:latest 10 | command: make test 11 | -------------------------------------------------------------------------------- /lib/resty/hmac.lua: -------------------------------------------------------------------------------- 1 | 2 | local str_util = require "resty.string" 3 | local to_hex = str_util.to_hex 4 | local ffi = require "ffi" 5 | local ffi_new = ffi.new 6 | local ffi_str = ffi.string 7 | local ffi_gc = ffi.gc 8 | local ffi_typeof = ffi.typeof 9 | local C = ffi.C 10 | local setmetatable = setmetatable 11 | 12 | 13 | local _M = { _VERSION = '0.06' } 14 | 15 | local mt = { __index = _M } 16 | 17 | 18 | ffi.cdef[[ 19 | typedef struct engine_st ENGINE; 20 | typedef struct evp_pkey_ctx_st EVP_PKEY_CTX; 21 | typedef struct hmac_ctx_st HMAC_CTX; 22 | 23 | //OpenSSL 1.0 24 | void HMAC_CTX_init(HMAC_CTX *ctx); 25 | void HMAC_CTX_cleanup(HMAC_CTX *ctx); 26 | 27 | //OpenSSL 1.1 28 | HMAC_CTX *HMAC_CTX_new(void); 29 | void HMAC_CTX_free(HMAC_CTX *ctx); 30 | ]] 31 | 32 | local buf = ffi_new("unsigned char[64]") 33 | local res_len = ffi_new("unsigned int[1]") 34 | 35 | local ctx_new, ctx_free 36 | local openssl11, e = pcall(function () 37 | local ctx = C.HMAC_CTX_new() 38 | C.HMAC_CTX_free(ctx) 39 | end) 40 | if openssl11 then 41 | ffi.cdef [[ 42 | typedef struct evp_md_ctx_st EVP_MD_CTX; 43 | typedef struct evp_md_st EVP_MD; 44 | ]] 45 | ctx_new = function () 46 | return C.HMAC_CTX_new() 47 | end 48 | ctx_free = function (ctx) 49 | C.HMAC_CTX_free(ctx) 50 | end 51 | else 52 | ffi.cdef [[ 53 | typedef struct env_md_ctx_st EVP_MD_CTX; 54 | typedef struct env_md_st EVP_MD; 55 | struct env_md_ctx_st 56 | { 57 | const EVP_MD *digest; 58 | ENGINE *engine; 59 | unsigned long flags; 60 | void *md_data; 61 | EVP_PKEY_CTX *pctx; 62 | int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count); 63 | }; 64 | 65 | struct env_md_st 66 | { 67 | int type; 68 | int pkey_type; 69 | int md_size; 70 | unsigned long flags; 71 | int (*init)(EVP_MD_CTX *ctx); 72 | int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count); 73 | int (*final)(EVP_MD_CTX *ctx,unsigned char *md); 74 | int (*copy)(EVP_MD_CTX *to,const EVP_MD_CTX *from); 75 | int (*cleanup)(EVP_MD_CTX *ctx); 76 | 77 | int (*sign)(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, void *key); 78 | int (*verify)(int type, const unsigned char *m, unsigned int m_length, const unsigned char *sigbuf, unsigned int siglen, void *key); 79 | int required_pkey_type[5]; 80 | int block_size; 81 | int ctx_size; 82 | int (*md_ctrl)(EVP_MD_CTX *ctx, int cmd, int p1, void *p2); 83 | }; 84 | 85 | struct hmac_ctx_st 86 | { 87 | const EVP_MD *md; 88 | EVP_MD_CTX md_ctx; 89 | EVP_MD_CTX i_ctx; 90 | EVP_MD_CTX o_ctx; 91 | unsigned int key_length; 92 | unsigned char key[128]; 93 | }; 94 | ]] 95 | 96 | local ctx_ptr_type = ffi_typeof("HMAC_CTX[1]") 97 | 98 | ctx_new = function () 99 | local ctx = ffi_new(ctx_ptr_type) 100 | C.HMAC_CTX_init(ctx) 101 | return ctx 102 | end 103 | ctx_free = function (ctx) 104 | C.HMAC_CTX_cleanup(ctx) 105 | end 106 | end 107 | 108 | ffi.cdef [[ 109 | int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, const EVP_MD *md, ENGINE *impl); 110 | int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len); 111 | int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len); 112 | 113 | const EVP_MD *EVP_md5(void); 114 | const EVP_MD *EVP_sha1(void); 115 | const EVP_MD *EVP_sha256(void); 116 | const EVP_MD *EVP_sha384(void); 117 | const EVP_MD *EVP_sha512(void); 118 | ]] 119 | 120 | local hashes = { 121 | MD5 = C.EVP_md5(), 122 | SHA1 = C.EVP_sha1(), 123 | SHA256 = C.EVP_sha256(), 124 | SHA384 = C.EVP_sha384(), 125 | SHA512 = C.EVP_sha512() 126 | } 127 | 128 | _M.ALGOS = hashes 129 | 130 | 131 | function _M.new(self, key, hash_algo) 132 | local ctx = ctx_new() 133 | 134 | local _hash_algo = hash_algo or hashes.MD5 135 | 136 | if C.HMAC_Init_ex(ctx, key, #key, _hash_algo, nil) == 0 then 137 | return nil 138 | end 139 | 140 | ffi_gc(ctx, ctx_free) 141 | 142 | return setmetatable({ _ctx = ctx }, mt) 143 | end 144 | 145 | 146 | function _M.update(self, s) 147 | return C.HMAC_Update(self._ctx, s, #s) == 1 148 | end 149 | 150 | 151 | function _M.final(self, s, hex_output) 152 | 153 | if s ~= nil then 154 | if C.HMAC_Update(self._ctx, s, #s) == 0 then 155 | return nil 156 | end 157 | end 158 | 159 | if C.HMAC_Final(self._ctx, buf, res_len) == 1 then 160 | if hex_output == true then 161 | return to_hex(ffi_str(buf, res_len[0])) 162 | end 163 | return ffi_str(buf, res_len[0]) 164 | end 165 | 166 | return nil 167 | end 168 | 169 | 170 | function _M.reset(self) 171 | return C.HMAC_Init_ex(self._ctx, nil, 0, nil, nil) == 1 172 | end 173 | 174 | 175 | return _M 176 | -------------------------------------------------------------------------------- /rockspec/lua-resty-hmac-ffi-0.06-1.rockspec: -------------------------------------------------------------------------------- 1 | package = 'lua-resty-hmac-ffi' 2 | version = '0.06-1' 3 | 4 | source = { 5 | url = 'git://github.com/jkeys089/lua-resty-hmac', 6 | tag = '0.06-1' 7 | } 8 | 9 | description = { 10 | summary = 'HMAC functions for ngx_lua and LuaJIT', 11 | homepage = 'https://github.com/jkeys089/lua-resty-hmac', 12 | license = 'BSD-2-Clause License' 13 | } 14 | 15 | dependencies = { 16 | 'lua == 5.1' 17 | } 18 | 19 | build = { 20 | type = 'builtin', 21 | modules = { 22 | ['resty.hmac'] = 'lib/resty/hmac.lua' 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /t/hmac.t: -------------------------------------------------------------------------------- 1 | # vi:ft= 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(2); 6 | 7 | plan tests => repeat_each() * (3 * blocks()); 8 | 9 | no_long_string(); 10 | 11 | run_tests(); 12 | 13 | __DATA__ 14 | 15 | === TEST 1: Hello HMAC-SHA1 16 | --- http_config eval: $::HttpConfig 17 | --- config 18 | location /t { 19 | content_by_lua ' 20 | local hmac = require "resty.hmac" 21 | local str = require "resty.string" 22 | local hmac_sha1 = hmac:new("secret_key", hmac.ALGOS.SHA1) 23 | ngx.say(hmac_sha1:update("hello")) 24 | local mac = hmac_sha1:final() 25 | ngx.say(mac == ngx.hmac_sha1("secret_key", "hello")) 26 | ngx.say("hmac-sha1: ", str.to_hex(mac)) 27 | '; 28 | } 29 | --- request 30 | GET /t 31 | --- response_body 32 | true 33 | true 34 | hmac-sha1: aee4b890b574ea8fa4f6a66aed96c3e590e5925a 35 | --- no_error_log 36 | [error] 37 | 38 | 39 | 40 | === TEST 2: HMAC-SHA1 incremental 41 | --- http_config eval: $::HttpConfig 42 | --- config 43 | location /t { 44 | content_by_lua ' 45 | local hmac = require "resty.hmac" 46 | local str = require "resty.string" 47 | local hmac_sha1 = hmac:new("test123", hmac.ALGOS.SHA1) 48 | ngx.say(hmac_sha1:update("hel")) 49 | ngx.say(hmac_sha1:update("lo")) 50 | local mac = hmac_sha1:final() 51 | ngx.say("hmac-sha1: ", str.to_hex(mac)) 52 | '; 53 | } 54 | --- request 55 | GET /t 56 | --- response_body 57 | true 58 | true 59 | hmac-sha1: f1e6301275f5929edf0cf6451c6fc4a2b46df5f5 60 | --- no_error_log 61 | [error] 62 | 63 | 64 | 65 | === TEST 3: HMAC-SHA1 empty string 66 | --- http_config eval: $::HttpConfig 67 | --- config 68 | location /t { 69 | content_by_lua ' 70 | local hmac = require "resty.hmac" 71 | local str = require "resty.string" 72 | local hmac_sha1 = hmac:new("not4u", hmac.ALGOS.SHA1) 73 | ngx.say(hmac_sha1:update("")) 74 | local mac = hmac_sha1:final() 75 | ngx.say(mac == ngx.hmac_sha1("not4u", "")) 76 | ngx.say("hmac-sha1: ", str.to_hex(mac)) 77 | '; 78 | } 79 | --- request 80 | GET /t 81 | --- response_body 82 | true 83 | true 84 | hmac-sha1: f97e3c6f613bbe9b39c8d8ffc2b27e2a5c9d7783 85 | --- no_error_log 86 | [error] 87 | 88 | 89 | 90 | === TEST 4: HMAC-SHA1 Short binary output 91 | --- http_config eval: $::HttpConfig 92 | --- config 93 | location /t { 94 | content_by_lua ' 95 | local hmac = require "resty.hmac" 96 | local str = require "resty.string" 97 | local hmac_sha1 = hmac:new("secret_key", hmac.ALGOS.SHA1) 98 | local mac = hmac_sha1:final("hello") 99 | ngx.say(mac == ngx.hmac_sha1("secret_key", "hello")) 100 | ngx.say("hmac-sha1: ", str.to_hex(mac)) 101 | '; 102 | } 103 | --- request 104 | GET /t 105 | --- response_body 106 | true 107 | hmac-sha1: aee4b890b574ea8fa4f6a66aed96c3e590e5925a 108 | --- no_error_log 109 | [error] 110 | 111 | 112 | 113 | === TEST 5: HMAC-SHA1 Short hex output 114 | --- http_config eval: $::HttpConfig 115 | --- config 116 | location /t { 117 | content_by_lua ' 118 | local hmac = require "resty.hmac" 119 | local str = require "resty.string" 120 | local hmac_sha1 = hmac:new("secret_key", hmac.ALGOS.SHA1) 121 | local mac_hex = hmac_sha1:final("hello", true) 122 | ngx.say(mac_hex == str.to_hex(ngx.hmac_sha1("secret_key", "hello"))) 123 | ngx.say("hmac-sha1: ", mac_hex) 124 | '; 125 | } 126 | --- request 127 | GET /t 128 | --- response_body 129 | true 130 | hmac-sha1: aee4b890b574ea8fa4f6a66aed96c3e590e5925a 131 | --- no_error_log 132 | [error] 133 | 134 | 135 | 136 | === TEST 6: HMAC-SHA1 Reset and re-use 137 | --- http_config eval: $::HttpConfig 138 | --- config 139 | location /t { 140 | content_by_lua ' 141 | local hmac = require "resty.hmac" 142 | local str = require "resty.string" 143 | local hmac_sha1 = hmac:new("secret_key", hmac.ALGOS.SHA1) 144 | ngx.say("hmac-sha1: ", hmac_sha1:final("hello", true)) 145 | hmac_sha1:reset() 146 | local reset_hex = hmac_sha1:final("world", true) 147 | ngx.say(reset_hex == str.to_hex(ngx.hmac_sha1("secret_key", "world"))) 148 | ngx.say("hmac-sha1: ", reset_hex) 149 | '; 150 | } 151 | --- request 152 | GET /t 153 | --- response_body 154 | hmac-sha1: aee4b890b574ea8fa4f6a66aed96c3e590e5925a 155 | true 156 | hmac-sha1: 4e9538f1efbe565c522acfb72fce6092ea6b15e0 157 | --- no_error_log 158 | [error] 159 | 160 | 161 | 162 | === TEST 7: Hello HMAC-SHA256 163 | --- http_config eval: $::HttpConfig 164 | --- config 165 | location /t { 166 | content_by_lua ' 167 | local hmac = require "resty.hmac" 168 | local hmac_sha256 = hmac:new("~@!$%^_", hmac.ALGOS.SHA256) 169 | ngx.say(hmac_sha256:update("hello, ")) 170 | ngx.say(hmac_sha256:update("world")) 171 | ngx.say("hmac-sha256: ", hmac_sha256:final("!", true)) 172 | '; 173 | } 174 | --- request 175 | GET /t 176 | --- response_body 177 | true 178 | true 179 | hmac-sha256: a9e4d61409ac1aceaa0fd825df76d664461bbdb93bb6fea65a285cd9240c4a1b 180 | --- no_error_log 181 | [error] 182 | 183 | 184 | 185 | === TEST 8: Hello HMAC-SHA512 186 | --- http_config eval: $::HttpConfig 187 | --- config 188 | location /t { 189 | content_by_lua ' 190 | local hmac = require "resty.hmac" 191 | local hmac_sha512 = hmac:new("小猫", hmac.ALGOS.SHA512) 192 | ngx.say(hmac_sha512:update("小狗")) 193 | ngx.say("hmac-sha512: ", hmac_sha512:final(_, true)) 194 | ngx.say(hmac_sha512:reset()) 195 | ngx.say("hmac-sha512: ", hmac_sha512:final("猴子", true)) 196 | '; 197 | } 198 | --- request 199 | GET /t 200 | --- response_body 201 | true 202 | hmac-sha512: a1f52b55635c9a6a945d6d98183744e16981455010850a4de06509cb91d506b26f1d710120eeea0348933cd0516a7e4d8f6b0f9da1281b2fd9dc8716d5c0ca71 203 | true 204 | hmac-sha512: e0ec96ca2b700643ea62916bb42923f2535dc3894aa30d9654333d51613b7fb48149ce6a01bc7efb257ddcd1994e8e7a71ada5df7fd44b391cf130ce9b53ebf0 205 | --- no_error_log 206 | [error] 207 | 208 | 209 | 210 | === TEST 9: Hello HMAC-MD5 211 | --- http_config eval: $::HttpConfig 212 | --- config 213 | location /t { 214 | content_by_lua ' 215 | local hmac = require "resty.hmac" 216 | local str = require "resty.string" 217 | local hmac_md5 = hmac:new("reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeely long key", hmac.ALGOS.MD5) 218 | ngx.say(hmac_md5:update("hmac ftw!!!")) 219 | local mac = hmac_md5:final() 220 | ngx.say("hmac-md5: ", str.to_hex(mac)) 221 | '; 222 | } 223 | --- request 224 | GET /t 225 | --- response_body 226 | true 227 | hmac-md5: 80f9a1bc99575c2430fe04c982cf5700 228 | --- no_error_log 229 | [error] 230 | 231 | 232 | 233 | === TEST 10: Hello HMAC-MD5 Default 234 | --- http_config eval: $::HttpConfig 235 | --- config 236 | location /t { 237 | content_by_lua ' 238 | local hmac = require "resty.hmac" 239 | local str = require "resty.string" 240 | local hmac_default = hmac:new("reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeely long key") 241 | ngx.say(hmac_default:update("hmac ftw!!!")) 242 | local mac = hmac_default:final() 243 | ngx.say("hmac-default: ", str.to_hex(mac)) 244 | '; 245 | } 246 | --- request 247 | GET /t 248 | --- response_body 249 | true 250 | hmac-default: 80f9a1bc99575c2430fe04c982cf5700 251 | --- no_error_log 252 | [error] -------------------------------------------------------------------------------- /t/version.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | use Cwd qw(cwd); 5 | 6 | repeat_each(2); 7 | 8 | plan tests => repeat_each() * (3 * blocks()); 9 | 10 | $ENV{TEST_NGINX_RESOLVER} = '8.8.8.8'; 11 | 12 | no_long_string(); 13 | #no_diff(); 14 | 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: hmac version 20 | --- http_config eval: $::HttpConfig 21 | --- config 22 | location /t { 23 | content_by_lua ' 24 | local hmac = require "resty.hmac" 25 | ngx.say(hmac._VERSION) 26 | '; 27 | } 28 | --- request 29 | GET /t 30 | --- response_body_like chop 31 | ^\d+\.\d+$ 32 | --- no_error_log 33 | [error] 34 | -------------------------------------------------------------------------------- /valgrind.suppress: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Memcheck:Cond 4 | fun:lj_str_new 5 | obj:* 6 | } 7 | { 8 | 9 | Memcheck:Param 10 | write(buf) 11 | fun:__write_nocancel 12 | fun:ngx_log_error_core 13 | fun:ngx_resolver_read_response 14 | } 15 | { 16 | 17 | Memcheck:Cond 18 | fun:ngx_sprintf_num 19 | fun:ngx_vslprintf 20 | fun:ngx_log_error_core 21 | fun:ngx_resolver_read_response 22 | fun:ngx_epoll_process_events 23 | fun:ngx_process_events_and_timers 24 | fun:ngx_single_process_cycle 25 | fun:main 26 | } 27 | { 28 | 29 | Memcheck:Addr1 30 | fun:ngx_vslprintf 31 | fun:ngx_snprintf 32 | fun:ngx_sock_ntop 33 | fun:ngx_event_accept 34 | } 35 | { 36 | 37 | Memcheck:Param 38 | write(buf) 39 | fun:__write_nocancel 40 | fun:ngx_log_error_core 41 | fun:ngx_resolver_read_response 42 | fun:ngx_event_process_posted 43 | fun:ngx_process_events_and_timers 44 | fun:ngx_single_process_cycle 45 | fun:main 46 | } 47 | { 48 | 49 | Memcheck:Cond 50 | fun:ngx_sprintf_num 51 | fun:ngx_vslprintf 52 | fun:ngx_log_error_core 53 | fun:ngx_resolver_read_response 54 | fun:ngx_event_process_posted 55 | fun:ngx_process_events_and_timers 56 | fun:ngx_single_process_cycle 57 | fun:main 58 | } 59 | { 60 | 61 | exp-sgcheck:SorG 62 | fun:lj_str_new 63 | fun:lua_pushlstring 64 | } 65 | { 66 | 67 | Memcheck:Leak 68 | fun:malloc 69 | fun:ngx_alloc 70 | obj:* 71 | } 72 | { 73 | 74 | exp-sgcheck:SorG 75 | fun:lj_str_new 76 | fun:lua_pushlstring 77 | } 78 | { 79 | 80 | exp-sgcheck:SorG 81 | fun:ngx_http_lua_ndk_set_var_get 82 | } 83 | { 84 | 85 | exp-sgcheck:SorG 86 | fun:lj_str_new 87 | fun:lua_getfield 88 | } 89 | { 90 | 91 | exp-sgcheck:SorG 92 | fun:lj_str_new 93 | fun:lua_setfield 94 | } 95 | { 96 | 97 | exp-sgcheck:SorG 98 | fun:ngx_http_variables_init_vars 99 | fun:ngx_http_block 100 | } 101 | { 102 | 103 | exp-sgcheck:SorG 104 | fun:ngx_conf_parse 105 | } 106 | { 107 | 108 | exp-sgcheck:SorG 109 | fun:ngx_vslprintf 110 | fun:ngx_log_error_core 111 | } 112 | { 113 | 114 | Memcheck:Leak 115 | fun:malloc 116 | fun:ngx_alloc 117 | fun:ngx_calloc 118 | fun:ngx_event_process_init 119 | } 120 | { 121 | 122 | Memcheck:Leak 123 | fun:malloc 124 | fun:ngx_alloc 125 | fun:ngx_malloc 126 | fun:ngx_pcalloc 127 | } 128 | { 129 | 130 | Memcheck:Addr4 131 | fun:lj_str_new 132 | fun:lua_setfield 133 | } 134 | { 135 | 136 | Memcheck:Addr4 137 | fun:lj_str_new 138 | fun:lua_getfield 139 | } 140 | { 141 | 142 | Memcheck:Leak 143 | fun:malloc 144 | fun:ngx_alloc 145 | fun:(below main) 146 | } 147 | { 148 | 149 | Memcheck:Param 150 | epoll_ctl(event) 151 | fun:epoll_ctl 152 | } 153 | { 154 | 155 | Memcheck:Leak 156 | fun:malloc 157 | fun:ngx_alloc 158 | fun:ngx_event_process_init 159 | } 160 | { 161 | 162 | Memcheck:Cond 163 | fun:ngx_conf_flush_files 164 | fun:ngx_single_process_cycle 165 | } 166 | { 167 | 168 | Memcheck:Cond 169 | fun:memcpy 170 | fun:ngx_vslprintf 171 | fun:ngx_log_error_core 172 | fun:ngx_http_charset_header_filter 173 | } 174 | { 175 | 176 | Memcheck:Leak 177 | fun:memalign 178 | fun:posix_memalign 179 | fun:ngx_memalign 180 | fun:ngx_pcalloc 181 | } 182 | { 183 | 184 | Memcheck:Addr4 185 | fun:lj_str_new 186 | fun:lua_pushlstring 187 | } 188 | { 189 | 190 | Memcheck:Cond 191 | fun:lj_str_new 192 | fun:lj_str_fromnum 193 | } 194 | { 195 | 196 | Memcheck:Cond 197 | fun:lj_str_new 198 | fun:lua_pushlstring 199 | } 200 | { 201 | 202 | Memcheck:Addr4 203 | fun:lj_str_new 204 | fun:lua_setfield 205 | fun:ngx_http_lua_cache_store_code 206 | } 207 | { 208 | 209 | Memcheck:Cond 210 | fun:lj_str_new 211 | fun:lua_getfield 212 | fun:ngx_http_lua_cache_load_code 213 | } 214 | { 215 | 216 | Memcheck:Cond 217 | fun:lj_str_new 218 | fun:lua_setfield 219 | fun:ngx_http_lua_cache_store_code 220 | } 221 | { 222 | 223 | Memcheck:Addr4 224 | fun:lj_str_new 225 | fun:lua_getfield 226 | fun:ngx_http_lua_cache_load_code 227 | } 228 | { 229 | 230 | Memcheck:Param 231 | socketcall.setsockopt(optval) 232 | fun:setsockopt 233 | fun:drizzle_state_connect 234 | } 235 | { 236 | 237 | Memcheck:Leak 238 | fun:malloc 239 | fun:ngx_alloc 240 | fun:ngx_palloc_large 241 | } 242 | { 243 | 244 | Memcheck:Leak 245 | fun:malloc 246 | fun:ngx_alloc 247 | fun:ngx_pool_cleanup_add 248 | } 249 | { 250 | 251 | Memcheck:Leak 252 | fun:malloc 253 | fun:ngx_alloc 254 | fun:ngx_pnalloc 255 | } 256 | { 257 | 258 | Memcheck:Cond 259 | fun:ngx_conf_flush_files 260 | fun:ngx_single_process_cycle 261 | fun:main 262 | } 263 | 264 | { 265 | 266 | Memcheck:Leak 267 | fun:malloc 268 | fun:ngx_alloc 269 | fun:ngx_palloc 270 | } 271 | { 272 | 273 | Memcheck:Leak 274 | fun:malloc 275 | fun:ngx_alloc 276 | fun:ngx_pcalloc 277 | } 278 | { 279 | 280 | Memcheck:Leak 281 | fun:malloc 282 | fun:ngx_alloc 283 | fun:ngx_malloc 284 | fun:ngx_palloc_large 285 | } 286 | { 287 | 288 | Memcheck:Leak 289 | fun:malloc 290 | fun:ngx_alloc 291 | fun:ngx_create_pool 292 | } 293 | { 294 | 295 | Memcheck:Leak 296 | fun:malloc 297 | fun:ngx_alloc 298 | fun:ngx_malloc 299 | fun:ngx_palloc 300 | } 301 | { 302 | 303 | Memcheck:Leak 304 | fun:malloc 305 | fun:ngx_alloc 306 | fun:ngx_malloc 307 | fun:ngx_pnalloc 308 | } 309 | 310 | { 311 | 312 | Memcheck:Leak 313 | fun:malloc 314 | fun:ngx_alloc 315 | fun:ngx_palloc_large 316 | fun:ngx_palloc 317 | fun:ngx_array_push 318 | fun:ngx_http_get_variable_index 319 | fun:ngx_http_memc_add_variable 320 | fun:ngx_http_memc_init 321 | fun:ngx_http_block 322 | fun:ngx_conf_parse 323 | fun:ngx_init_cycle 324 | fun:main 325 | } 326 | 327 | { 328 | 329 | Memcheck:Leak 330 | fun:malloc 331 | fun:ngx_alloc 332 | fun:ngx_event_process_init 333 | fun:ngx_single_process_cycle 334 | fun:main 335 | } 336 | { 337 | 338 | Memcheck:Leak 339 | fun:malloc 340 | fun:ngx_alloc 341 | fun:ngx_crc32_table_init 342 | fun:main 343 | } 344 | { 345 | 346 | Memcheck:Leak 347 | fun:malloc 348 | fun:ngx_alloc 349 | fun:ngx_event_process_init 350 | fun:ngx_worker_process_init 351 | fun:ngx_worker_process_cycle 352 | fun:ngx_spawn_process 353 | fun:ngx_start_worker_processes 354 | fun:ngx_master_process_cycle 355 | fun:main 356 | } 357 | { 358 | 359 | Memcheck:Leak 360 | fun:malloc 361 | fun:ngx_alloc 362 | fun:ngx_palloc_large 363 | fun:ngx_palloc 364 | fun:ngx_pcalloc 365 | fun:ngx_hash_init 366 | fun:ngx_http_variables_init_vars 367 | fun:ngx_http_block 368 | fun:ngx_conf_parse 369 | fun:ngx_init_cycle 370 | fun:main 371 | } 372 | { 373 | 374 | Memcheck:Leak 375 | fun:malloc 376 | fun:ngx_alloc 377 | fun:ngx_palloc_large 378 | fun:ngx_palloc 379 | fun:ngx_pcalloc 380 | fun:ngx_http_upstream_drizzle_create_srv_conf 381 | fun:ngx_http_upstream 382 | fun:ngx_conf_parse 383 | fun:ngx_http_block 384 | fun:ngx_conf_parse 385 | fun:ngx_init_cycle 386 | fun:main 387 | } 388 | { 389 | 390 | Memcheck:Leak 391 | fun:malloc 392 | fun:ngx_alloc 393 | fun:ngx_palloc_large 394 | fun:ngx_palloc 395 | fun:ngx_pcalloc 396 | fun:ngx_hash_keys_array_init 397 | fun:ngx_http_variables_add_core_vars 398 | fun:ngx_http_core_preconfiguration 399 | fun:ngx_http_block 400 | fun:ngx_conf_parse 401 | fun:ngx_init_cycle 402 | fun:main 403 | } 404 | { 405 | 406 | Memcheck:Leak 407 | fun:malloc 408 | fun:ngx_alloc 409 | fun:ngx_palloc_large 410 | fun:ngx_palloc 411 | fun:ngx_array_push 412 | fun:ngx_hash_add_key 413 | fun:ngx_http_add_variable 414 | fun:ngx_http_echo_add_variables 415 | fun:ngx_http_echo_handler_init 416 | fun:ngx_http_block 417 | fun:ngx_conf_parse 418 | fun:ngx_init_cycle 419 | } 420 | { 421 | 422 | Memcheck:Leak 423 | fun:malloc 424 | fun:ngx_alloc 425 | fun:ngx_palloc_large 426 | fun:ngx_palloc 427 | fun:ngx_pcalloc 428 | fun:ngx_http_upstream_drizzle_create_srv_conf 429 | fun:ngx_http_core_server 430 | fun:ngx_conf_parse 431 | fun:ngx_http_block 432 | fun:ngx_conf_parse 433 | fun:ngx_init_cycle 434 | fun:main 435 | } 436 | { 437 | 438 | Memcheck:Leak 439 | fun:malloc 440 | fun:ngx_alloc 441 | fun:ngx_palloc_large 442 | fun:ngx_palloc 443 | fun:ngx_pcalloc 444 | fun:ngx_http_upstream_drizzle_create_srv_conf 445 | fun:ngx_http_block 446 | fun:ngx_conf_parse 447 | fun:ngx_init_cycle 448 | fun:main 449 | } 450 | { 451 | 452 | Memcheck:Leak 453 | fun:malloc 454 | fun:ngx_alloc 455 | fun:ngx_palloc_large 456 | fun:ngx_palloc 457 | fun:ngx_array_push 458 | fun:ngx_hash_add_key 459 | fun:ngx_http_variables_add_core_vars 460 | fun:ngx_http_core_preconfiguration 461 | fun:ngx_http_block 462 | fun:ngx_conf_parse 463 | fun:ngx_init_cycle 464 | fun:main 465 | } 466 | { 467 | 468 | Memcheck:Leak 469 | fun:malloc 470 | fun:ngx_alloc 471 | fun:ngx_palloc_large 472 | fun:ngx_palloc 473 | fun:ngx_pcalloc 474 | fun:ngx_init_cycle 475 | fun:main 476 | } 477 | { 478 | 479 | Memcheck:Leak 480 | fun:malloc 481 | fun:ngx_alloc 482 | fun:ngx_palloc_large 483 | fun:ngx_palloc 484 | fun:ngx_hash_init 485 | fun:ngx_http_upstream_init_main_conf 486 | fun:ngx_http_block 487 | fun:ngx_conf_parse 488 | fun:ngx_init_cycle 489 | fun:main 490 | } 491 | { 492 | 493 | Memcheck:Leak 494 | fun:malloc 495 | fun:ngx_alloc 496 | fun:ngx_palloc_large 497 | fun:ngx_palloc 498 | fun:ngx_pcalloc 499 | fun:ngx_http_drizzle_keepalive_init 500 | fun:ngx_http_upstream_drizzle_init 501 | fun:ngx_http_upstream_init_main_conf 502 | fun:ngx_http_block 503 | fun:ngx_conf_parse 504 | fun:ngx_init_cycle 505 | fun:main 506 | } 507 | { 508 | 509 | Memcheck:Leak 510 | fun:malloc 511 | fun:ngx_alloc 512 | fun:ngx_palloc_large 513 | fun:ngx_palloc 514 | fun:ngx_hash_init 515 | fun:ngx_http_variables_init_vars 516 | fun:ngx_http_block 517 | fun:ngx_conf_parse 518 | fun:ngx_init_cycle 519 | fun:main 520 | } 521 | { 522 | 523 | Memcheck:Leak 524 | fun:memalign 525 | fun:posix_memalign 526 | fun:ngx_memalign 527 | fun:ngx_create_pool 528 | } 529 | { 530 | 531 | Memcheck:Leak 532 | fun:memalign 533 | fun:posix_memalign 534 | fun:ngx_memalign 535 | fun:ngx_palloc_block 536 | fun:ngx_palloc 537 | } 538 | { 539 | 540 | Memcheck:Cond 541 | fun:index 542 | fun:expand_dynamic_string_token 543 | fun:_dl_map_object 544 | fun:map_doit 545 | fun:_dl_catch_error 546 | fun:do_preload 547 | fun:dl_main 548 | fun:_dl_sysdep_start 549 | fun:_dl_start 550 | } 551 | --------------------------------------------------------------------------------