最近需要在openresty内对客户端上传的一段des加密数据做解密,于是搜到了lua-resty-nettle这个库。
下面记录一下关键概念和lua-resty-nettle用法。
关键概念
块
DES加密是逐块进行的,据我了解常见的都是8字节一块。
密钥
DES是对称加密,其密钥要求长度为8个字节,等于一个块的大小。
加密模式
支持多种加密模式,很常听见这些名词:ECB,CBC,CTR,OFB,CFB。
常用的是ECB和CBC。
初始化向量
英文叫做iv,第二个字母就是vector。
只有ECB不需要iv,其他加密模式要求传8字节(一个块的大小)的iv一起参与编码,起到进一步混淆加密结果的作用。
按道理iv每次加密随机生成是最好的,加密端可以将iv暴露出去,以便解密端可以基于相同的iv完成解密。
padding补齐
des要求待加密的数据也是按块大小对齐的,一般就是8字节。
当数据不够长时,加密端算法会自动补齐,当然也可以调用方主动补齐后再加密。
内置的标准补齐算法有几种:’pkcs5′,’pkcs7′,’iso10126′,’ansix923′,’zero’ 。
常见的是pkcs5,pkcs7,zero,无论它们原理是什么,目标都是补齐到8字节对齐。
加密端和解密端必须按相同的补齐算法计算,否则就会发现数据不一样。
用法
这个库只能在LuaJIT下工作,适用于openresty。
加密
可以通过在线DES加密网站,对一个内容做加密计算:http://tool.chacuo.net/cryptdes。
lua解密
解密需要引入2个模块:
- des模块:负责解密工作
- padding:负责对解密后的字符串擦除padding补齐用途的字节
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 |
local pkcs7 = require "resty.nettle.padding.pkcs7" local des = require "resty.nettle.des" function hexToBin(hex, spacer) if spacer == nil then spacer = "" end local h2b = { ["0"] = 0, ["1"] = 1, ["2"] = 2, ["3"] = 3, ["4"] = 4, ["5"] = 5, ["6"] = 6, ["7"] = 7, ["8"] = 8, ["9"] = 9, ["A"] = 10, ["B"] = 11, ["C"] = 12, ["D"] = 13, ["E"] = 14, ["F"] = 15, ["a"] = 10, ["b"] = 11, ["c"] = 12, ["d"] = 13, ["e"] = 14, ["f"] = 15, } return (string.gsub(hex, "(.)(.)"..spacer, function (h, l) return string.char(h2b[h]*16+h2b[l]) end)) end local ds, wk = des.new("Zmge53Xe", "ecb") local plain = pkcs7.unpad(ds:decrypt(hexToBin("1fabbb0ee09c2e4f57d95510e21b909bb8e91d850004d615")), 8) print(plain) |
首先通过des.new函数创建des加密器:
- 第一个参数:8字节的密钥(与加密算法的块大小一致)
- 第二个参数:加密模式,我选择ecb,不需要传iv
- 第三个参数:iv,初始化向量,8字节
然后通过ds:decrypt可以完成des解密,解密后的字符串末尾可能有补齐字节,所以使用pkcs7算法删除补齐的字节,得到原始字符串。
注意,我和客户端协商的就是使用pkcs7算法,如果是其他算法需要使用其他的padding类进行unpad。
参考资料
https://github.com/bungle/lua-resty-nettle/issues/6
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~

初始向量和偏移向量是一个意思吗
是一个意思,就是指iv。