如何使用 OpenSSL 3 在 C 中执行公钥 RSA 数据加密

问题描述 投票:0回答:1

我对 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;
    }
c openssl rsa public-key
1个回答
0
投票

首先,像

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 的倍数;从那时起,限制已经增加,但它仍然不是无限的,也没有记录我发现),并且不能保证嵌入空格,尽管有些有时可能有效。

© www.soinside.com 2019 - 2024. All rights reserved.