rsa: Criptografia/descriptografia RSA & assinatura/verificação para nginx-module-luaJIT
Instalação
Se você ainda não configurou a assinatura do repositório RPM, inscreva-se. Então você pode prosseguir com os seguintes passos.
CentOS/RHEL 7 ou Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-rsa
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-rsa
Para usar esta biblioteca Lua com NGINX, certifique-se de que o nginx-module-lua esteja instalado.
Este documento descreve lua-resty-rsa v1.1.1 lançado em 09 de novembro de 2024.
Esta biblioteca requer uma construção do nginx com OpenSSL, o módulo ngx_lua e LuaJIT.
Sinopse
# nginx.conf:
server {
location = /test {
content_by_lua_file conf/test.lua;
}
}
-- conf/test.lua:
local resty_rsa = require "resty.rsa"
local rsa_public_key, rsa_priv_key, err = resty_rsa:generate_rsa_keys(2048)
if not rsa_public_key then
ngx.say('erro ao gerar chaves rsa: ', err)
end
ngx.say(rsa_public_key)
--[[
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAuw4T755fepEyXTM66pzf6nv8NtnukQTMGnhmBFIFHp/P2vEpxjXU
BBDUpzKkVFR3wuK9O1FNmRDAGNGYC0N/9cZNdhykA1NixJfKQzncN31VJTmNqJNZ
W0x7H9ZGoh2aE0zCCZpRlC1Rf5rL0SVlBoQkn/n9LnYFwyLLIK5/d/y/NZVL6Z6L
cyvga0zRajamLIjY0Dy/8YIwVV6kaSsHeRv2cOB03eam6gbhLGIz/l8wuJhIn1rO
yJLQ36IOJymbbNmcC7+2hEQJP40qLvH7hZ1LaAkgQUHjfi8RvH2T1Jmce7XGPxCo
Ed0yfeFz+pL1KeSWNey6cL3N5hJZE8EntQIDAQAB
-----END RSA PUBLIC KEY-----
]]--
ngx.say(rsa_priv_key)
--[[
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAuw4T755fepEyXTM66pzf6nv8NtnukQTMGnhmBFIFHp/P2vEp
xjXUBBDUpzKkVFR3wuK9O1FNmRDAGNGYC0N/9cZNdhykA1NixJfKQzncN31VJTmN
qJNZW0x7H9ZGoh2aE0zCCZpRlC1Rf5rL0SVlBoQkn/n9LnYFwyLLIK5/d/y/NZVL
6Z6Lcyvga0zRajamLIjY0Dy/8YIwVV6kaSsHeRv2cOB03eam6gbhLGIz/l8wuJhI
n1rOyJLQ36IOJymbbNmcC7+2hEQJP40qLvH7hZ1LaAkgQUHjfi8RvH2T1Jmce7XG
PxCoEd0yfeFz+pL1KeSWNey6cL3N5hJZE8EntQIDAQABAoIBAGim1ayIFK8EMQNH
uDyui/Aqcc9WWky0PGTK23irUsXxb1708gQ89WNY70Cj6qBrqZ1VMb3QHPP4FSFN
kh0rJJoi2g+ssm5R5r5KlhTKeFRrQInVC1Y3KhUUUwZa4aWtnhgSJ7Urq1yVhjU4
K7PVkhH1OHBwcp/d1Bd6jd65AgPkY63P+WpcARJkClmQ1RhgoRwThyJdpKrV4/gO
ha0AUGlJNRNvRwiZxP0zaI5C8RdrG96SnVpeYOcD0z/M1HVlkoYMXsXLKttwLfpK
88Igtm6ZJwRpfuMF5VA+9hHaYGCBdGz0B/rMp2fc+EtrOavYQGrWIWi2RL1Qk6Rt
BUyeTgECgYEA9anj4n/cak1MT+hbNFsL31mJXryl1eVNjEZj/iPMztpdS15CmFgj
Kjr9UuintjSiK7Is43nZUWWyP1XQjRhVi2uP7PRIv92QNl/YteWD6tYCInJHKe2J
QqYyZrElezsdayXb5DK6bi1UIYYji90g79N7x6pOR0UnQNQUXTv+Y8ECgYEAwuzl
6Ez4BSXIIL9NK41jfNMa73Utfl5oO1f6mHM2KbILqaFE76PSgEeXDbOKdcjCbbqC
KCGjwyPd+Clehg4vkYXTq1y2SQGHwfz7DilPSOxhPY9ND7lGbeNzDUK4x8xe52hd
MWKdgqeqCK83e5D0ihzRiMah8dbxmlfLAOZ3sPUCgYEA0dT9Czg/YqUHq7FCReQG
rg3iYgMsexjTNh/hxO97PqwRyBCJPWr7DlU4j5qdteobIsubv+kSEI6Ww7Ze3kWM
u/tyAeleQlPTnD4d8rBKD0ogpJ+L3WpBNaaToldpNmr149GAktgpmXYqSEA1GIAW
ZAL11UPIfOO6dYswobpevYECgYEApSosSODnCx2PbMgL8IpWMU+DNEF6sef2s8oB
aam9zCi0HyCqE9AhLlb61D48ZT8eF/IAFVcjttauX3dWQ4rDna/iwgHF5yhnyuS8
KayxJJ4+avYAmwEnfzdJpoPRpGI0TCovRQhFZI8C0Wb+QTJ7Mofmt9lvIUc64sff
GD0wT/0CgYASMf708dmc5Bpzcis++EgMJVb0q+ORmWzSai1NB4bf3LsNS6suWNNU
zj/JGtMaGvQo5vzGU4exNkhpQo8yUU5YbHlA8RCj7SYkmP78kCewEqxlx7dbcuj2
LAPWpiDca8StTfEphoKEVfCPHaUk0MlBHR4lCrnAkEtz23vhZKWhFw==
-----END RSA PRIVATE KEY-----
]]--
local pub, err = resty_rsa:new({ public_key = rsa_public_key })
if not pub then
ngx.say("erro ao criar rsa: ", err)
return
end
local encrypted, err = pub:encrypt("hello")
if not encrypted then
ngx.say("falha ao criptografar: ", err)
return
end
ngx.say("comprimento criptografado: ", #encrypted)
local priv, err = resty_rsa:new({ private_key = rsa_priv_key })
if not priv then
ngx.say("erro ao criar rsa: ", err)
return
end
local decrypted = priv:decrypt(encrypted)
ngx.say(decrypted == "hello")
local algorithm = "SHA256"
local priv, err = resty_rsa:new({ private_key = rsa_priv_key, algorithm = algorithm })
if not priv then
ngx.say("erro ao criar rsa: ", err)
return
end
local str = "hello"
local sig, err = priv:sign(str)
if not sig then
ngx.say("falha ao assinar:", err)
return
end
ngx.say("comprimento da assinatura: ", #sig)
local pub, err = resty_rsa:new({ public_key = rsa_public_key, algorithm = algorithm })
if not pub then
ngx.say("erro ao criar rsa: ", err)
return
end
local verify, err = pub:verify(str, sig)
if not verify then
ngx.say("erro de verificação: ", err)
return
end
ngx.say(verify)
Métodos
Para carregar esta biblioteca,
- você precisa especificar o caminho desta biblioteca na diretiva lua_package_path do ngx_lua. Por exemplo,
lua_package_path "/path/to/lua-resty-rsa/lib/?.lua;;";. - você usa
requirepara carregar a biblioteca em uma variável Lua local:
local rsa = require "resty.rsa"
generate_rsa_keys
syntax: public_key, private_key, err = rsa:generate_rsa_keys(bits, in_pkcs8_fmt)
Gera a chave pública rsa e a chave privada especificando o número de bits. O in_pkcs8_fmt é opcional. Se in_pkcs8_fmt for verdadeiro, a chave privada gerada estará no formato PKCS#8 e a chave pública estará no formato PKIX, que começa com -----BEGIN PUBLIC ou -----BEGIN PRIVATE. Caso contrário, as chaves geradas estarão no formato PKCS#1, que começa com -----BEGIN RSA.
new
syntax: obj, err = rsa:new(opts)
Cria uma nova instância de objeto rsa especificando uma tabela de opções opts.
A tabela de opções aceita as seguintes opções:
public_keyEspecifica a chave pública rsa.private_keyEspecifica a chave privada rsa.passwordEspecifica a senha para ler a chave rsa.key_typeEspecifica o tipo da chave fornecida. Por padrão, o tipo será detectado a partir do valor da chave.
valor de key_type |
significado |
|---|---|
| rsa.KEY_TYPE.PKCS1 | A chave de entrada está no formato PKCS#1 (geralmente começa com -----BEGIN RSA PUBLIC). |
| rsa.KEY_TYPE.PKIX | A chave de entrada está no formato PKIX (geralmente começa com -----BEGIN PUBLIC). |
-- cria um objeto rsa com formato PKIX da chave pública
local resty_rsa = require "resty.rsa"
local pub, err = resty_rsa:new({
public_key = RSA_PKCS8_PUB_KEY,
key_type = resty_rsa.KEY_TYPE.PKIX,
})
-- cria um objeto rsa com formato pkcs#8 da chave privada
local priv, err = resty_rsa:new({
private_key = RSA_PKCS8_PASS_PRIV_KEY,
key_type = resty_rsa.KEY_TYPE.PKCS8,
-- você precisa especificar a senha se a chave privada estiver criptografada
-- password = "foobar",
})
paddingEspecifica o modo de preenchimento quando você deseja criptografar/descriptografar.algorithmEspecifica o algoritmo de resumo quando você deseja assinar/verificar.
valor de algorithm |
significado |
|---|---|
| md4/MD4/RSA-MD4/md4WithRSAEncryption | resumo com md4 |
| md5/MD5/RSA-MD5/md5WithRSAEncryption/ssl3-md5 | resumo com md5 |
| ripemd160/RIPEMD160/RSA-RIPEM160/ripemd160WithRSA/rmd160 | resumo com ripemd160 |
| sha1/SHA1/RSA-SHA1/sha1WithRSAEncryption/ssl3-sha1 | resumo com sha1 |
| sha224/SHA224/RSA-SHA224/sha224WithRSAEncryption | resumo com sha224 |
| sha256/SHA256/RSA-SHA256/sha256WithRSAEncryption | resumo com sha256 |
| sha384/SHA384/RSA-SHA384/sha384WithRSAEncryption | resumo com sha384 |
| sha512/SHA512/RSA-SHA512/sha512WithRSAEncryption | resumo com sha512 |
encrypt
syntax: encrypted, err = obj:encrypt(str)
decrypt
syntax: decrypted, err = obj:decrypt(encrypted)
sign
syntax: signature, err = obj:sign(str)
verify
syntax: ok, err = obj:verify(str, signature)
Performance
Eu obtive o resultado:
criptografar 50000 vezes custou : 2.4110000133514s
descriptografar 50000 vezes custou : 57.196000099182s
assinar 50000 vezes custou : 59.169999837875s
verificar 50000 vezes custou : 1.8230001926422s
quando executei este script.
local resty_rsa = require "resty.rsa"
local algorithm = "SHA256"
local rsa_public_key, rsa_priv_key, err = resty_rsa:generate_rsa_keys(2048)
if not rsa_public_key then
ngx.say("erro ao gerar chaves rsa: ", err)
return
end
local pub, err = resty_rsa:new({
public_key = rsa_public_key,
padding = resty_rsa.PADDING.RSA_PKCS1_PADDING,
algorithm = algorithm,
})
if not pub then
ngx.say("erro ao criar rsa: ", err)
return
end
local priv, err = resty_rsa:new({
private_key = rsa_priv_key,
padding = resty_rsa.PADDING.RSA_PKCS1_PADDING,
algorithm = algorithm,
})
if not priv then
ngx.say("erro ao criar rsa: ", err)
return
end
local num = 5 * 10000
local str = "hello test"
local encrypted, decrypted, err, sig, verify
ngx.update_time()
local now = ngx.now()
local function timer(operation)
ngx.update_time()
local t = ngx.now()
ngx.say(operation, " por ", num, " vezes custou : ", t - now, "s")
now = t
end
for _ = 1, num do
encrypted, err = pub:encrypt(str)
if not encrypted then
ngx.say("falha ao criptografar: ", err)
return
end
end
timer("criptografar")
for _ = 1, num do
decrypted = priv:decrypt(encrypted)
if decrypted ~= str then
ngx.say("decriptografado não corresponde")
return
end
end
timer("descriptografar")
for _ = 1, num do
sig, err = priv:sign(str)
if not sig then
ngx.say("falha ao assinar:", err)
return
end
end
timer("assinar")
for _ = 1, num do
verify, err = pub:verify(str, sig)
if not verify then
ngx.say("erro de verificação: ", err)
return
end
end
timer("verificar")
Etapas de Lançamento
- atualize o
_VERSIONemlib/resty/rsa.lua - atualize a
versionemdist.ini - renomeie o rockspec atual para a nova versão e atualize a referência nele.
- marque a nova versão
- opm upload
Veja Também
- o módulo ngx_lua: http://wiki.nginx.org/HttpLuaModule
- o lua-resty-string: https://github.com/openresty/lua-resty-string
GitHub
Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório GitHub do nginx-module-rsa.