烦恼一般都是想太多了。

0%

OpenSSL的Lua绑定与使用

OpenSSL 提供的 API 还是比较复杂,不过还好有人做了一个 Lua 的绑定。https://github.com/zhaozg/lua-openssl,同时对一些 C 的 API 进行了封装,用起来就简单多了。

安装

Linux

安装官方的说明,如下即可:

git clone --recurse https://github.com/zhaozg/lua-openssl.git lua-openssl
cd lua-openssl
make
make install
make clean

不过我在安装的过程中,会遇到几个问题,我在 Ubuntu 下,用 apt 安装了 Lua/OpenSSL 均找不到相关的头文件。

而我采用两者源代码编译后进行安装,可以在 /usr/local 下找到对应的库文件和头文件就可以使用了。

MacOS

brew install openssl lua

在编译过程中,会查找 Lua 命令的存在,查找对应的库。

而对于 OpenSSL 需要执行以下命令:

export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig"

这样直接 make 就可以安装了。

使用

因为我只要涉及到使用 RSA 的密钥和,所以只展示这里的用法。

首先使用 openssl 命令生成一个 RSA 的密钥。

openssl genrsa -out rsa-openssl.pem 2048

这样生成的是一个私钥(实际私钥中可以提取出公钥信息),这是一个 pem 格式的 RSA 密钥文件:

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAoCYVdJFC9XYtCyd6kzr5yn1+rhPEtqIdV4KKnRYAVN53dZ2g
WYKoHCc9AYXJQqNRmLCvyE6ZEGly4vLUxgcJgv2avE6/YyDkgzoGzHIAGhnuIt1a
tVI96amLNtYcecThN0HPePdHeWbpS4LwlgIjaTADHem2LfmwY1Dtrwsmla3WwM6P
948hJRih+189p80OpkEQ86h61yB4rY9QYwJaZbaLFdiAV6Ln4woIHi+1OY7BQify
t874QZCac/2Nz2DjWlUqbg5jPt7tCL5/aTWfyL1GHWBMs7x8BnYHp1w9RVnTsDpe
oEZdRx8NP+WhQV/ddmXQUVFr6i3YJk4SgttupwIDAQABAoIBAG5kMg/q/aPjtQLm
ULjiQ0MQJF1sJQHbV6x1wIStoMbfnqrFX72zsZvOdF/zT5sOpvVAfbruatYESfwk
dQSX3zebBqldAtIa30mRmxQcVPOpAhyoRpmMOj8x7lN7XZ+WVcRYKeJxWaRWiuPR
O3O7v5sHTG63Jiwk3DBpnZ02a39qgODTThRjmb8F8JUr9sEco9F7eg95jU4sQXWg
t1JXVo0qgm6ALEA0RRO9tSatTDCFkN2tgvJ4Td0COe+MHtlHvE+mzdj3yLMUZRAL
WKZb7zOT0S6qqMfEZEDuE6v4ZLFjKZBaqQENGhczBmJt5P9ZxSOSH9X0Y3jQ3bF8
DmjhImECgYEAzFCI4Vwky7aQgjG5f4xGBQGxzM9cFV4SrioBHbRQz2A48cx54le0
YOC2ldZLanrwebjlAaT9ZfskZS2mfMxEMwnFyJ2enLLDqDPGXO9giM2T36VFihhk
4pIbpsx81d8dcptOprAKUPyF6AM2/PkNKSL1LTaoapQblWvf8Hih5vECgYEAyKlb
6HHYXEvkXaEgWGjn9sEnI+/2KkdLtYwVRIV1MRMHRBARknRH1Ga1tF2PK8PT1x8Y
uFkzEsZbZRZXcC9FQR4XKDHolsyWzjAvrtEwcpPCMmqYfPKMYtMBLEtu1uhAUWYL
0EMeCRrcKfu4tCGdNw121wvKAazRTHTMH7vgnxcCgYA9/HT6wkTblSDUjxdzLfCU
VkZGF+cdCHRsaIv8IheeQtgj6+BSnj84YRSj8ubggDnzA/heflrulLofBDGNjT9n
qKBb1A4qBkY8ArE8wtcrygsCABdP5US+RIulGEcLb+x0N9At3BzVIzfRAyCssTaf
814lAH8qDpMryxWe1EpyUQKBgChAIJl9zKKm7oYBfhV95ZnPoORKjBxq9LrUAKgg
BSP05y418vBntsjaWXR2l/N1cpbiO/kum1oWw9qBIsT0FnY7bPW5HSiynUV60PXG
LGuvS/MFAtV9ab+hB8k00GT3bX9mctQxwmKdKrCZN7GaVIjogIAec0Tmv40QmKl8
7E+9AoGAeG9MsNzouEceokO8pRIvrVPvjSVEE+oGdPw9AXqxzV0b1NFlMuCYReqN
LdkcJH8lIKopnOU+uXGm3h2PswSf1W9NcnDGDN11G0bjgpS/ghrS+Ewi+qApKeNe
BIs5ELvpl+5fqcyvsvm9ZDTMe94VRUMnyMTWNPviDjGtpL7JGns=
-----END RSA PRIVATE KEY-----

读取

读取使用的是 Lua 绑定中的 openssl.pkey 来进行读取的,它的 API 在里。不过,它不能读取文件,只能读取字符串,所以我们要使用 Lua 自己的 IO 库来读取成为字符进行读取:

read (input[, priv=false[, format='auto'[, passhprase]]])

三个参数方便是:输入(字符串或者 BIO 对象)、是否私钥、格式(der,pem)、密码。

local pkey  = require 'openssl'.pkey
local file = io.open('./rsa-openssl.pem','r'):read('*a')

-- 读取后的密钥对象,读取后返回的是一个 pkey 对象
local key = pkey.read(file, true)
local params = key:parse()
for k, v in pairs(params) do print(k, v) end

输出:

type	rsa
rsa openssl.rsa: 0x7fb558d00948
bits 2048
size 256

接下来我们解析和 RSA 相关的参数,比如:n, e, p, q, d 等。

local rsa = key:parse().rsa
local rsa_params = rsa:parse()
for k, v in pairs(rsa_params) do print(k, v) end

输出:

p	143474583331419867830562744660438510286015562299102553985627632512512583822740177904056516815190873109230049903987915310389156124434466941185638919163185903601523390513344140836690989199412995255185487799294977031490478168007553781534162882533049402556998644029553047215723632060092994322355253408945202652913
q 140909338446924385769069804035851642429757637984920583137521396992286965747594955575490977795105115601880479171874275162381208540904328052730351954850972035633266069196024154417733083506255498864594785158535609304132452167552279233260937451257639704420206214670926065473953266618923458962324893693514839269143
n 20216908621178498204920137811341508388900484323393782530910996775497866613781744423255159400952471020143706423402858610017877944319356867483294568447383341717624035601428904173159314521244110931670984951774144939173254872362257039974231171172944322722321006625420197699875532838548699813278176103570786084219789033309162245722957052130238378463144025402561390577240433224866889133637304672114032432176736213365428175753805911558486773599252789881671688951163343771673506382049610885317695581908726556103268585116032473028770304372464218227585670524797638956188402540501508797897253106491558592312209210070753619963559
d 13935621816099892524944187644038522383822564037250928877335005864368465512269257126822280939591801247157970881749609193395450449892838343051372997384844324001612307678022349909554481186157479154343908711054778180678880462318460744019956561297248268596073233048558179823487147656765453317436587049739998189642738034027725830429806390734946119587768684761857882937993779293002157513469114376730897921091352017162195396320797528114610659224400944795373051263182850450591559530749354700491452010745809969179304583696946308670871913913013345163614660548678440566979200379562102568461361600133231474290379868159858742207073
e 65537
size 256
bits 2048
dmp1 43528161807507533638632818897470114592014395306362147808050936375578493128271708458830213830911395548023575724262503930855357908084448573959657271918483075534569625914778240570302683037855388325050781297791812690802526472290373252334463899681166688604006958500383039165513114366706272885719357058303820198481
iqmp 84572167331770707180976675336691177811651921878501742590348918966472216855434936147554743962831318290039939947146211490896065085877354521089720045770790645669113891846273623657936024439340654182981811057834667458160772923788214342319848078936037805610273259192846464333122568255165940096509982299062524254843
dmq1 28264860509685642847859859985280157641967040129236400597004078381076406483633417550321259656292656815269554285265715874767892449741799236785223717876480131535390935588307880036857334265731339366677801023759237070847387219351545887063006908070752880881151576942246273963113808123233712124734471405388499275709

这样我们就拿到了私钥相关的的信息了。

公钥提取

我们可以在 pkey 返回的 key 中提取公钥,这也是一个 pkey 对象。

然后我们还可以将其导出为 PEM 字符串:

local public = key:get_public():export()
print(public)

输出:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoCYVdJFC9XYtCyd6kzr5
yn1+rhPEtqIdV4KKnRYAVN53dZ2gWYKoHCc9AYXJQqNRmLCvyE6ZEGly4vLUxgcJ
gv2avE6/YyDkgzoGzHIAGhnuIt1atVI96amLNtYcecThN0HPePdHeWbpS4LwlgIj
aTADHem2LfmwY1Dtrwsmla3WwM6P948hJRih+189p80OpkEQ86h61yB4rY9QYwJa
ZbaLFdiAV6Ln4woIHi+1OY7BQifyt874QZCac/2Nz2DjWlUqbg5jPt7tCL5/aTWf
yL1GHWBMs7x8BnYHp1w9RVnTsDpeoEZdRx8NP+WhQV/ddmXQUVFr6i3YJk4Sgttu
pwIDAQAB
-----END PUBLIC KEY-----