如何在openssl中导入外部rsa公钥

如何在openssl中导入外部rsa公钥,openssl,rsa,Openssl,Rsa,我希望通过从外部服务器接收的RSA公钥文件执行诸如RSA签名验证之类的操作。 键值以der格式或pem格式给出,如下所示 der:"30820122300d06092a864886f70d01010105000382010f003082010a02820101008ab8c549138cc59f605b50265f69ec3b8ce3b3e9af5e174d26cfe242650104bea05101189676c7a292cc6b5ae719e119e3ac29e9d3ad9dadcda496

我希望通过从外部服务器接收的RSA公钥文件执行诸如RSA签名验证之类的操作。 键值以der格式或pem格式给出,如下所示

der:"30820122300d06092a864886f70d01010105000382010f003082010a02820101008ab8c549138cc59f605b50265f69ec3b8ce3b3e9af5e174d26cfe242650104bea05101189676c7a292cc6b5ae719e119e3ac29e9d3ad9dadcda496f2f7185f9c0c4872a2db124f01992b238e83fd582d8a290f2973f9cf744f1e53f8aa53a225c12299b1cc3658fb607cb5aba579832d6c2687f71300a4df3df1c1407e17d22a5c19c830ed0c5824072309a612bb3e4fb339f25bbbcfe2999f4342110649abac5f4bfea2a59cd38c173979a679afdc8baacb4e87eb50acf806cfb7407504bdac110cfbcb99c04227031e146b9f3b8377c87035690309fae9872e2c7b93e8375fccdebc4f98be1d574269c513a43594f6b8861f7464832ae99ebaceae0fcc3ac50203010001"

pem_base64:"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAirjFSROMxZ9gW1AmX2nsO4zjs+mvXhdNJs/iQmUBBL6gUQEYlnbHopLMa1rnGeEZ46wp6dOtna3NpJby9xhfnAxIcqLbEk8BmSsjjoP9WC2KKQ8pc/nPdE8eU/iqU6IlwSKZscw2WPtgfLWrpXmDLWwmh/cTAKTfPfHBQH4X0ipcGcgw7QxYJAcjCaYSuz5PsznyW7vP4pmfQ0IRBkmrrF9L/qKlnNOMFzl5pnmv3Iuqy06H61Cs+AbPt0B1BL2sEQz7y5nAQicDHhRrnzuDd8hwNWkDCfrphy4se5PoN1/M3rxPmL4dV0JpxROkNZT2uIYfdGSDKumeus6uD8w6xQIDAQAB"
我想将上述数据导入struct 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);
==========================================================
在这种情况下,在d2i_中,公钥函数返回空指针。 我不知道出了什么问题

我不知道如何将pem_base64接收的字符串数据也更改为struct rsa_st*rsa。 示例代码使用了一个名为ReadPublicKey的函数,该函数似乎加载了一个X.509证书文件

我不读取文件,但我需要像上面那样从服务器获取数据


请回答知情人士。

您的数据不仅是PKCS1定义的RSA公钥,而且是X.509定义的X.509 SubjectPublicKeyInfo,包含PKCS1定义的RSA公钥。OpenSSL调用这个X.509结构PUBKEY。使用

此外:

你发布的代码没有显示buf_len来自哪里。确保它是正确的

您发布的代码将pArr设置为指向malloc'ed空格,然后将&pArr作为ppin传递给d2i例程。d2i例程更改了ppin指向的指针,因此它不再指向malloc’ed空间。如果您现在尝试freepArr,根据C标准,这是一种未定义的行为,实际上可能会崩溃或损坏堆,并导致其他看似无关的事情出错或失败;如果你不释放它,那就是内存泄漏

PEM格式不仅仅是DER的base64。它是DER的base64,分为以行终止符终止的行,添加了标题行和尾行破折号、开始/结束、类型、破折号;这些是格式的一部分,不是可选的。可以选择822样式的头块,但此处不适用。DER的Base64可能有用,但它不是PEM

梅塔:请在你的问题中添加更多关于你的问题的信息。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(&quot;error : failed d2i_RSAPublicKey \n&quot;); 
                return -1; 
        } 

        BN_print(STDout,pub_rsa->n);   // print modulus bignum 
        BN_print(STDout,pub_rsa->e);  //  print exponent bignum 

        return 0; 
} 
因为你没有放置任何分隔符,你必须知道每个部分的长度才能正确阅读

但是,这在OpenSSL版本1.1.0或更高版本中不起作用。API已更改,因此您可以使用它,它是一个typedef ror结构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"
这是因为相邻的字符串文字是组合的,所以与

"ABC" "DEF" "GHI" 
"ABCDEFGHI"
并且不包含所需的任何线路终端。您需要在字符串值中至少放入LF字符,最好是CR和LF字符,这在C中只能通过使用转义序列\n和\r进行移植。尽管PEM规范要求使用CR LF,但OpenSSL将只使用LF。因此,您需要:

char raw_data[] = { "-----BEGIN PUBLIC KEY-----\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAirjFSROMxZ9gW1AmX2ns\n"
"O4zjs+mvXhdNJs/iQmUBBL6gUQEYlnbHopLMa1rnGeEZ46wp6dOtna3NpJby9xhf\n"
"nAxIcqLbEk8BmSsjjoP9WC2KKQ8pc/nPdE8eU/iqU6IlwSKZscw2WPtgfLWrpXmD\n"
"LWwmh/cTAKTfPfHBQH4X0ipcGcgw7QxYJAcjCaYSuz5PsznyW7vP4pmfQ0IRBkmr\n"
"rF9L/qKlnNOMFzl5pnmv3Iuqy06H61Cs+AbPt0B1BL2sEQz7y5nAQicDHhRrnzuD\n"
"d8hwNWkDCfrphy4se5PoN1/M3rxPmL4dV0JpxROkNZT2uIYfdGSDKumeus6uD8w6\n"
"xQIDAQAB\n"
"-----END PUBLIC KEY-----\n" };
或者不使用{}也一样,因为使用单个字符串文本初始化字符数组是由C作为特例处理的

接下来,您的代码尝试从十六进制转换此数据,与前一种情况相同-但PEM不是十六进制,因此即使在修复了上述十六进制例程之后,这也是完全错误的。该数据已采用PEM格式,因此您只需使用BIO_new_mem_bufraw_数据、strlenraw_数据,或者作为优化BIO_new_mem_bufraw_数据,-1即可为您完成strlen

最后,这与上面的问题相同:您调用PEM_read_bio_RSAPublicKey,但您拥有的数据不是PKCS1格式;取而代之的是叫PEM_read_bio_RSA_PUBKEY

同样,您的代码与这些更改一起工作


既然如此,我不想问您为什么不想使用命令行功能来实现这一点,即使这只需要一两秒钟,而不是几天。

我这样做的目的是在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(&quot;error : failed d2i_RSAPublicKey \n&quot;); 
                return -1; 
        } 

        BN_print(STDout,pub_rsa->n);   // print modulus bignum 
        BN_print(STDout,pub_rsa->e);  //  print exponent bignum 

        return 0; 
} 
之后,我编码如下

    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。 我想在上述两种情况下得到帮助。 同样,我想在RSA公钥中找到模和公指数。 我想用C代码实现它,而不是用shell命令


BR,

你确定你有公钥而不是x509公钥证书吗谢谢dave_thompson,我还有更多问题,所以我发布如下。这属于问题而不是答案。请参阅更新我的答案。