跳转至

rsa - RSA加密解密

作者:王城钧

一、概述

rsa 库提供基于 RSA 非对称加密的安全通信能力,支持 PEM 格式密钥的加密/解密、数字签名/验签功能,适用于设备与服务器间的数据保密传输和身份认证。

二、核心示例

1、核心示例是指:使用本库文件提供的核心 API,开发的基础业务逻辑的演示代码;

2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;

3、更加完整和详细的 demo,请参考 LuatOS 仓库 中各个产品目录下的 demo/rsa

-- 注意:本demo需要用到公钥和私钥, demo目录中的公钥私钥文件是演示用的, 实际使用请自行生成
PROJECT = "rsademo"
VERSION = "1.0.1"

log.info("main", PROJECT, VERSION)

local function rsa()
    -- 为了日志能正常显示出来, 这里特意延时2秒, 实际使用中不需要
    sys.wait(2000)

    -- 检查是否带rsa库, 没有就提醒一下吧
    if not rsa then
        log.warn("main", "this demo need rsa lib!!!")
        return
    end

    -- 读取公钥并马上加密数据
    local res = rsa.encrypt((io.readFile("/luadb/public.pem")), "abc")
    -- 打印结果
    log.info("rsa", "encrypt", res and #res or 0, res and res:toHex() or "")

    -- 下面是解密, 通常不会在设备端进行, 这里主要是演示用法, 会很慢
    if res then
        -- 读取私钥, 然后解码数据
        local dst = rsa.decrypt((io.readFile("/luadb/privkey.pem")), res, "")
        log.info("rsa", "decrypt", dst and #dst or 0, dst and dst:toHex() or "")
    end

    -- 演示签名和验签
    local hash = crypto.sha1("1234567890"):fromHex()
    -- 签名通常很慢, 通常是服务器做
    local sig = rsa.sign((io.readFile("/luadb/privkey.pem")), rsa.MD_SHA1, hash, "")
    log.info("rsa", "sign", sig and #sig or 0, sig and sig:toHex() or "")
    if sig then
        -- 验签是很快的
        local ret = rsa.verify((io.readFile("/luadb/public.pem")), rsa.MD_SHA1, hash, sig)
        log.info("rsa", "verify", ret)
    end
end

sys.taskInit(rsa)

-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!

三、常量详解

核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;

rsa 核心库没有常量。

四、函数详解

rsa.encrypt(key, data)

功能

RSA 加密过程通过解析 PEM 格式公钥,对不超过公钥位数一半的待加密数据执行 RSA-PKCS1_V1.5 加密运算,成功返回二进制密文数据,失败时返回 nil。

参数

key

参数含义:表示公钥数据;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:仅支持PEM格式
参数示例:(io.readFile("/luadb/public.pem"))

data

参数含义:表示待加密数据;
数据类型:string
取值范围:不能超过公钥位数的一半;
         例如 2048bit(256字节,1字节等于8)的公钥, 只能加密128字节的数据;
是否必选:必须传入此参数;
注意事项:仅支持PEM格式
参数示例:"abc"

返回值

local res = rsa.encrypt(key,data)

res

含义说明:加密成功后的数据,若失败会返回nil
数据类型:string或者nil
取值范围:暂无;
注意事项:暂无;
返回示例:使用log.info("rsa", "encrypt", res and #res or 0, res and res:toHex() or "")
         打印的结果如下:
         rsa encrypt 256 
         1586CB23B2004F6208A1816DA209896F0CD026A53DD53771067BC64E13
         16C8E97A51F4595E83B7EF68B36E689C25F4D49ABB7F9E3DA7A8FAB3AB
         F45986F295ABF6D5FA5E140B46EFA258578DA6E9DA6A91B7253AF5DFFC
         86C93C0DE90B444ACDB564C5ED3EFBA09CC1A09B369C15362BFFA40E61
         1FE80D2A78C37B42BC09EFBDCE18BD3475BCD42E782031BADA8330BF32
         EEAAFF76294B8B34F075D8C39EC970E44DD1FABDD1432C1D5F317E815C
         7ADCFF9E0B85D659794BCCC3989188036C2CF2ED05369A4B1EF9EAE83F
         8C7215D0CA6D23029CCC940E4FDA1CCEF3AEB2D16A1D19F5FEE50F6858
         A83AC2FA79B4C945F55DAF9C6D8CDF1E98DCA34F7E55F07E

示例

-- 下面代码中的 "abc" 是待加密数据
local res = rsa.encrypt((io.readFile("/luadb/public.pem")), "abc")
-- 打印结果
log.info("rsa", "encrypt", res and #res or 0, res and res:toHex() or "")

rsa.decrypt(key, data, pwd)

功能

RSA 解密过程通过私钥解析(支持可选密码)、数据长度校验,对加密数据执行解密运算,成功返回原始二进制数据,失败或出错时返回 nil。 参数

key

参数含义:表示私钥数据;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:仅支持PEM格式
参数示例:(io.readFile("/luadb/privkey.pem"))

data

参数含义:表示待解密数据;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:"1586CB23B2004F6208A1816DA209896F0CD026A53DD53771067BC64E
          1316C8E97A51F4595E83B7EF68B36E689C25F4D49ABB7F9E3DA7A8FA
          B3ABF45986F295ABF6D5FA5E140B46EFA258578DA6E9DA6A91B7253A
          F5DFFC86C93C0DE90B444ACDB564C5ED3EFBA09CC1A09B369C15362B
          FFA40E611FE80D2A78C37B42BC09EFBDCE18BD3475BCD42E782031BA
          DA8330BF32EEAAFF76294B8B34F075D8C39EC970E44DD1FABDD1432C
          1D5F317E815C7ADCFF9E0B85D659794BCCC3989188036C2CF2ED0536
          9A4B1EF9EAE83F8C7215D0CA6D23029CCC940E4FDA1CCEF3AEB2D16A
          1D19F5FEE50F6858A83AC2FA79B4C945F55DAF9C6D8CDF1E98DCA34F
          7E55F07E"

pwd

参数含义:表示私钥的密码;
数据类型:string
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:暂无;
参数示例:暂无;

返回值

local dst = rsa.decrypt(key,data,pwd)

dst

含义说明:解密成功后的数据,若失败会返回nil
数据类型:string或者nil
取值范围:暂无;
注意事项:暂无;
返回示例:使用log.info("rsa", "decrypt", dst and #dst or 0, dst and dst:toHex() or "")
         打印的结果如下:
         rsa decrypt 3 616263

示例

-- 注意, 解密通常很慢, 建议在服务器端进行
-- res 是待解密的数据
local dst = rsa.decrypt((io.readFile("/luadb/privkey.pem")), res, "")
log.info("rsa", "decrypt", dst and #dst or 0, dst and dst:toHex() or "")

rsa.sign(key, md, hash, pwd)

功能

RSA 签名过程通过私钥解析、指定哈希算法及可选密码,对输入哈希值进行签名运算,成功生成并返回二进制签名数据,失败或出错时返回 nil。

参数

key

参数含义:表示私钥数据;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:仅支持PEM格式
参数示例:(io.readFile("/luadb/privkey.pem"))

md

参数含义:签名模式;
数据类型:number
取值范围:rsa.MD_SHA1rsa.MD_SHA256rsa.MD_MD5rsa.MD_SHA224
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:rsa.MD_SHA1rsa.MD_SHA256

hash

参数含义:hash数据
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:如果是HEX字符串,记得fromHex转二进制数据
参数示例:hash

pwd

参数含义:私钥密码;
数据类型:string
取值范围:暂无;
是否必选:可选传入此参数;
注意事项:如果是HEX字符串,记得fromHex转二进制数据
参数示例:"123456"

返回值

local sig= rsa.sign(key, md, hash, pwd)

sig

含义说明:成功返回sig数据, 否则返回nil
数据类型:string或者nil
取值范围:暂无;
注意事项:暂无;
返回示例:使用log.info("rsa", "sign", sig and #sig or 0, sig and sig:toHex() or "")
         打印结果如下:
         rsa sign 256
         2A526049BSDOFFDF370EE1EB37E87A1C054B387386C635B4DD46E3970F90D08732D4CC
         1B38EA9153B6C52AE2602C55272828D4F627E1BF8B94BC02C79DB1F0462F3A5A654D9D
         AF2794F4DBECIA691FE6DOC45SCA0DCE9B9ACDFCAC79D9CFF46740248131E58ACE00BE
         7DA8S37F1E6SS0F17C204ADDD79C7356C57D9FD4ACC7006BA2E248B9FEFE002EBFCCF8
         5B5A8DA0D1369D6463D24F8CA24C2E314CCE39DF43A0SEB3840BDC1298F0361D13HE2E
         F3C87A76D82696873B8FEDD748DF54D70CB3D2A5072D137954BFA4FA990D2C01D8061F
         0F2E27DF813DAB751A06F38C8327E574EDCC52F21A98EC2E6CD9A8A8AFC9DA0475EB75
         47D0

示例

local sig = rsa.sign((io.readFile("/luadb/privkey.pem")), rsa.MD_SHA1, hash, "")
log.info("rsa", "sign", sig and #sig or 0, sig and sig:toHex() or "")

rsa.verify(key, md, hash, sig)

功能

RSA 验签过程首先通过公钥解析、指定哈希算法及签名模式,验证待验签数据与签名是否匹配,成功返回 true,失败返回 false,出错返回 nil。

参数

key

参数含义:表示公钥数据;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:仅支持PEM格式
参数示例:(io.readFile("/luadb/public.pem"))

md

参数含义:签名模式;
数据类型:number
取值范围:rsa.MD_SHA1rsa.MD_SHA256rsa.MD_MD5rsa.MD_SHA224
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:rsa.MD_SHA1rsa.MD_SHA256

hash

参数含义:hash数据
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:如果是HEX字符串,记得fromHex转二进制数据
参数示例:暂无;

sig

参数含义:私钥签名后的数据;
数据类型:string
取值范围:暂无;
是否必选:必须传入此参数;
注意事项:如果是HEX字符串,记得fromHex转二进制数据
参数示例:"2A526049B5D0FFFDF370EE1EB37E87A1C054B387386C635B4DD46E39
          70F90D08732D4CC1B338EA9153B6C52AE22602C55272C828D4F627E1
          BF8B994BC02C79DB1F0462F3A5A654D9DAF2794F4D8EC1A691FE6D0C
          455CA0DCE9B9ACDFC44C79D9CFFF46740248131EE58ACE00BE7DA853
          7F1E6550F17C204ADDD79C735C57D9FD4ACC7006BA22E248B9FEFE00
          2E8FCCCF85B5A8DA0D133669D6463D24F8CA24C2E314CCCE39DF43A0
          5EB33840BDC1298F0361D13FE2EEF3C87A76D826968873B8FEDD748D
          F54D70CB3D2A5072D137954BFA4FA990D2C01D8061FF0F2E27DF813D
          A8751A06F38C83827E574EDCC52F271A98EC2E6CD9A8A8AFC9DA0475
          EB7547D0"

返回值

local ret = rsa.verify(key, md, hash, sig)

ret

含义说明:验签是否成功,成功返回true,失败返回false
数据类型:boolean或者nil
取值范围:true或者false或者nil
注意事项:暂无;
返回示例:true

示例

local ret = rsa.verify((io.readFile("/luadb/public.pem")), rsa.MD_SHA1, hash, sig)
log.info("rsa", "verify", ret)

五、产品支持说明

目前合宙主流模组都支持 rsa 核心库。