最近在項(xiàng)目中用到OpenResty做服務(wù)端的接口糖荒,其中接口認(rèn)證方面又用到了RSA算法進(jìn)行加解密。但是目前OpenResty并沒有官方的rsa模塊寂嘉,只有doujiang24前輩提供的lua-resty-rsa庫(kù)泉孩,但是該庫(kù)只支持公鑰加密私鑰解密寓搬,對(duì)私鑰加密公鑰解密卻不支持,為了完善這一方面的缺陷句喷,開發(fā)了自己的rsa加解密庫(kù)唾琼。
因?yàn)閘ua相關(guān)的RSA加解密庫(kù)比較少锡溯,而C和C++相關(guān)的RSA加解密庫(kù)卻比較多哑姚,因此萌生了通過LuaJit的FFI 拓展庫(kù)來調(diào)用C或C++實(shí)現(xiàn)來封裝成Lua 的RSA庫(kù)。經(jīng)過谷歌終于找到了一個(gè)很符合要求的實(shí)現(xiàn)方法:
http://hayageek.com/rsa-encryption-decryption-openssl-c/
下面就來說說整個(gè)開發(fā)詳細(xì)流程
安裝OpenSSL
RSA加密和解密的公鑰私鑰由OpenSSL生成倡蝙。在Ubuntu下寺鸥,安裝OpenSSL通過以下兩條命令可以完成:
sudo apt-get install openssl
sudo apt-get install libssl-dev
生成公鑰和私鑰
-- 生成 RSA 私鑰(傳統(tǒng)格式的,PKCS#1標(biāo)準(zhǔn))
openssl genrsa -out rsa_private_key.pem 1024
-- 將傳統(tǒng)格式的私鑰轉(zhuǎn)換成 PKCS#8 格式的(JAVA需要使用的私鑰需要經(jīng)過PKCS#8編碼,而本次在項(xiàng)目作為接口使用Lua編寫,如不需要這一步其實(shí)可以略過)
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt
-- 生成 RSA 公鑰
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
編譯動(dòng)態(tài)鏈接庫(kù)
參考上面給的鏈接躬贡,要封裝的RSA加解密C語(yǔ)言實(shí)現(xiàn)版如下:
rsa.c文件
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <stdio.h>
int padding = RSA_PKCS1_PADDING;
RSA * createRSA(unsigned char * key,int public)
{
RSA *rsa= NULL;
BIO *keybio ;
keybio = BIO_new_mem_buf(key, -1);
if (keybio==NULL)
{
printf( "Failed to create key BIO");
return 0;
}
if(public)
{
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL);
}
else
{
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL);
}
if(rsa == NULL)
{
printf( "Failed to create RSA");
}
return rsa;
}
int public_encrypt(unsigned char * data,int data_len,unsigned char * key, unsigned char *encrypted)
{
RSA * rsa = createRSA(key,1);
int result = RSA_public_encrypt(data_len,data,encrypted,rsa,padding);
return result;
}
int private_decrypt(unsigned char * enc_data,int data_len,unsigned char * key, unsigned char *decrypted)
{
RSA * rsa = createRSA(key,0);
int result = RSA_private_decrypt(data_len,enc_data,decrypted,rsa,padding);
return result;
}
int private_encrypt(unsigned char * data,int data_len,unsigned char * key, unsigned char *encrypted)
{
RSA * rsa = createRSA(key,0);
int result = RSA_private_encrypt(data_len,data,encrypted,rsa,padding);
return result;
}
int public_decrypt(unsigned char * enc_data,int data_len,unsigned char * key, unsigned char *decrypted)
{
RSA * rsa = createRSA(key,1);
int result = RSA_public_decrypt(data_len,enc_data,decrypted,rsa,padding);
return result;
}
void printLastError(char *msg)
{
char * err = malloc(130);;
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
printf("%s ERROR: %s\n",msg, err);
free(err);
}
在ubuntu下通過以下命令來生成.so庫(kù)
# gcc rsa.c -fPIC -shared -o librsa.so
使用rsa.so庫(kù)
生成的動(dòng)態(tài)鏈接庫(kù)放到usr/lib目錄下就能使用了,以下使用rsa.so封裝了一個(gè)lua版的rsa加解密庫(kù)
module("rsa", package.seeall)
local ffi = require('ffi')
local rsa = ffi.load('rsa')
ffi.cdef [[
int public_encrypt(unsigned char * data,int data_len,unsigned char * key, unsigned char *encrypted);
int private_decrypt(unsigned char * enc_data,int data_len,unsigned char * key, unsigned char *decrypted);
int private_encrypt(unsigned char * data,int data_len,unsigned char * key, unsigned char *encrypted);
int public_decrypt(unsigned char * enc_data,int data_len,unsigned char * key, unsigned char *decrypted);
]]
local _M = { _VERSION = '1.0' }
--公鑰加密
function _M.public_encrypt(msg, publicKey)
local c_str = ffi.new("char[?]", 1024 / 8)
ffi.copy(c_str, msg)
local pub = ffi.new("char[?]", #publicKey)
ffi.copy(pub, publicKey)
--存放加密結(jié)果
local encrypt = ffi.new("char[?]", 2048)
local ret = rsa.public_encrypt(c_str, #msg, pub, encrypt)
if ret == -1 then
return nil
end
return ffi.string(encrypt,ret)
end
--私鑰解密
function _M.private_decrypt(msg, privateKey)
local c_str = ffi.new("char[?]", 1024 / 8)
ffi.copy(c_str, msg)
local pri = ffi.new("char[?]", #privateKey)
ffi.copy(pri, privateKey)
--存放解密結(jié)果
local decrypt = ffi.new("char[?]", 2048)
local ret = rsa.private_decrypt(c_str, #msg, pri, decrypt)
if ret == -1 then
return nil
end
return ffi.string(decrypt,ret)
end
--私鑰加密
function _M.private_encrypt(msg, privateKey)
local c_str = ffi.new("char[?]", 1024 / 8)
ffi.copy(c_str, msg)
local pri = ffi.new("char[?]", #privateKey)
ffi.copy(pri, privateKey)
--存放加密結(jié)果
local encrypt = ffi.new("char[?]", 2048)
local ret = rsa.private_encrypt(c_str, #msg, pri, encrypt)
if ret == -1 then
return nil
end
return ffi.string(encrypt,ret)
end
--公鑰解密
function _M.public_decrypt(msg, publicKey)
local c_str = ffi.new("char[?]", 1024 / 8)
ffi.copy(c_str, msg)
local pub = ffi.new("char[?]", #publicKey)
ffi.copy(pub, publicKey)
--存放解密結(jié)果
local decrypt = ffi.new("char[?]", 2048)
local ret = rsa.public_decrypt(c_str, #msg, pub, decrypt)
if ret == -1 then
return nil
end
return ffi.string(decrypt,ret)
end
return _M
就這樣,本人的openresty rsa加解密第三方庫(kù)就制作完成了闯第,支持公鑰加密私鑰解密缀拭,也支持私鑰加密公鑰解密。下面貼出本人的測(cè)試代碼:
local rsa = require "resty.rsa"
local RSA_PUBLIC_KEY = [[-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3bTBJNQJjY6u7Y5b2eOWws0yW
CGuWPm6MGOSVan65wCrJa5p3q3sodQUDVPotjsknjLlje9E1F7Bx94ZuqTwkvAr6
ieLkgbbeqTCzeJ0AryUXiF3auxFSPdpBoD6nxtEeN8bZwfa/IYzdKyKlbhiQbUMN
qWgmxiPVwupwAML7RQIDAQAB
-----END PUBLIC KEY-----]]
local RSA_PRIV_KEY = [[-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC3bTBJNQJjY6u7Y5b2eOWws0yWCGuWPm6MGOSVan65wCrJa5p3
q3sodQUDVPotjsknjLlje9E1F7Bx94ZuqTwkvAr6ieLkgbbeqTCzeJ0AryUXiF3a
uxFSPdpBoD6nxtEeN8bZwfa/IYzdKyKlbhiQbUMNqWgmxiPVwupwAML7RQIDAQAB
AoGAc4NXvUKc1mqWY9Q75cwNGlJQEMwMtPlsNN4YVeBTHjdeuqoBBQwA62GGXqrN
QpOBKl79ASGghob8n0j6aAY70PQqHSU4c06c7UlkeEvxJKlyUTO2UgnjjIHb2flR
uW8y3xmjpXAfwe50eAVMNhCon7DBc+XMF/paSVwiG8V+GAECQQDvosVLImUkIXGf
I2AJ2iSOUF8W1UZ5Ru68E8hJoVkNehk14RUFzTkwhoPHYDseZyEhSunFQbXCotlL
Ar5+O+lBAkEAw/PJXvi3S557ihDjYjKnj/2XtIa1GwBJxOliVM4eVjfRX15OXPR2
6shID4ZNWfkWN3fjVm4CnUS41+bzHNctBQJAGCeiF3a6FzA/0bixH40bjjTPwO9y
kRrzSYX89F8NKOybyfCMO+95ykhk1B4BF4lxr3drpPSAq8Paf1MhfHvxgQJBAJUB
0WNy5o+OWItJBGAr/Ne2E6KnvRhnQ7GFd8zdYJxXndNTt2tgSv2Gh6WmjzOYApjz
heC3jy1gkN89NCn+RrECQBTvoqFHfyAlwOGC9ulcAcQDqj/EgCRVkVe1IsQZenAe
rKCWlUaeIKeVkRz/wzb1zy9AVsPC7Zbnf4nrOxJ23mI=
-----END RSA PRIVATE KEY-----]]
ngx.say('-----公鑰加密私鑰解密 start------')
local str='i love lwl'
local encryptPubStr = rsa.public_encrypt(str, RSA_PUBLIC_KEY)
if not encryptPubStr then
ngx.say('pub encrypt failed')
end
local decryptPriStr=rsa.private_decrypt(encryptPubStr,RSA_PRIV_KEY)
if not decryptPriStr then
ngx.say('pri decrypt failed')
end
ngx.say('公鑰加密私鑰解密成功\n'..decryptPriStr)
ngx.say('-----公鑰加密私鑰解密 end------')
ngx.say('================================')
ngx.say('-----私鑰加密公鑰解密 start------')
local str='i like lwl'
local encryptPriStr = rsa.private_encrypt(str, RSA_PRIV_KEY)
if not encryptPriStr then
ngx.say('pri encrypt failed')
end
local decryptPubStr=rsa.public_decrypt(encryptPriStr,RSA_PUBLIC_KEY)
if not decryptPubStr then
ngx.say('pub decrypt failed')
end
ngx.say('公鑰加密私鑰解密成功\n'..decryptPubStr)
ngx.say('-----私鑰加密公鑰解密 end------')
項(xiàng)目已托管到Github,歡迎star或fork褐荷,也歡迎提出改進(jìn)意見叛甫。
傳送門:lua-rsa