我想通过从外部服务器接收的 RSA 公钥文件执行 RSA 签名验证等操作。 键值以 der 格式或 pem 格式给出,如下所示。
der:"30820122300d06092a864886f70d01010105000382010f003082010a02820101008ab8c549138cc59f605b50265f69ec3b8ce3b3e9af5e174d26cfe242650104bea05101189676c7a292cc6b5ae719e119e3ac29e9d3ad9dadcda496f2f7185f9c0c4872a2db124f01992b238e83fd582d8a290f2973f9cf744f1e53f8aa53a225c12299b1cc3658fb607cb5aba579832d6c2687f71300a4df3df1c1407e17d22a5c19c830ed0c5824072309a612bb3e4fb339f25bbbcfe2999f4342110649abac5f4bfea2a59cd38c173979a679afdc8baacb4e87eb50acf806cfb7407504bdac110cfbcb99c04227031e146b9f3b8377c87035690309fae9872e2c7b93e8375fccdebc4f98be1d574269c513a43594f6b8861f7464832ae99ebaceae0fcc3ac50203010001"
pem_base64:"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAirjFSROMxZ9gW1AmX2nsO4zjs+mvXhdNJs/iQmUBBL6gUQEYlnbHopLMa1rnGeEZ46wp6dOtna3NpJby9xhfnAxIcqLbEk8BmSsjjoP9WC2KKQ8pc/nPdE8eU/iqU6IlwSKZscw2WPtgfLWrpXmDLWwmh/cTAKTfPfHBQH4X0ipcGcgw7QxYJAcjCaYSuz5PsznyW7vP4pmfQ0IRBkmrrF9L/qKlnNOMFzl5pnmv3Iuqy06H61Cs+AbPt0B1BL2sEQz7y5nAQicDHhRrnzuDd8hwNWkDCfrphy4se5PoN1/M3rxPmL4dV0JpxROkNZT2uIYfdGSDKumeus6uD8w6xQIDAQAB"
我想将上述数据导入"结构rsa_st * rsa">,但它不起作用。
例如,要以 der 格式导入 rsa 公钥,我执行以下操作:
==========================================================
char data[] = "30820122300d06092a864886f70d01010105000382010f003082010a02820101008ab8c549138cc59f605b50265f69ec3b8ce3b3e9af5e174d26cfe242650104bea05101189676c7a292cc6b5ae719e119e3ac29e9d3ad9dadcda496f2f7185f9c0c4872a2db124f01992b238e83fd582d8a290f2973f9cf744f1e53f8aa53a225c12299b1cc3658fb607cb5aba579832d6c2687f71300a4df3df1c1407e17d22a5c19c830ed0c5824072309a612bb3e4fb339f25bbbcfe2999f4342110649abac5f4bfea2a59cd38c173979a679afdc8baacb4e87eb50acf806cfb7407504bdac110cfbcb99c04227031e146b9f3b8377c87035690309fae9872e2c7b93e8375fccdebc4f98be1d574269c513a43594f6b8861f7464832ae99ebaceae0fcc3ac50203010001";
unsigned char * pArr = (unsigned char *)malloc(buf_len);
RSA *pub_rsa = NULL;
fnStr2Hex(pArr, data); // Converts a data array composed of strings to a hex array (pArr).
pub_rsa=d2i_RSAPublicKey(NULL,&pArr,(long)buf_len);
==========================================================
在这种情况下,Ind2i_RSAPublicKey函数返回 NULL 指针。 我不知道出了什么问题。
而且我不知道如何将pem_base64收到的字符串数据更改为"结构rsa_st * rsa"。示例代码使用一个名为"ReadPublicKey">的函数,该函数似乎加载了一个 X.509 证书文件。
我不读取文件,但我需要像上面一样从服务器获取数据。
请回答知道此事的人。
您的数据不是(只是)由 PKCS1 定义的 RSA 公钥重新发布为RFC8017,而是由 X.509 定义的 X.509 SubjectPublicKeyInfo,重新发布为包含RFC3279 定义的 RSA 公钥的RFC5280。OpenSSL 将此 X.509 结构称为 PUBKEY。使用d2i_RSA_PUBKEY。
也:
您发布的代码不会显示
buf_len
的来源。确保它是正确的。您发布的代码
pArr
设置为指向 malloc'ed 空间,然后将&pArr
作为ppin
传递给d2i
例程。d2i
例程更改ppin
指向的指针,因此它不再指向错误定位的空间。如果您现在尝试free(pArr)
根据 C 标准,它是未定义的行为,并且在实践中可能会崩溃或损坏您的堆,并导致其他看似无关的事情出错或失败;如果您不free
它,那就是内存泄漏。PEM 格式不仅仅是 DER 的 base64。它是 DER 的 base64,分为由行终止符终止的行,添加了标题和尾部行(破折号、开始/结束、类型、破折号);这些是格式的一部分,不是可选的。可以选择使用 822 样式的标头块,但这不适用于此处。DER的Base64可能很有用,但它不是PEM。
Meta:请在您的问题中添加有关您的问题的其他信息。Stackexchange旨在将问题包含在问题中,将答案放在答案中,以及其他原因,因为答案没有按时间顺序保存。我以为有一个关于这个的帮助中心页面,但如果是这样,我现在找不到它。
无论如何,你说你的"当前"代码是:
void fnStr2Hex(char* out, char* in) {
int data_len = strlen(in);
char * pStr = in;
int i;
for(i=0; i<data_len/2; i++) {
char buf[3] = {0,};
memcpy(buf, pStr, sizeof(buf));
out[i] = (unsigned char)strtol(buf, NULL, 16);
// need to check strol 2nd arguments... for error checking..
printf("i:%d, pArr[i]:%02X n", i, out[i]);
pStr+=2;
}
}
int main() {
char raw_data[] =
"30819F300D06092A864886F70D010101050003818D0030818902818100AA18ABA43B50DEEF38598FAF87D2AB634E4571C130A9BCA7B878267414FAAB8B471BD8965F5C9FC3818485EAF529C26246F3055064A8DE19C8C338BE5496CBAEB059DC0B358143B44A35449EB264113121A455BD7FDE3FAC919E94B56FB9BB4F651CDB23EAD439D6CD523EB08191E75B35FD13A7419B3090F24787BD4F4E19670203010001";
int data_len = strlen(raw_data);
unsigned char * pArr = (unsigned char *)malloc(data_len);
memset(pArr, 0x00, data_len);
// raw_data is a string. Not in hex state. So I changed the contents of
raw_data [] to hex in pArr.
// The implementation of this function is above main function.
fnStr2Hex(pArr, raw_data);
STDout=BIO_new_fp(stdout,BIO_NOCLOSE);
pub_rsa=d2i_RSAPublicKey(NULL,&pArr,(long)data_len);
if(pub_rsa == NULL) {
printf("error : failed d2i_RSAPublicKey n");
return -1;
}
BN_print(STDout,pub_rsa->n); // print modulus bignum
BN_print(STDout,pub_rsa->e); // print exponent bignum
return 0;
}
这是不可编译的;它有一个损坏的注释,没有声明STDout
和pub_rsa
,也没有所需的#include
。 修复这些问题会留下以下问题:
(大)您的十六进制转换是错误的。它一次从十六进制字符串复制 3 个字符,因此虽然转换后的字节应该是十六进制 30 81 9F 等,但它实际上是在我的系统(可能大多数)08 19 F3 等上计算的,这是完全错误的。由于它访问任何有效对象之外的至少一个字节,因此理论上它可以做得更糟。如果你看一下,你的"检查"
printf
会告诉你这一点。(小)你的分配是错误的。首先,在 C 中永远不需要强制转换
malloc
(或realloc
或calloc
)的返回值,有时(但不是在这里)有害的;请参阅 comp.lang.c 常见问题解答。其次,尽管十六进制字符串是 324 个字符(加上终止 null),但您只需要 162 个字节即可包含解码结果(也由您的"检查"printf
显示)。但是,由于d2i
忽略了多余的尾随数据,因此不会造成任何伤害。另外,您仍然有我之前描述的释放它的问题。(大)正如我之前所说,
d2i_RSAPublicKey
是错误的例程;它需要一种你没有的特定数据格式(PKCS1)。此数据的正确例程是d2i_RSA_PUBKEY
。(小)您的错误处理很差。当OpenSSL例程返回故障指示时,在几乎所有情况下,它还会将详细的错误信息存储在"错误队列"中。显示此信息的最简单方法是使用
ERR_print_errors_fp
尽管如果您愿意,还有更复杂的方法。为了获得最佳结果,您需要事先加载错误字符串,通常是通过ERR_load_crypto_strings
或 1.1.0+OPENSSL_init_crypto
或其中之一的变体加载错误字符串,这些变体也涵盖 SSL(您当前未使用也不需要)。尽管在这种情况下,在修复d2i_RSAPublicKey
之前,错误队列会为您提供 ASN.1 解码例程的内部描述,无论如何您都可能无法理解 - 尽管它至少可能为您指明了查看 ASN.1 格式的方向。
具有这些修复的代码确实可以正确打印十六进制的模数和指数:
AA18ABA43B50DEEF38598FAF87D2AB634E4571C130A9BCA7B878267414FAAB8B471BD8965F5C9FC3818485EAF529C26246F3055064A8DE19C8C338BE5496CBAEB059DC0B358143B44A35449EB264113121A455BD7FDE3FAC919E94B56FB9BB4F651CDB23EAD439D6CD523EB08191E75B35FD13A7419B3090F24787BD4F4E196710001
由于您没有放置任何分隔符,因此您必须知道每个部分的长度才能正确阅读。
但是,这在 OpenSSL 版本 1.1.0 或更高版本中不起作用。API 已更改,因此您无法再直接访问RSA
中的n
和e
等字段(这是一个 typedef rorstruct rsa_st
)。
然后,您可以为 PEM 格式提出以下建议:
raw_data[] = {
"-----BEGIN PUBLIC KEY-----"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAirjFSROMxZ9gW1AmX2ns"
"O4zjs+mvXhdNJs/iQmUBBL6gUQEYlnbHopLMa1rnGeEZ46wp6dOtna3NpJby9xhf"
"nAxIcqLbEk8BmSsjjoP9WC2KKQ8pc/nPdE8eU/iqU6IlwSKZscw2WPtgfLWrpXmD"
"LWwmh/cTAKTfPfHBQH4X0ipcGcgw7QxYJAcjCaYSuz5PsznyW7vP4pmfQ0IRBkmr"
"rF9L/qKlnNOMFzl5pnmv3Iuqy06H61Cs+AbPt0B1BL2sEQz7y5nAQicDHhRrnzuD"
"d8hwNWkDCfrphy4se5PoN1/M3rxPmL4dV0JpxROkNZT2uIYfdGSDKumeus6uD8w6"
"xQIDAQAB"
"-----END PUBLIC KEY----- " };
这也是错误的。除了缺少数据类型(正式声明说明符)char
之外,预处理器换行语法
"ABC"
"DEF"
"GHI"
完全等同于
"ABC" "DEF" "GHI"
因为相邻的字符串文字被组合在一起,所以完全等效于
"ABCDEFGHI"
并且不包含所需的任何行终止符。您需要在字符串值中至少放置 LF 字符,理想情况下是 CR 和 LF 字符,这在 C 中只能通过使用转义序列n
和r
来移植完成。(尽管PEM规范要求CR LF,但OpenSSL仅适用于LF。因此,您需要:
char raw_data[] = { "-----BEGIN PUBLIC KEY-----n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAirjFSROMxZ9gW1AmX2nsn"
"O4zjs+mvXhdNJs/iQmUBBL6gUQEYlnbHopLMa1rnGeEZ46wp6dOtna3NpJby9xhfn"
"nAxIcqLbEk8BmSsjjoP9WC2KKQ8pc/nPdE8eU/iqU6IlwSKZscw2WPtgfLWrpXmDn"
"LWwmh/cTAKTfPfHBQH4X0ipcGcgw7QxYJAcjCaYSuz5PsznyW7vP4pmfQ0IRBkmrn"
"rF9L/qKlnNOMFzl5pnmv3Iuqy06H61Cs+AbPt0B1BL2sEQz7y5nAQicDHhRrnzuDn"
"d8hwNWkDCfrphy4se5PoN1/M3rxPmL4dV0JpxROkNZT2uIYfdGSDKumeus6uD8w6n"
"xQIDAQABn"
"-----END PUBLIC KEY-----n" };
(或者没有{ }
相同,因为使用单个字符串文本初始化字符数组由 C 作为特殊情况处理)。
接下来,您的代码尝试从十六进制转换此数据,与前一种情况相同 - 但 PEM不是十六进制,因此即使在如上所述修复十六进制例程后,这也是完全错误的。此数据已经采用 PEM 格式,因此您应该简单地使用BIO_new_mem_buf(raw_data, strlen(raw_data))
- 或作为为您执行strlen
的优化BIO_new_mem_buf(raw_data,-1)
。
最后,这具有与上述相同的问题:您调用PEM_read_bio_RSAPublicKey
但您拥有的数据不是 PKCS1 格式;而是调用PEM_read_bio_RSA_PUBKEY
。
同样,具有这些更改的代码可以正常工作。
由于这是SO,我不问你为什么不想为此使用命令行功能 - 即使它只需要一两秒钟,而不是几天。
我这样做的目的是在 RSA 中找到模数和指数 公钥。 我的示例代码和当前结果如下所示。
====
=============================================================void fnStr2Hex(char* out, char* in) {
int data_len = strlen(in);
char * pStr = in;
int i;
for(i=0; i<data_len/2; i++) {
char buf[3] = {0,};
memcpy(buf, pStr, sizeof(buf));
out[i] = (unsigned char)strtol(buf, NULL, 16);
// need to check strol 2nd arguments... for error checking..
printf("i:%d, pArr[i]:%02X n", i, out[i]);
pStr+=2;
}
}
int main() {
char raw_data[] =
"30819F300D06092A864886F70D010101050003818D0030818902818100AA18ABA43B50DEEF38598FAF87D2AB634E4571C130A9BCA7B878267414FAAB8B471BD8965F5C9FC3818485EAF529C26246F3055064A8DE19C8C338BE5496CBAEB059DC0B358143B44A35449EB264113121A455BD7FDE3FAC919E94B56FB9BB4F651CDB23EAD439D6CD523EB08191E75B35FD13A7419B3090F24787BD4F4E19670203010001";
int data_len = strlen(raw_data);
unsigned char * pArr = (unsigned char *)malloc(data_len);
memset(pArr, 0x00, data_len);
// raw_data is a string. Not in hex state. So I changed the contents of
raw_data [] to hex in pArr.
// The implementation of this function is above main function.
fnStr2Hex(pArr, raw_data);
STDout=BIO_new_fp(stdout,BIO_NOCLOSE);
pub_rsa=d2i_RSAPublicKey(NULL,&pArr,(long)data_len);
if(pub_rsa == NULL) {
printf("error : failed d2i_RSAPublicKey n");
return -1;
}
BN_print(STDout,pub_rsa->n); // print modulus bignum
BN_print(STDout,pub_rsa->e); // print exponent bignum
return 0;
}
结果 : 错误 : 失败d2i_RSAPublicKey 我不知道它为什么会失败。
你说你需要前缀和后缀来做PEM格式。 如下所示的配置是否正确?
raw_data[] = {
"-----BEGIN PUBLIC KEY-----"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAirjFSROMxZ9gW1AmX2ns"
"O4zjs+mvXhdNJs/iQmUBBL6gUQEYlnbHopLMa1rnGeEZ46wp6dOtna3NpJby9xhf"
"nAxIcqLbEk8BmSsjjoP9WC2KKQ8pc/nPdE8eU/iqU6IlwSKZscw2WPtgfLWrpXmD"
"LWwmh/cTAKTfPfHBQH4X0ipcGcgw7QxYJAcjCaYSuz5PsznyW7vP4pmfQ0IRBkmr"
"rF9L/qKlnNOMFzl5pnmv3Iuqy06H61Cs+AbPt0B1BL2sEQz7y5nAQicDHhRrnzuD"
"d8hwNWkDCfrphy4se5PoN1/M3rxPmL4dV0JpxROkNZT2uIYfdGSDKumeus6uD8w6"
"xQIDAQAB"
"-----END PUBLIC KEY----- " };
之后,我编码如下。
int data_len = strlen(raw_data);
BIO *bufio = NULL;
RSA *pub_rsa = NULL;
unsigned char * pArr = (unsigned char *)malloc(data_len);
memset(pArr, 0x00, data_len);
fnStr2Hex(pArr, raw_data); // for converting hex
bufio = BIO_new_mem_buf((void*)pArr, data_len);
if(bufio == NULL) {
printf("Error (1) n");
return -1;
}
PEM_read_bio_RSAPublicKey(bufio, &pub_rsa, 0, NULL);
if(pub_rsa == NULL) {
printf("Error (2) n");
return -1;
}
} // end of main
当我执行上面的代码时,输出错误 (2)。 我希望在上述两种(DER,PEM)情况下得到帮助。 同样,我想在 RSA 公钥中找到模数和公共指数。 (我想用 C 代码实现它,而不是在 shell 命令中实现它。
溴,