我对 C 比较陌生,我正在尝试用 C 加密字符串数据。
我已经获得了一个有点像的公钥
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1WRkqlsZbmaNWbOZr/M4
.
.
.
EKseLc8iKzkwEQcuyMn4znaFpnOL0CmSrYB5K1E9zmmtDhMvDs540ZotcH/xpJiV BwIDAQAB
-----END PUBLIC KEY-----
以及我试图在 Typescript 中实现的目标的示例表示
rsaEncrypt(text: string, publicKey: string): Promise<string> {
const buffer = Buffer.from(JSON.stringify(text));
const encrypted = publicEncrypt(
{
key: publicKey,
padding: constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha1',
},
buffer,
);
return encrypted.toString('base64');
}
这是我的实现,但是,在 PEM_read_bio_RSA_PUBKEY 之后我的 rsa 始终为 NULL
int rsa_encrypt(const unsigned char *msg, size_t msg_len, unsigned char **enc_msg, size_t *enc_msg_len) {
RSA *rsa = NULL;
BIO *bio = NULL;
int ret = -1;
tappa_print("%s", "In rsa_enc");
tappa_print("%s", PUBLIC_KEY);
bio = BIO_new_mem_buf(PUBLIC_KEY, -1);
tappa_printf("Bio %d", BIO_get_init(bio));
if (bio == NULL) {
fprintf(stderr, "Error creating bio\n");
return -1;
}
rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
tappa_printf("RSA %d", rsa==NULL);
if (rsa == NULL) {
ERR_print_errors_fp(stderr);
tappa_print("%s", strerror(errno));
fprintf(stderr, "Error reading public key\n");
//BIO_free(bio);
return -1;
}
tappa_printf("RSA %d", RSA_size(rsa));
*enc_msg = (unsigned char *)malloc(RSA_size(rsa));
tappa_printf("Enc msg %d", sizeof *enc_msg);
if (*enc_msg == NULL) {
fprintf(stderr, "Memory allocation error\n");
RSA_free(rsa);
BIO_free(bio);
return -1;
}
*enc_msg_len = RSA_public_encrypt(msg_len, msg, *enc_msg, rsa, RSA_PKCS1_PADDING);
tappa_printf("Enc msg len%d", sizeof *enc_msg_len);
if (*enc_msg_len == -1) {
fprintf(stderr, "Encryption error\n");
free(*enc_msg);
RSA_free(rsa);
BIO_free(bio);
return -1;
}
ret = 0;
tappa_printf("ret msg %d", ret);
RSA_free(rsa);
BIO_free(bio);
return ret;
}
我尝试了在互联网上看到的另一种方法,从文件中读取密钥,但是,将文件添加到我的项目后,我遇到了“没有这样的文件/目录”错误
FILE* fp =fopen("public.txt","r");
if(fp==NULL){
perror("file error");
return NULL;
}
首先,像
RSA_public_encrypt
这样的低级(即特定于算法的)API 在 OpenSSL 3 中已被弃用(至少从 1.1.0 起大部分已弃用)。虽然还没有被删除。
其次,你的“typescript”(我假设实际上是nodejs)代码正在使用RSA-OAEP进行加密,而OpenSSL
RSA_public_encrypt
没有——也不能;它是在 SSLeay 的最早版本中设置的,早在 PKCS1v2.0 发布之前,甚至可能早于 Bleichenbacher 的基础工作,尽管我必须努力确认这一点。尽管 RSAES-PKCS1-v1_5(又名“类型 2”)和 RSAES-OAEP 均采用较新版本的 PKCS1,并且可以用普通语言描述为 PKCS1 算法(或填充),但标识符 RSA_PKCS1_PADDING
表示仅 v1_5 而不是 OAEP .
第三,
errno
的值仅对 some C-stdlib 调用有用(主要是那些涉及操作系统调用的调用);在 mem_BIO 上执行失败的操作后,它是无关紧要且无用的。
第四,
sizeof *enc_msg
,其中enc_msg
是unsigned char **
,是指针的大小,今天通常是固定值8,而不是它指向的malloc数据的大小,这可能就是你想要的。同样,现在 sizeof *enc_msg_len
上的 size_t *
是固定值,通常为 8,而不是 RSA 密文的大小。另外,如果您的 tappa_printf
使用与 stdio {,v}{,f,s}printf
相同的说明符,则 %d
实际上对于 size_t
来说并不正确,尽管在许多平台上它会“意外”工作。 %zu
有保证。
总而言之,您的代码对我有用,只要有一个实际上是PEM格式的公钥,以及一条有效的(即小)消息。你只发布“类似于”你的公钥的东西,所以我不能确定它有什么问题,但它肯定必须在 BEGIN 行和正文之间以及正文和 END 行之间有换行符(在 C 中,换行符) ,它可能需要在主体内有换行符(实际 PEM 需要每 64 个换行符,低于 1.1.0 的 OpenSSL 需要每 76 个或更少,但为 4 的倍数;从那时起,限制已经增加,但它仍然不是无限的,也没有记录我发现),并且不能保证嵌入空格,尽管有些有时可能有效。