1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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
|