spacewander/lua-resty-rsa

能不能搞个私钥加密,公钥解密的支持

Closed this issue · 3 comments

能不能搞个私钥加密,公钥解密的支持

同求

私钥加密,公钥解密可以通过下面的代码实现:

local ffi = require "ffi"
local ffi_new = ffi.new
local ffi_cast = ffi.cast
local ffi_gc = ffi.gc
local ffi_str = ffi.string
local C = ffi.C
local setmetatable = setmetatable


ffi.cdef[[
typedef struct bio_st BIO;
typedef struct bio_method_st BIO_METHOD;
BIO_METHOD *BIO_s_mem(void);
BIO * BIO_new(BIO_METHOD *type);
int	BIO_puts(BIO *bp,const char *buf);
void BIO_vfree(BIO *a);

typedef struct rsa_st RSA;
int RSA_size(const RSA *rsa);
void RSA_free(RSA *rsa);
typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata);
RSA * PEM_read_bio_RSAPrivateKey(BIO *bp, RSA **rsa, pem_password_cb *cb,
                                void *u);
RSA * PEM_read_bio_RSAPublicKey(BIO *bp, RSA **rsa, pem_password_cb *cb,
                                void *u);

int	RSA_private_encrypt(int flen, const unsigned char *from,
        unsigned char *to, RSA *rsa,int padding);
int	RSA_public_decrypt(int flen, const unsigned char *from,
        unsigned char *to, RSA *rsa,int padding);
unsigned long ERR_get_error(void);
const char * ERR_reason_error_string(unsigned long e);
]]


local function err()
    local code = C.ERR_get_error()

    local err_str = C.ERR_reason_error_string(code)

    return nil, ffi_str(err_str)
end

local  _M = {}
local mt = { __index = _M }

function _M.new(_, opts)
    local key
    local is_pub
    if opts.public_key then
        key = opts.public_key
        is_pub = true
    else
        key = opts.private_key
    end

    local bio_method = C.BIO_s_mem()
    local bio = C.BIO_new(bio_method)
    ffi_gc(bio, C.BIO_vfree)

    local len = C.BIO_puts(bio, key)
    if len < 0 then
        return err()
    end

    local func = is_pub and C.PEM_read_bio_RSAPublicKey
                        or C.PEM_read_bio_RSAPrivateKey

    local rsa = func(bio, nil, nil, nil)
    if ffi_cast("void *", rsa) == nil then
        return err()
    end
    ffi_gc(rsa, C.RSA_free)

    local size = C.RSA_size(rsa)
    return setmetatable({
            public_rsa = is_pub and rsa,
            private_rsa = (not is_pub) and rsa,
            buf = ffi_new("unsigned char[?]", size),
        }, mt)
end


function _M.decrypt_with_public_key(self, str)
    local rsa = self.public_rsa
    if not rsa then
        return nil, "not inited for decrypt"
    end

    local buf = self.buf
    local len = C.RSA_public_decrypt(#str, str, buf, rsa, 1)
    if len == -1 then
        return err()
    end

    return ffi_str(buf, len)
end


function _M.encrypt_with_private_key(self, str)
    local rsa = self.private_rsa
    if not rsa then
        return nil, "not inited for encrypt"
    end

    local buf = self.buf
    local len = C.RSA_private_encrypt(#str, str, buf, rsa, 1)
    if len == -1 then
        return err()
    end

    return ffi_str(buf, len)
end

-- 以下是调用示范
local RSA_PUBLIC_KEY = [[
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAJ9YqFCTlhnmTYNCezMfy7yb7xwAzRinXup1Zl51517rhJq8W0wVwNt+
mcKwRzisA1SIqPGlhiyDb2RJKc1cCNrVNfj7xxOKCIihkIsTIKXzDfeAqrm0bU80
BSjgjj6YUKZinUAACPoao8v+QFoRlXlsAy72mY7ipVnJqBd1AOPVAgMBAAE=
-----END RSA PUBLIC KEY-----
]]
local RSA_PRIV_KEY = [[
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCfWKhQk5YZ5k2DQnszH8u8m+8cAM0Yp17qdWZedede64SavFtM
FcDbfpnCsEc4rANUiKjxpYYsg29kSSnNXAja1TX4+8cTigiIoZCLEyCl8w33gKq5
tG1PNAUo4I4+mFCmYp1AAAj6GqPL/kBaEZV5bAMu9pmO4qVZyagXdQDj1QIDAQAB
AoGBAJega3lRFvHKPlP6vPTm+p2c3CiPcppVGXKNCD42f1XJUsNTHKUHxh6XF4U0
7HC27exQpkJbOZO99g89t3NccmcZPOCCz4aN0LcKv9oVZQz3Avz6aYreSESwLPqy
AgmJEvuVe/cdwkhjAvIcbwc4rnI3OBRHXmy2h3SmO0Gkx3D5AkEAyvTrrBxDCQeW
S4oI2pnalHyLi1apDI/Wn76oNKW/dQ36SPcqMLTzGmdfxViUhh19ySV5id8AddbE
/b72yQLCuwJBAMj97VFPInOwm2SaWm3tw60fbJOXxuWLC6ltEfqAMFcv94ZT/Vpg
nv93jkF9DLQC/CWHbjZbvtYTlzpevxYL8q8CQHiAKHkcopR2475f61fXJ1coBzYo
suAZesWHzpjLnDwkm2i9D1ix5vDTVaJ3MF/cnLVTwbChLcXJSVabDi1UrUcCQAmn
iNq6/mCoPw6aC3X0Uc3jEIgWZktoXmsI/jAWMDw/5ZfiOO06bui+iWrD4vRSoGH9
G2IpDgWic0Uuf+dDM6kCQF2/UbL6MZKDC4rVeFF3vJh7EScfmfssQ/eVEz637N06
2pzSvvB4xq6Gt9VwoGVNsn5r/K6AbT+rmewW57Jo7pg=
-----END RSA PRIVATE KEY-----
]]


local priv, err = _M:new({ private_key = RSA_PRIV_KEY })
if not priv then
    ngx.say("new rsa err: ", err)
    return
end
local encrypted, err = priv:encrypt_with_private_key("hello")
if not encrypted then
    ngx.say("failed to encrypt: ", err)
    return
end

local pub, err = _M:new({ public_key = RSA_PUBLIC_KEY })
if not pub then
    ngx.say("new rsa err: ", err)
    return
end
local decrypted = pub:decrypt_with_public_key(encrypted)
ngx.say(decrypted == "hello")

但是我没有把它放入 rsa 库的打算。因为私钥加密/公钥解密本身是有违最佳实践的,相对来说不够安全。参见这个 SO 回答:
https://crypto.stackexchange.com/a/2125

这个填充方式为什么只能是RSA_PKCS1_PADDING呢?