当前位置 : 主页 > 网络编程 > lua >

lua ffi.string

来源:互联网 收集:自由互联 发布时间:2021-06-23
缘起 使用ffi给lua包一个rsa算法, 刚刚学习ffi,连文档都没仔细看过,当返回加密结果时,如果直接返回CDATA,则解密没有问题,如果转为lua string(使用ffi.string) ,则后续无法解密 调

缘起

使用ffi给lua包一个rsa算法, 刚刚学习ffi,连文档都没仔细看过,当返回加密结果时,如果直接返回CDATA,则解密没有问题,如果转为lua string(使用ffi.string) ,则后续无法解密

调试

  1. 直接在lua中调试基本无法凑效
  2. 重新编译openssl的libcrypt库,加入调试信息,先是祭出gdb,调的晕乎乎的;然后,则可以地方修改C代码,打印调试信息
  3. 发现,使用ffi.string 和不使用ffi.string 的差别在于,字符串的前面一部分是相同的,后面一部分是不同的,出于对零字节的敏感,发现是从零字节之后开始不同的;猜测ffi.string()或许可以有第二个参数(悲催,因为给一个参数也好使过,所以再没看过文档)
  4. 查ffi的文档,发现ffi.string()是有第二个参数的,添加第二个参数,问题解决
  5. 这个花费了我大约2天的时间,欲哭无泪

结论

  1. ffi.string(cdata, len) 是有第二个参数的,如果不写第二个参数,则从第一个零字节处截断
  2. 学习要循序渐进,文档是要看的

成果

local ffi = require("ffi")
local Rsa = ffi.load("crypto")
 
ffi.cdef[[
typedef struct rsa_st RSA;
typedef struct bio_st BIO;
typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata);
 
int RSA_public_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa,int padding);
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);
int RSA_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa,int padding);
 
BIO *BIO_new_mem_buf(void *buf, int len);
RSA *PEM_read_bio_RSA_PUBKEY(BIO *bp, RSA **x, pem_password_cb *cb, void *u);
RSA *PEM_read_bio_RSAPrivateKey(BIO *bp, RSA **x, pem_password_cb *cb, void *u);
int RSA_size(const RSA *r);
 
]]
 
 
local RSA_PKCS1_PADDING = 1;
 
local function init_public_key(pem_key)
	local bio = Rsa.BIO_new_mem_buf(ffi.cast("unsigned char *", pem_key), -1)
	local rsa = Rsa.PEM_read_bio_RSA_PUBKEY(bio, nil, nil, nil);
	if rsa == nil then
		return nil, "parse public key fail"
	end
	return rsa, nil
end
local function init_private_key(pem_key)
	local bio = Rsa.BIO_new_mem_buf(ffi.cast("unsigned char *", pem_key), -1)
	local rsa = Rsa.PEM_read_bio_RSAPrivateKey(bio, nil, nil, nil);
	if rsa == nil then
		return nil, "parse public key fail"
	end
	return rsa, nil
end
local function public_decrypt(key, data)
	local rsa, err = init_public_key(key)
	if err ~= nil then
		return nil, err
	end
	local size = tonumber(Rsa.RSA_size(rsa))
	local decrypted = ffi.new("unsigned char[?]", size)
	data = ffi.cast("const unsigned char *" ,data)
	print("string len"..string.len(ffi.string(data)))
	local len = Rsa.RSA_public_decrypt(size, data, decrypted, rsa, RSA_PKCS1_PADDING)
	return ffi.string(decrypted, len),len
end
 
local function private_encrypt(key, data)
	local rsa, err = init_private_key(key)
	if err ~= nil then
		return nil, err
	end
	local size = tonumber(Rsa.RSA_size(rsa))
	local encrypted = ffi.new("unsigned char[?]", size)
	local len = Rsa.RSA_private_encrypt(#data, data, encrypted, rsa, RSA_PKCS1_PADDING)
	return ffi.string(encrypted, len),len
end
网友评论