因为在写 Kong 的自定义插件,要用 Lua 实现 AES-ECB 加解密,网上搜了很久,也有一些相关的库,但都太复杂了,要么依赖 OpenSSL 要么依赖 LuaJIT 2.0 或者要使用 luarocks 进行安装,因为我的自定义 Kong 镜像就打了个简单的 OpenResty 镜像进去,不想在额外打镜像进去,会导致镜像太大,同时这些库,个人觉得不是很好理解,尤其是因为写自定义插件,第一次接触 Lua 的我来说,作为一个前 PHPer,于是参照 PHP 的 mcrypt 库,利用 luajit 的 ffi 实现了一个 AES 加解密库。
先上地址(代码写的可能不是很好,见谅(ノ ̄▽ ̄))
https://github.com/Lyafei/lua-aes
首先你需要在你的操作系统中安装 libmcrypt
的库,参照 CentOS下php安装mcrypt扩展 中安装 mcrypt 的方法
如果是在容器中,可以在你的 Dockefile 中加入
RUN yum install -y epel-release
RUN yum install -y libmcrypt libmcrypt-devel
如果用 PHP 加解密:
mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,$text, MCRYPT_MODE_ECB );
mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key,$text, MCRYPT_MODE_ECB );
如果用 Lua 加解密:
local aes = require("resty.aes_ecb")
local data = 'lyafei'
local key = '12345678912345678912345678912345' --length is 32
local ecb = aes:new();
local enc_data = ecb:encrypt(key,data )
local dec_data = ecb:decrypt(key,enc_data )
为什么要使用 MCRYPT_RIJNDAEL_128
模式,因为官方给出的解释是:
所以这里使用的是
MCRYPT_RIJNDAEL_128
而不是 MCRYPT_RIJNDAEL_256
为什么 key 是32位呢?
MCRYPT_RIJNDAEL_128 & MCRYPT_MODE_ECB + 16位Key = openssl_encrypt(AES-128-ECB, 16位Key) = AES-128
MCRYPT_RIJNDAEL_128 & MCRYPT_MODE_ECB + 24位Key = openssl_encrypt(AES-192-ECB, 24位Key) = AES-192
MCRYPT_RIJNDAEL_128 & MCRYPT_MODE_ECB + 32位Key = openssl_encrypt(AES-256-ECB, 32位Key) = AES-256
从上对应关系可以看出,16位key对应AES-128、24位key对应AES-192、32位key对应AES-256。
需要注意,数据在加密后是二进制数据,这时候就要加密后要 base64 加密一下,解密前要 base64 解密下,base64 加解密算法参考下面文章
local enc_data = enc(ecb:encrypt(key,data ))
local dec_data = ecb:decrypt(key,dec(enc_data) )
因为默认是有 padding 模式的,所以在数据后面会自动填充 \u0000
,所以解密之后会出现 dec_data = 'lyafei���������'
这个时候就需要去除类似于 \u0000
的填充。
local function Strip_Control_and_Extended_Codes( str )
local s = ""
for i = 1, str:len() do
if str:byte(i) >= 32 and str:byte(i) <= 126 then
s = s .. str:sub(i,i)
end
end
return s
end
dec_data = Strip_Control_and_Extended_Codes(dec_data)
dec_data = 'lyafei'
详细可以参考:https://rosettacode.org/wiki/Strip_control_codes_and_extended_characters_from_a_string
2020-06-16
上面 Strip_Control_and_Extended_Codes
方法虽然将不可见字符过滤掉了,但同时还会过滤到中文,所以方法进行修改
local function Strip_Control_and_Extended_Codes( str )
local s = ""
local index = 1
for uchar in string.gmatch(str, "([%z\32-\127\194-\244][\128-\191]*)") do
s = s..uchar
index = index + 1
end
return s
end