PBKDF2-in-Openresty.md

PBKDF2最常见的用途是用来加密用户的密码.
在lua中并没有原生的加密库, openresty中也没有提供较好的keyhash功能或者库, 我们只好自己手动去包装一个.
我们可以借助luajit的FFI模块我们可以快速将动态库包装成lua模块使用.

gun/nettle是一个加密库,下面是他的介绍:

Nettle is a cryptographic library that is designed to fit easily in more or less 
any context: In crypto toolkits for object-oriented languages (C++, Python, Pike, ...), 
in applications like LSH or GNUPG, or even in kernel space.

nettle中提供了很多常用的hash,cipher,key_hash函数. 详细列表见nettle文档: http://www.lysator.liu.se/~nisse/nettle/nettle.html

这里是一个将libnettle包装成模块使用的例子:
首先安装gnu/nettle. 可以直接在 http://ftp.gnu.org/gnu/nettle/ 下载. 然后执行./configure 并 make 就可以了.
然后将编译出来的libnettle.so放在你需要的位置,并且将下文中libnettle.so的位置改成放置位置.
编译过程需要m4, 如果没有的话 make 会报错.

接下来是lua模块:

--[[
 
    pbkdf2.lua
    
    @version    160818:1
    @author     karminski <>

    @changelogs
                160818:1 INIT version.

]]--

local ffi     = require "ffi"
local ffi_new = ffi.new
local ffi_str = ffi.string
local C       = ffi.C

local _M = { _VERSION = '0.0.1' }

ffi.cdef[[
void nettle_pbkdf2_hmac_sha1(size_t key_length, const uint8_t *key, unsigned iterations, size_t salt_length, const uint8_t *salt, size_t length, uint8_t *dst);
void nettle_pbkdf2_hmac_sha256(size_t key_length, const uint8_t *key, unsigned iterations, size_t salt_length, const uint8_t *salt, size_t length, uint8_t *dst);
]]

local nettle = ffi.load("/lib/libnettle.so") -- change this path when needed.
local uint8t = ffi.typeof("uint8_t[?]")


-- hmac_sha1()
-- @param    string key
-- @param    number iterations
-- @param    string salt
-- @param    number len
-- @return   string sha1
function _M.hmac_sha1(key, iterations, salt, len)
    local buf = ffi_new(uint8t, len)
    nettle.nettle_pbkdf2_hmac_sha1(#key, key, iterations, #salt, salt, len, buf)
    return ffi_str(buf, len)
end

-- hmac_sha256()
-- @param    string key
-- @param    number iterations
-- @param    string salt
-- @param    number len
-- @return   string sha256
function _M.hmac_sha256(key, iterations, salt, len)
    local buf = ffi_new(uint8t, len)
    nettle.nettle_pbkdf2_hmac_sha256(#key, key, iterations, #salt, salt, len, buf)
    return ffi_str(buf, len)
end


return _M

需要注意的是, 在编写依赖ffi的lua模块时,一定要将 require "ffi" 以及 ffi.load 放在代码最底层, 否则会出现table overflow的情况.
另外可以直接使用这个项目, 该项目直接将nettle的所有函数全部包装了: https://github.com/bungle/lua-resty-nettle/

以上.