Skip to content

Commit 88e92ae

Browse files
committed
Fixed secure random example in README synopsis; Added AES encryption of simple strings
1 parent 5b3ffa7 commit 88e92ae

File tree

1 file changed

+193
-0
lines changed

1 file changed

+193
-0
lines changed

lib/resty/aes.lua

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
module("resty.aes", package.seeall)
2+
3+
_VERSION = '0.05'
4+
5+
--local asn1 = require "resty.asn1"
6+
local ffi = require "ffi"
7+
local ffi_new = ffi.new
8+
local ffi_gc = ffi.gc
9+
local ffi_str = ffi.string
10+
local C = ffi.C
11+
12+
local mt = { __index = resty.aes }
13+
14+
ffi.cdef[[
15+
typedef struct engine_st ENGINE;
16+
17+
typedef struct evp_cipher_st EVP_CIPHER;
18+
typedef struct evp_cipher_ctx_st
19+
{
20+
const EVP_CIPHER *cipher;
21+
ENGINE *engine;
22+
int encrypt;
23+
int buf_len;
24+
25+
unsigned char oiv[16];
26+
unsigned char iv[16];
27+
unsigned char buf[32];
28+
int num;
29+
30+
void *app_data;
31+
int key_len;
32+
unsigned long flags;
33+
void *cipher_data;
34+
int final_used;
35+
int block_mask;
36+
unsigned char final[32];
37+
} EVP_CIPHER_CTX;
38+
39+
typedef struct env_md_ctx_st EVP_MD_CTX;
40+
typedef struct env_md_st EVP_MD;
41+
42+
const EVP_MD *EVP_md5(void);
43+
const EVP_MD *EVP_sha(void);
44+
const EVP_MD *EVP_sha1(void);
45+
const EVP_MD *EVP_sha224(void);
46+
const EVP_MD *EVP_sha256(void);
47+
const EVP_MD *EVP_sha384(void);
48+
const EVP_MD *EVP_sha512(void);
49+
50+
const EVP_CIPHER *EVP_aes_128_ecb(void);
51+
const EVP_CIPHER *EVP_aes_128_cbc(void);
52+
const EVP_CIPHER *EVP_aes_128_cfb1(void);
53+
const EVP_CIPHER *EVP_aes_128_cfb8(void);
54+
const EVP_CIPHER *EVP_aes_128_cfb128(void);
55+
const EVP_CIPHER *EVP_aes_128_ofb(void);
56+
const EVP_CIPHER *EVP_aes_128_ctr(void);
57+
const EVP_CIPHER *EVP_aes_192_ecb(void);
58+
const EVP_CIPHER *EVP_aes_192_cbc(void);
59+
const EVP_CIPHER *EVP_aes_192_cfb1(void);
60+
const EVP_CIPHER *EVP_aes_192_cfb8(void);
61+
const EVP_CIPHER *EVP_aes_192_cfb128(void);
62+
const EVP_CIPHER *EVP_aes_192_ofb(void);
63+
const EVP_CIPHER *EVP_aes_192_ctr(void);
64+
const EVP_CIPHER *EVP_aes_256_ecb(void);
65+
const EVP_CIPHER *EVP_aes_256_cbc(void);
66+
const EVP_CIPHER *EVP_aes_256_cfb1(void);
67+
const EVP_CIPHER *EVP_aes_256_cfb8(void);
68+
const EVP_CIPHER *EVP_aes_256_cfb128(void);
69+
const EVP_CIPHER *EVP_aes_256_ofb(void);
70+
71+
void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a);
72+
int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a);
73+
void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a);
74+
75+
int EVP_EncryptInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv);
76+
int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl, unsigned char *key, const unsigned char *iv);
77+
int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
78+
int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
79+
int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
80+
81+
int EVP_DecryptInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, unsigned char *key, const unsigned char *iv);
82+
int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl, unsigned char *key, const unsigned char *iv);
83+
int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
84+
int EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
85+
int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
86+
87+
int EVP_BytesToKey(const EVP_CIPHER *type,const EVP_MD *md, const unsigned char *salt, const unsigned char *data, int datal, int count, unsigned char *key,unsigned char *iv);
88+
]]
89+
90+
local ctx_ptr_type = ffi.typeof("EVP_CIPHER_CTX[1]")
91+
92+
hash = {md5 = C.EVP_md5(),
93+
sha1 = C.EVP_sha1(),
94+
sha224 = C.EVP_sha224(),
95+
sha256 = C.EVP_sha256(),
96+
sha384 = C.EVP_sha512()
97+
}
98+
99+
function cipher(size, _cipher)
100+
local _size = size or 128
101+
local _cipher = _cipher or "cbc"
102+
local func = "EVP_aes_" .. _size .. "_" .. _cipher
103+
if C[func] then
104+
return { size=_size, cipher=_cipher, method=C[func]()}
105+
else
106+
return nil
107+
end
108+
end
109+
110+
function new(self, key, salt, _cipher, _hash, hash_rounds)
111+
local encrypt_ctx = ffi_new(ctx_ptr_type)
112+
local decrypt_ctx = ffi_new(ctx_ptr_type)
113+
local _cipher = _cipher or cipher()
114+
local _hash = _hash or hash.sha1
115+
local hash_rounds = hash_rounds or 5
116+
local _cipherLength = _cipher.size/8
117+
local gen_key = ffi_new("unsigned char[?]",_cipherLength)
118+
local gen_iv = ffi_new("unsigned char[?]",_cipherLength)
119+
120+
if C.EVP_BytesToKey(_cipher.method, _hash, salt, key, #key,
121+
hash_rounds, gen_key, gen_iv) ~= _cipherLength then
122+
return nil
123+
end
124+
125+
C.EVP_CIPHER_CTX_init(encrypt_ctx)
126+
C.EVP_CIPHER_CTX_init(decrypt_ctx)
127+
128+
if C.EVP_EncryptInit_ex(encrypt_ctx, _cipher.method, nil,
129+
gen_key, gen_iv) == 0 or
130+
C.EVP_DecryptInit_ex(decrypt_ctx, _cipher.method, nil,
131+
gen_key, gen_iv) == 0 then
132+
return nil
133+
end
134+
135+
ffi_gc(encrypt_ctx, C.EVP_CIPHER_CTX_cleanup)
136+
ffi_gc(decrypt_ctx, C.EVP_CIPHER_CTX_cleanup)
137+
138+
return setmetatable({
139+
_encrypt_ctx = encrypt_ctx,
140+
_decrypt_ctx = decrypt_ctx
141+
}, mt)
142+
end
143+
144+
function encrypt(self, s)
145+
local s_len = #s
146+
local max_len = s_len + 16
147+
local buf = ffi_new("unsigned char[?]", max_len)
148+
local out_len = ffi_new("int[1]")
149+
local tmp_len = ffi_new("int[1]")
150+
local ctx = self._encrypt_ctx
151+
152+
if C.EVP_EncryptInit_ex(ctx, nil, nil, nil, nil) == 0 then
153+
return nil
154+
end
155+
156+
if C.EVP_EncryptUpdate(ctx, buf, out_len, s, s_len) == 0 then
157+
return nil
158+
end
159+
160+
if C.EVP_EncryptFinal_ex(ctx, buf + out_len[0], tmp_len) == 0 then
161+
return nil
162+
end
163+
164+
return ffi_str(buf, out_len[0] + tmp_len[0])
165+
end
166+
167+
function decrypt(self, s)
168+
local s_len = #s
169+
local buf = ffi_new("unsigned char[?]", s_len)
170+
local out_len = ffi_new("int[1]")
171+
local tmp_len = ffi_new("int[1]")
172+
local ctx = self._decrypt_ctx
173+
174+
if C.EVP_DecryptInit_ex(ctx, nil, nil, nil, nil) == 0 then
175+
return nil
176+
end
177+
178+
if C.EVP_DecryptUpdate(ctx, buf, out_len, s, s_len) == 0 then
179+
return nil
180+
end
181+
182+
if C.EVP_DecryptFinal_ex(ctx, buf + out_len[0], tmp_len) == 0 then
183+
return nil
184+
end
185+
186+
return ffi_str(buf, out_len[0] + tmp_len[0])
187+
end
188+
189+
-- to prevent use of casual module global variables
190+
getmetatable(resty.aes).__newindex = function (table, key, val)
191+
error('attempt to write to undeclared variable "' .. key .. '": '
192+
.. debug.traceback())
193+
end

0 commit comments

Comments
 (0)