d2i_RSA_PUBKEY、d2i_RSAPrivateKey 和 d2i_RSAPublicKey returns 空

d2i_RSA_PUBKEY, d2i_RSAPrivateKey and d2i_RSAPublicKey returns NULL

我使用以下命令创建了一个 RSA 私钥:

 openssl genrsa -out keypair.pem 2048

我必须为这个项目使用 DER 编码的密钥 (PKCS#1),所以我从这个 PEM 编码的私钥文件生成了两个 DER 文件——一个带有私钥,另一个带有 public键。

openssl rsa -inform PEM -in keypair.pem -outform DER -pubout -out public.der

openssl rsa -inform PEM -in keypair.pem -outform DER -out private.der

在我的代码中,我将这两个文件的内容加载到 char* 变量中。

None 以下各项按预期工作:

d2i_RSA_PUBKEY(NULL, &public_key_bytes, public_key_length);

d2i_RSAPublicKey(NULL, &public_key_bytes, public_key_length);

d2i_RSAPrivateKey(NULL, &private_key_bytes, private_key_length);

我知道,因为他们所有人 return null。我还尝试了以下方法:

RSA * rsa = RSA_new();
d2i_RSA_PUBKEY(&rsa, &public_key_bytes, public_key_length);

RSA * rsa = RSA_new();
d2i_RSAPublicKey(&rsa, &public_key_bytes, public_key_length);

RSA * rsa = RSA_new();
d2i_RSAPrivateKey(&rsa, &private_key_bytes, private_key_length);

所有 return null 也是。

我的完整测试代码如下:

#include <stdio.h>
#include <stdlib.h>

#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/pem.h>

typedef struct
{
    int len;
    char * bytes;
} FileData;

static FileData readFileBytes(const char * name, int zero_ended)
{
    FILE * fl = fopen(name, "r");
    if (fl == NULL) return (FileData) { .len = 0, .bytes = NULL };
    fseek(fl, 0, SEEK_END);
    long len = ftell(fl);
    char * ret = malloc(len + (zero_ended ? 1 : 0));
    fseek(fl, 0, SEEK_SET);
    fread(ret, 1, len, fl);
    if (zero_ended) ret[len] = 0;
    fclose(fl);
    return (FileData) { .len = len, .bytes = ret };
}

int main()
{
    FileData private_key = readFileBytes("../private.der", 0);
    FileData public_key = readFileBytes("../public.der", 0);

    char* public_key_bytes = public_key.bytes;
    int public_key_length = public_key.len;

    char* private_key_bytes = private_key.bytes;
    int private_key_length = private_key.len;

    RSA * rsa;

    public_key_bytes = public_key.bytes;
    public_key_length = public_key.len;
    rsa = d2i_RSA_PUBKEY(NULL, &public_key_bytes, public_key_length);
    printf("d2i_RSA_PUBKEY(NULL, &public_key_bytes, public_key_length) != NULL -> %s\n", (rsa != NULL) ? "true" : "false");

    public_key_bytes = public_key.bytes;
    public_key_length = public_key.len;
    rsa = d2i_RSAPublicKey(NULL, &public_key_bytes, public_key_length);
    printf("d2i_RSAPublicKey(NULL, &public_key_bytes, public_key_length) != NULL -> %s\n", (rsa != NULL) ? "true" : "false");

    private_key_bytes = private_key.bytes;
    private_key_length = private_key.len;
    rsa = d2i_RSAPrivateKey(NULL, &private_key_bytes, private_key_length);
    printf("d2i_RSAPrivateKey(NULL, &private_key_bytes, private_key_length) != NULL -> %s\n", (rsa != NULL) ? "true" : "false");

    public_key_bytes = public_key.bytes;
    public_key_length = public_key.len;
    rsa = RSA_new();
    rsa = d2i_RSA_PUBKEY(&rsa, &public_key_bytes, public_key_length);
    printf("d2i_RSA_PUBKEY(&rsa, &public_key_bytes, public_key_length) != NULL -> %s\n", (rsa != NULL) ? "true" : "false");

    public_key_bytes = public_key.bytes;
    public_key_length = public_key.len;
    rsa = RSA_new();
    rsa = d2i_RSAPublicKey(&rsa, &public_key_bytes, public_key_length);
    printf("d2i_RSAPublicKey(&rsa, &public_key_bytes, public_key_length) != NULL -> %s\n", (rsa != NULL) ? "true" : "false");

    private_key_bytes = private_key.bytes;
    private_key_length = private_key.len;
    rsa = RSA_new();
    rsa = d2i_RSAPrivateKey(&rsa, &private_key_bytes, private_key_length);
    printf("d2i_RSAPrivateKey(&rsa, &private_key_bytes, private_key_length) != NULL -> %s\n", (rsa != NULL) ? "true" : "false");

    getchar();

    return 0;
}

我做错了什么?

TLDRd2i_RSA_PUBKEYd2i_RSAPrivateKey 应该工作,并且在 Unix 上为我做。

你说你想要'DER-encoded keys (PKCS#1)'。

对于公钥,OpenSSL 通常使用 X.509 中定义的格式 SubjectPublicKeyInfo,其中包含 AlgorithmIdentifier plus(已编辑)BIT STRING包含结构中的公钥值,该结构因算法而异。对于 RSA,algid 包含一个标识 RSA 的 OID,没有参数;依赖于算法的结构是 PKCS#1。

相比之下,OpenSSL 支持两种类型的私钥格式:每种算法(DH 除外)都有一种 'legacy' 格式,RSA 为 PKCS#1;和由 PKCS#8 定义的通用格式,它像 SPKI 一样由 AlgorithmIdentifier 加上一个算法相关的私钥值组成,这次在 OCTET STRING 中。 PKCS#8 也有一个加密密钥的选项,这是 SPKI 没有或不需要的。

OpenSSL 的旧部分,包括 genrsarsa 命令行实用程序,使用旧的私钥格式,但 OpenSSL 命名为 PUBKEY 的 SPKI 公钥格式。因此,您的 rsa 命令创建了一个 d2i_RSA_PUBKEY 可读但 d2i_RSAPublicKey 不可读的公钥文件(这只是 PKCS#1 部分)和一个 d2i_RSAPrivateKey 可读的私钥文件。

如果您确实需要 'bare' PKCS#1 格式的公钥,rsa 实用程序从 1.0 开始就有选项 -RSAPublicKey_in-RSAPublicKey_out 来读写这种格式。 0,虽然最近才记录但仍未出现在帮助消息中。 d2i_RSAPublicKeyd2i_RSA_PUBKEY 无法读取该文件。

一种可能:你没有提到操作系统。 DER 文件是二进制文件,在 C 中要正确处理 Windows 上的 二进制文件,您必须 fopen 加上 b 修饰符,在这里您需要 "rb" 用于读取二进制文件。如果我 运行 你的代码在 Unix 上它可以工作,但要在 Windows 上获得正确的结果我必须添加 b.

还有一个小问题:你说的'loading contents ... in char* variables'。实际上,您将文件内容加载到内存中并使用 char * 变量指向它们。严格来说,OpenSSL d2i 例程需要 const unsigned char * 变量的地址——如果您在符合标准的模式下 运行 至少,您的编译器应该警告您这种不匹配。但是 C 需要指向所有 char 风格(signed unsigned 和 'plain')的指针,无论是否有限定,都具有相同的表示和对齐要求,即使它们不是t 与标准中定义的兼容,因此在预期 const unsigned char ** 的地方传递 char ** 确实有效。