- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我使用以下命令创建了一个 RSA 私钥:
openssl genrsa -out keypair.pem 2048
我必须为此项目使用 DER 编码的 key (PKCS#1),因此我从这个 PEM 编码的私钥文件生成了两个 DER 文件 - 一个带有私钥,另一个带有公钥。
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* 变量中。
以下均未按预期工作:
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);
我知道,因为它们都返回 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);
所有返回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;
}
我做错了什么?
最佳答案
TLDR:d2i_RSA_PUBKEY
和 d2i_RSAPrivateKey
应该可以工作,并且在 Unix 上为我做。
您说您想要“DER 编码 key (PKCS#1)”。
对于公钥,OpenSSL 通常使用 X.509 中定义的格式作为 SubjectPublicKeyInfo
,其中包含一个 AlgorithmIdentifier
plus(已编辑)BIT STRING
包含结构中的公钥值,该结构因算法而异。对于 RSA,algid 包含一个标识 RSA 的 OID,没有参数;依赖于算法的结构是 PKCS#1。
相比之下,OpenSSL 支持两种类型的私钥格式:每种算法(DH 除外)都有一种“传统”格式,对于 RSA 是 PKCS#1;和由 PKCS#8 定义的通用格式,它像 SPKI 一样由 AlgorithmIdentifier
加上一个算法相关的私钥值组成,这次在 OCTET STRING
中。 PKCS#8 还有一个加密 key 的选项,SPKI 没有也不需要。
OpenSSL 的旧部分,包括 genrsa
和 rsa
命令行实用程序,使用传统的私钥格式,但 OpenSSL 命名为 PUBKEY 的 SPKI 公钥格式。因此,您的 rsa
命令创建了一个 publickey 文件,可由 d2i_RSA_PUBKEY
读取,但 d2i_RSAPublicKey
不可读(这只是 PKCS#1 部分)和一个 privatekey 文件可由 d2i_RSAPrivateKey
读取。
如果您确实需要“裸”PKCS#1 格式的公钥,rsa
实用程序有选项 -RSAPublicKey_in
和 -RSAPublicKey_out
来读取并从 1.0.0 开始编写这种格式,尽管最近才记录并且仍然不在帮助消息中。 d2i_RSAPublicKey
可读取该文件,但 d2i_RSA_PUBKEY
不可读取。
一种可能性:您没有提到操作系统。 DER 文件是二进制文件,在 C 中要正确处理 Windows 上的二进制文件,您必须使用 b
修饰符来 fopen
,在这里您需要 "rb"
用于读取二进制文件。如果我在 Unix 上运行您的代码,它可以工作,但要在 Windows 上获得正确的结果,我必须添加 b
。
还有一个小问题:你谈到“加载内容......在 char* 变量中”。实际上,您将文件内容加载到内存中并使用 char *
变量指向它们。严格来说,OpenSSL d2i
例程需要 const unsigned char *
变量的地址——如果您在标准中运行它,您的编译器至少应该警告您这种不匹配-符合模式。但是 C 需要指向所有 char
风格(signed
unsigned
和 'plain')的指针,无论是否有限定,都具有相同的表示和对齐方式要求,即使它们与标准中定义的不兼容,所以传递 char **
是预期的 const unsigned char **
确实有效。
关于c - d2i_RSA_PUBKEY、d2i_RSAPrivateKey 和 d2i_RSAPublicKey 返回 NULL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36801158/
我是一名优秀的程序员,十分优秀!