lua-resty-rsa

用于 OpenResty/LuaJIT 的 RSA 加密/解密和签名/验证

$ opm get spacewander/lua-resty-rsa

名称

lua-resty-rsa - LuaJIT 的 RSA 函数

状态

该库被认为是生产就绪的。

构建状态: [!Travis](https://travis-ci.org/spacewander/lua-resty-rsa)

描述

该库需要使用 OpenSSL 构建的 nginx,ngx_lua 模块LuaJIT

概要

        # nginx.conf:
    
        lua_package_path "/path/to/lua-resty-rsa/lib/?.lua;;";
    
        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('generate rsa keys err: ', 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("new rsa err: ", err)
            return
        end
        local encrypted, err = pub:encrypt("hello")
        if not encrypted then
            ngx.say("failed to encrypt: ", err)
            return
        end
        ngx.say("encrypted length: ", #encrypted)
    
        local priv, err = resty_rsa:new({ private_key = rsa_priv_key })
        if not priv then
            ngx.say("new rsa err: ", 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("new rsa err: ", err)
            return
        end
    
        local str = "hello"
        local sig, err = priv:sign(str)
        if not sig then
            ngx.say("failed to sign:", err)
            return
        end
        ngx.say("sig length: ", #sig)
    
        local pub, err = resty_rsa:new({ public_key = rsa_public_key, algorithm = algorithm })
        if not pub then
            ngx.say("new rsa err: ", err)
            return
        end
        local verify, err = pub:verify(str, sig)
        if not verify then
            ngx.say("verify err: ", err)
            return
        end
        ngx.say(verify)

方法

要加载该库,

  1. 您需要在 ngx_lua 的 lua_package_path 指令中指定该库的路径。例如,lua_package_path "/path/to/lua-resty-rsa/lib/?.lua;;";

  2. 您可以使用 require 将库加载到一个本地 Lua 变量中

        local rsa = require "resty.rsa"

generate_rsa_keys

语法: public_key, private_key, err = rsa:generate_rsa_keys(bits, in_pkcs8_fmt)

通过指定 bits 的数量来生成 rsa 公钥和私钥。in_pkcs8_fmt 是可选的。如果 in_pkcs8_fmt 为真,则生成的密钥将采用 PKCS#8 格式,以 -----BEGIN PUBLIC-----BEGIN PRIVATE 开头。否则,生成的密钥将采用 PKCS#1 格式,以 -----BEGIN RSA 开头。

new

语法: obj, err = rsa:new(opts)

通过指定一个选项表 opts 来创建一个新的 rsa 对象实例。

选项表接受以下选项

  • public_key 指定 rsa 公钥。

  • private_key 指定 rsa 私钥。

  • password 指定读取 rsa 密钥的密码。

  • key_type 指定给定密钥的类型。默认情况下,将从密钥的值中检测类型。

| key_type 值 | 含义 | | ------------------- | ------ | | rsa.KEY_TYPE.PKCS1 | 输入密钥采用 PKCS#1 格式(通常以 -----BEGIN RSA PUBLIC 开头)。 | | rsa.KEY_TYPE.PKCS8 | 输入密钥采用 PKCS#8 格式(通常以 -----BEGIN PUBLIC 开头)。 |

    -- creates a rsa object with pkcs#8 format of public key
    local resty_rsa = require "resty.rsa"
    local pub, err = resty_rsa:new({
        public_key = RSA_PKCS8_PUB_KEY,
        key_type = resty_rsa.KEY_TYPE.PKCS8,
    })
    
    -- creates a rsa object with pkcs#8 format of private key
    local priv, err = resty_rsa:new({
        private_key = RSA_PKCS8_PASS_PRIV_KEY,
        key_type = resty_rsa.KEY_TYPE.PKCS8,
        -- you need to specify the password if the pkey is encrypted
        -- password = "foobar",
    })
  • padding 指定您想要加密/解密时的填充模式。

  • algorithm 指定您想要签名/验证时的摘要算法。

| algorithm 值 | 含义 | | ------------------- | ------ | | md4/MD4/RSA-MD4/md4WithRSAEncryption | 使用 md4 进行摘要 | | md5/MD5/RSA-MD5/md5WithRSAEncryption/ssl3-md5 | 使用 md5 进行摘要 | | ripemd160/RIPEMD160/RSA-RIPEM160/ripemd160WithRSA/rmd160 | 使用 ripemd160 进行摘要 | | sha1/SHA1/RSA-SHA1/sha1WithRSAEncryption/ssl3-sha1 | 使用 sha1 进行摘要 | | sha224/SHA224/RSA-SHA224/sha224WithRSAEncryption | 使用 sha224 进行摘要 | | sha256/SHA256/RSA-SHA256/sha256WithRSAEncryption | 使用 sha256 进行摘要 | | sha384/SHA384/RSA-SHA384/sha384WithRSAEncryption | 使用 sha384 进行摘要 | | sha512/SHA512/RSA-SHA512/sha512WithRSAEncryption | 使用 sha512 进行摘要 |

encrypt

语法: encrypted, err = obj:encrypt(str)

decrypt

语法: decrypted, err = obj:decrypt(encrypted)

sign

语法: signature, err = obj:sign(str)

verify

语法: ok, err = obj:verify(str, signature)

性能

当我运行这段脚本时,我得到了结果

    encrypt for 50000 times cost : 2.4110000133514s
    decrypt for 50000 times cost : 57.196000099182s
    sign for 50000 times cost : 59.169999837875s
    verify for 50000 times cost : 1.8230001926422s

    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("generate rsa keys err: ", 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("new rsa err: ", 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("new rsa err: ", 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, " for ", num, " times cost : ", t - now, "s")
        now = t
    end
    
    for _ = 1, num do
        encrypted, err = pub:encrypt(str)
        if not encrypted then
            ngx.say("failed to encrypt: ", err)
            return
        end
    end
    
    timer("encrypt")
    
    for _ = 1, num do
        decrypted = priv:decrypt(encrypted)
        if decrypted ~= str then
            ngx.say("decrypted not match")
            return
        end
    end
    
    timer("decrypt")
    
    for _ = 1, num do
        sig, err = priv:sign(str)
        if not sig then
            ngx.say("failed to sign:", err)
            return
        end
    end
    
    timer("sign")
    
    for _ = 1, num do
        verify, err = pub:verify(str, sig)
        if not verify then
            ngx.say("verify err: ", err)
            return
        end
    end
    
    timer("verify")

作者

朱德江 (doujiang24) <doujiang24@gmail.com>

罗泽轩 (spacewander)

发布步骤

  1. 更新 lib/resty/rsa.lua 中的 _VERSION

  2. 更新 dist.ini 中的 version

  3. 将当前 rockspec 重命名为新版本,并在其中更新引用。

  4. 标记新版本

  5. opm upload

版权和许可

该模块在 MIT 许可下授权。

版权所有 (C) 2014-2018,由朱德江 (doujiang24) <doujiang24@gmail.com> 版权所有 (C) 2018-,由罗泽轩 (spacewander)

保留所有权利。

在满足以下条件的情况下,允许以源代码和二进制形式重新分发和使用本软件,无论是否经过修改。

  • 源代码的再分发必须保留上述版权声明、此条件列表和以下免责声明。

  • 二进制形式的再分发必须在随分发提供的文档和/或其他材料中复制上述版权声明、此条件列表和以下免责声明。

本软件由版权持有人和贡献者“按原样”提供,不附带任何明示或暗示的担保,包括但不限于适销性保证和适用于特定目的的保证。在任何情况下,版权持有人或贡献者均不对因使用本软件而造成的任何直接、间接、意外、特殊、示例性或后果性损害(包括但不限于替代商品或服务的采购;使用损失、数据或利润损失;或业务中断)负责,无论这种损害是基于何种责任理论造成的,无论是基于合同、严格责任还是侵权行为(包括疏忽或其他原因),即使已告知可能发生此类损害。

另请参阅

  • ngx_lua 模块: http://wiki.nginx.org/HttpLuaModule

  • lua-resty-string: https://github.com/openresty/lua-resty-string

作者

spacewander

许可证

mit

版本