因为在写 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
最后修改:2020 年 07 月 03 日 05 : 00 PM
如果觉得我的文章对你有用,请随意赞赏