| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /*
- @module rsa
- @summary RSA加密解密
- @version 1.0
- @date 2022.11.03
- @demo rsa
- @tag LUAT_USE_RSA
- @usage
- -- 请在电脑上生成私钥和公钥, 当前最高支持4096bit, 一般来说2048bit就够用了
- -- openssl genrsa -out privkey.pem 2048
- -- openssl rsa -in privkey.pem -pubout -out public.pem
- -- privkey.pem 是私钥, public.pem 是公钥
- -- 私钥用于 加密 和 签名, 通常保密, 放在服务器端
- -- 公钥用于 解密 和 验签, 一般可公开,放在设备端
- -- 为了演示API使用, 这里把私钥也放在设备上
- 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
- */
- #include "luat_base.h"
- #include "luat_mem.h"
- #include "luat_crypto.h"
- #include "luat_fs.h"
- #define LUAT_LOG_TAG "rsa"
- #include "luat_log.h"
- #include "mbedtls/rsa.h"
- #include "mbedtls/pk.h"
- #include "mbedtls/entropy.h"
- #include "mbedtls/ctr_drbg.h"
- #include "mbedtls/md.h"
- static int myrand( void *rng_state, unsigned char *output, size_t len ) {
- (void)rng_state;
- luat_crypto_trng((char*)output, len);
- return 0;
- }
- /*
- RSA加密
- @api rsa.encrypt(key, data)
- @string 公钥数据,仅支持PEM格式
- @string 待加密数据, 不能超过公钥位数的一半, 例如 2048bit的公钥, 只能加密128字节的数据
- @return string 加密成功后的数据,若失败会返回nil
- @usage
- -- 下面代码中的 "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 "")
- */
- static int l_rsa_encrypt(lua_State* L) {
- int ret = 0;
- size_t ilen = 0;
- size_t keylen = 0;
- size_t olen = 0;
- char buff[1024];
- const char* key = luaL_checklstring(L, 1, &keylen);
- const char* data = luaL_checklstring(L, 2, &ilen);
- mbedtls_pk_context ctx_pk;
- mbedtls_pk_init(&ctx_pk);
- ret = mbedtls_pk_parse_public_key(&ctx_pk, (const unsigned char*)key, keylen + 1);
- if (ret) {
- mbedtls_pk_free(&ctx_pk);
- LLOGW("bad public key %04X", -ret);
- return 0;
- }
- ret = mbedtls_pk_encrypt(&ctx_pk, (const unsigned char*)data, ilen, (unsigned char*)buff, &olen, 1024, myrand, NULL);
- mbedtls_pk_free(&ctx_pk);
- if (ret) {
- LLOGW("mbedtls_rsa_pkcs1_encrypt %04X", -ret);
- return 0;
- }
- lua_pushlstring(L, buff, olen);
- return 1;
- }
- /*
- RSA解密
- @api rsa.decrypt(key, data, pwd)
- @string 私钥数据,仅支持PEM格式
- @string 待解密数据
- @string 私钥的密码,可选
- @return string 解密成功后的数据,若失败会返回nil
- @usage
- -- 注意, 解密通常很慢, 建议在服务器端进行
- -- 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 "")
- */
- static int l_rsa_decrypt(lua_State* L) {
- int ret = 0;
- size_t ilen = 0;
- size_t keylen = 0;
- size_t rsa_len = 0;
- size_t olen = 0;
- size_t pwdlen = 0;
- char buff[1024];
- const char* key = luaL_checklstring(L, 1, &keylen);
- const char* data = luaL_checklstring(L, 2, &ilen);
- const char* pwd = luaL_optlstring(L, 3, "", &pwdlen);
- mbedtls_pk_context ctx_pk;
- mbedtls_pk_init(&ctx_pk);
- ret = mbedtls_pk_parse_key(&ctx_pk, (const unsigned char*)key, keylen + 1, (const unsigned char*)pwd, pwdlen
- #if MBEDTLS_VERSION_NUMBER >= 0x03000000
- , myrand, NULL
- #endif
- );
- if (ret) {
- mbedtls_pk_free(&ctx_pk);
- LLOGW("bad private key %04X", -ret);
- return 0;
- }
- rsa_len = (mbedtls_pk_get_bitlen(&ctx_pk) + 7 ) / 8;
- if (rsa_len != ilen) {
- mbedtls_pk_free(&ctx_pk);
- LLOGW("data len NOT match expect %d but %d", rsa_len, ilen);
- return 0;
- }
- ret = mbedtls_pk_decrypt(&ctx_pk, (const unsigned char*)data, ilen, (unsigned char*)buff, &olen, 1024, myrand, NULL);
- mbedtls_pk_free(&ctx_pk);
- if (ret) {
- LLOGW("mbedtls_rsa_pkcs1_decrypt %04X", -ret);
- return 0;
- }
- lua_pushlstring(L, buff, olen);
- return 1;
- }
- /*
- RSA验签
- @api rsa.verify(key, md, hash, sig)
- @string 公钥数据,仅支持PEM格式
- @int 签名模式, 例如 rsa.MD_SHA1 , rsa.MD_SHA256
- @string hash数据, 如果是HEX字符串,记得fromHex转二进制数据
- @string sig数据, 如果是HEX字符串,记得fromHex转二进制数据
- @return bool 有效返回true,否则为false,出错返回nil
- @usage
- local ret = rsa.verify((io.readFile("/luadb/public.pem")), rsa.MD_SHA1, hash, sig)
- log.info("rsa", "verify", ret)
- */
- static int l_rsa_verify(lua_State* L) {
- int ret = 0;
- size_t hash_len = 0;
- size_t sig_len = 0;
- size_t keylen = 0;
- const char* key = luaL_checklstring(L, 1, &keylen);
- mbedtls_md_type_t md = luaL_checkinteger(L, 2);
- const char* hash = luaL_checklstring(L, 3, &hash_len);
- const char* sig = luaL_checklstring(L, 4, &sig_len);
- mbedtls_pk_context ctx_pk;
- mbedtls_pk_init(&ctx_pk);
- ret = mbedtls_pk_parse_public_key(&ctx_pk, (const unsigned char*)key, keylen + 1);
- if (ret) {
- mbedtls_pk_free(&ctx_pk);
- LLOGW("bad public key %04X", -ret);
- return 0;
- }
- ret = mbedtls_pk_verify(&ctx_pk, md, (const unsigned char*)hash, hash_len, (const unsigned char*)sig, sig_len);
- lua_pushboolean(L, ret == 0 ? 1 : 0);
- return 1;
- }
- /*
- RSA签名
- @api rsa.sign(key, md, hash, pwd)
- @string 私钥数据,仅支持PEM格式
- @int 签名模式, 例如 rsa.MD_SHA1 , rsa.MD_SHA256
- @string hash数据, 如果是HEX字符串,记得fromHex转二进制数据
- @string 私钥密码, 可选
- @return string 成功返回sig数据, 否则返回nil
- @usage
- 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 "")
- */
- static int l_rsa_sign(lua_State* L) {
- int ret = 0;
- size_t pwdlen = 0;
- size_t hash_len = 0;
- size_t sig_len = 0;
- size_t keylen = 0;
- char sig[MBEDTLS_PK_SIGNATURE_MAX_SIZE] = {0};
- const char* key = luaL_checklstring(L, 1, &keylen);
- mbedtls_md_type_t md = luaL_checkinteger(L, 2);
- const char* hash = luaL_checklstring(L, 3, &hash_len);
- const char* pwd = luaL_optlstring(L, 4, "", &pwdlen);
- mbedtls_pk_context ctx_pk;
- mbedtls_pk_init(&ctx_pk);
- ret = mbedtls_pk_parse_key(&ctx_pk, (const unsigned char*)key, keylen + 1, (const unsigned char*)pwd, pwdlen
- #if MBEDTLS_VERSION_NUMBER >= 0x03000000
- , myrand, NULL
- #endif
- );
- if (ret) {
- mbedtls_pk_free(&ctx_pk);
- LLOGW("bad private key %04X", -ret);
- return 0;
- }
- ret = mbedtls_pk_sign(&ctx_pk, md, (const unsigned char*)hash, hash_len, (unsigned char*)sig,
- #if MBEDTLS_VERSION_NUMBER >= 0x03000000
- MBEDTLS_PK_SIGNATURE_MAX_SIZE,
- #endif
- &sig_len, myrand, NULL);
- mbedtls_pk_free(&ctx_pk);
- if (ret) {
- LLOGW("mbedtls_pk_sign %04X", -ret);
- return 0;
- }
- lua_pushlstring(L, sig, sig_len);
- return 1;
- }
- #include "rotable2.h"
- static const rotable_Reg_t reg_rsa[] =
- {
- { "encrypt" , ROREG_FUNC(l_rsa_encrypt)},
- { "decrypt" , ROREG_FUNC(l_rsa_decrypt)},
- { "verify", ROREG_FUNC(l_rsa_verify)},
- { "sign", ROREG_FUNC(l_rsa_sign)},
- //@const MD_MD5 MD5模式,用于签名和验签
- { "MD_MD5", ROREG_INT(MBEDTLS_MD_MD5)},
- //@const MD_SHA1 SHA1模式,用于签名和验签
- { "MD_SHA1", ROREG_INT(MBEDTLS_MD_SHA1)},
- //@const MD_SHA224 SHA224模式,用于签名和验签
- { "MD_SHA224", ROREG_INT(MBEDTLS_MD_SHA224)},
- //@const MD_SHA256 SHA256模式,用于签名和验签
- { "MD_SHA256", ROREG_INT(MBEDTLS_MD_SHA256)},
- { NULL, ROREG_INT(0) }
- };
- LUAMOD_API int luaopen_rsa( lua_State *L ) {
- luat_newlib2(L, reg_rsa);
- return 1;
- }
|