我必须处理一些与AIX相关的Openssl错误,并尝试编写一些Testcode。简而言之,我想在缓冲区中读取RSA密钥文件,而不是从缓冲区中取出数据来进行一些检查。当我运行Testprogram时,我总是收到“错误:RSA为NULL”,这意味着缓冲区为空。
我使用以下命令行创建了Testkey:
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -outform DER -out testprivate_key.pem
openssl rsa -in testprivate_key.pem -inform DER -outform DER -pubout -out testpublic_key.pem
我必须承认我对Openssl编程没有真正的了解,因此非常欢迎任何提示。
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <openssl/pem.h>
#include <openssl/err.h> /* ERR_* */
#include <openssl/rand.h> /* RAND_* */
#include <openssl/bn.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
unsigned char buf[1024*10];
/* const char keyfiles[][32] = { "testpublic_key32.pem", "testpublic_key64.pem" }; */
int get_buffer () {
RSA *pub_key = NULL;
/* FILE *key_file; */
/* key_file = fopen( keyfiles[0],"rt"); */
FILE *key_file = fopen("testpublic_key.pem","r"); // read in key file
if (!key_file)
{
printf("Failed to open key file\n");
exit(1);
}
pub_key = PEM_read_RSA_PUBKEY(key_file,&pub_key,NULL,NULL); // fill buffer
BIO *mem = BIO_new(BIO_s_mem());
RSA_print(mem,pub_key,0);
BIO_read(mem,buf,1024*10);
BUF_MEM *bio_buf=NULL;
BIO_get_mem_ptr(mem,&bio_buf);
RSA_free(pub_key);
BIO_free(mem);
}
int get_key(const unsigned char *buf, int len) {
RSA *rsa = d2i_RSA_PUBKEY(NULL, &buf, len); // get data from buffer and do some checks
if (rsa != NULL) {
if (rsa->e != NULL) {
printf("BN : <%s> (hex) -- <%s> (dec)\n", BN_bn2hex(rsa->e), BN_bn2dec(rsa->e));
if (BN_is_odd(rsa->e) == 0) {
printf("Error : RSA public exponent is even\n");
} else {
printf("RSA public exponent is OK.\n");
return 0;
}
}
RSA_free(rsa);
}
else {
printf("Error : RSA is NULL\n");
}
return 1;
}
int main() {
get_buffer();
return get_key(buf, sizeof buf);
}
编译字符串:
gcc -lcrypto -o openssl_odd_even openssl_odd_even.c
/home/packagebuilder/test/openssl_bignum_issue # ./openssl_odd_even
Error : RSA is NULL
答案 0 :(得分:2)
我不确定当您可以直接在RSA结构中直接引用已加载的密钥时,为什么要在某个基本缓冲区中扔掉密钥。但是,假设您有某些原因,让我们从基础知识入手,并说明整个过程。
通过CLI生成密钥
您可以以任意形式(PEM或DER)生成密钥对。对于我们来说,我们需要PEM,因此我们必须使用genpkey接口。如果我们想要DER,我们可以使用genrsa界面,这很容易。无论如何,语法看起来像这样。请注意以PEM格式生成输出的特定请求(从而使我们诚实地命名.pem文件):
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -outform PEM -out testprivate_key.pem
这应该生成testprivate_key.pem,如下所示:
-----BEGIN PRIVATE KEY-----
... base64 encoding of the key pair here ...
-----END PRIVATE KEY-----
接下来,我们需要该密钥对中的公共密钥。我们也可以使用openssl rsa CLI来获取该信息。
openssl rsa -in testprivate_key.pem -inform PEM -pubout -out testpublic_key.pem -outform PEM
这应该创建testpublic_key.pem,看起来应该像这样:
-----BEGIN PUBLIC KEY-----
... bas64 encoding of public key here ...
-----END PUBLIC KEY-----
这可以解决密钥文件的问题。进入代码。
从PEM编码的文件中读取RSA公钥
一旦有了文件,我们就可以使用openssl libcrypto(对于Windows为libeay32)将它们之一读入程序。这个简单的示例应用程序从当前工作目录中读取PEM编码的公钥,然后将其以DER形式存储在内存缓冲区中,然后使用BIO_dump
(非常来自bio api的便捷实用函数):
#include <stdio.h>
#include <stdlib.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
int main()
{
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
// read the PEM from disk (assumes current working directory)
FILE *fp = fopen("testpublic_key.pem", "r");
if (fp == NULL)
{
perror("testpublic_key.pem");
return EXIT_FAILURE;
}
// load from disk
RSA *pub_key = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
if (pub_key == NULL)
{
perror("Failed to load RSA public key from PEM file");
return EXIT_FAILURE;
}
// no longer need this
fclose(fp);
// from here we can use pub_key however we want. in this case we're
// goin ot store it in a memory buffer in DER form.
unsigned char buff[4*1024], *p = buff;
int len = i2d_RSA_PUBKEY(pub_key, &p);
if (len > 0)
{
// show the content of the buffer in the console using BIO-dump
BIO* bio = BIO_new_fp(stdout, BIO_NOCLOSE);
BIO_dump(bio, (const char*)buff, len);
BIO_flush(bio);
BIO_free(bio);
}
RSA_free(pub_key);
return EXIT_SUCCESS;
}
编译该文件并从我们先前创建的密钥文件所在的工作目录中运行,将为我们提供类似于以下的内容:
样本输出(显然会有所不同)
0000 - 30 82 01 22 30 0d 06 09-2a 86 48 86 f7 0d 01 01 0.."0...*.H.....
0010 - 01 05 00 03 82 01 0f 00-30 82 01 0a 02 82 01 01 ........0.......
0020 - 00 9c b5 e2 ff c0 1b e8-c1 4d cc bb 76 c1 8b d6 .........M..v...
0030 - eb b6 ec 92 a3 e3 38 82-50 16 13 3d 2c bc ef 49 ......8.P..=,..I
0040 - 21 3c d6 83 ae 4d be b7-d5 7c 67 11 84 a4 ed 4e !<...M...|g....N
0050 - 86 b4 c8 41 3e c4 70 e5-a1 cf 9d 13 26 6c bf f2 ...A>.p.....&l..
0060 - 5c 7e 4f 04 a6 0e e0 9d-90 55 87 67 e7 f8 58 62 \~O......U.g..Xb
0070 - a6 ff 85 a0 99 68 62 58-0b 02 66 74 3d f6 19 05 .....hbX..ft=...
0080 - 7d e3 51 fa b1 c2 db e2-f3 e8 fa f5 5f 36 95 67 }.Q........._6.g
0090 - cf 8f eb 32 7e 39 5d e1-37 30 57 5a 1d 25 9d fa ...2~9].70WZ.%..
00a0 - ad 50 63 f5 23 14 b2 2a-de 10 7d b8 7e 83 2b b9 .Pc.#..*..}.~.+.
00b0 - 8c 8b aa 73 7b 4a 91 be-68 5d d8 ad d0 76 e0 de ...s{J..h]...v..
00c0 - 15 bc c6 9a 77 f2 31 a9-11 e3 b7 83 ce ae e2 96 ....w.1.........
00d0 - 6b 9c 2b 20 b9 e5 d7 22-27 46 10 2b 91 5c a3 67 k.+ ..."'F.+.\.g
00e0 - 7e ea 8c d0 69 e1 06 0e-eb 1a a4 dd 22 b9 5e f8 ~...i.......".^.
00f0 - f1 8a db 73 86 57 f2 d5-d1 70 10 24 f7 08 1d 76 ...s.W...p.$...v
0100 - 14 2e de d0 47 95 ce ac-52 fc 4a 16 c5 19 29 cd ....G...R.J...).
0110 - 94 40 f2 23 4d 63 03 5f-10 8a 21 6b 5d 5a 3c 30 .@.#Mc._..!k]Z<0
0120 - 1d 02 03 01 00 01 ......
现在,您可以在get_key
函数中将此缓冲区与您的缓冲区一起使用,以检查密钥本身的各个部分(尽管您为什么不希望有任何线索,因为您已经知道了RSA*
早于从PEM加载时)。修改源以添加您的get_key
函数及其对公钥的检查为我们提供了这一点:
#include <stdio.h>
#include <stdlib.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
int get_key(const unsigned char *buf, int len)
{
int result = 1;
RSA *rsa = d2i_RSA_PUBKEY(NULL, &buf, len);
if (rsa != NULL)
{
if (rsa->e != NULL)
{
printf("BN : <%s> (hex) -- <%s> (dec)\n", BN_bn2hex(rsa->e), BN_bn2dec(rsa->e));
if (BN_is_odd(rsa->e) == 0)
{
printf("Error : RSA public exponent is even\n");
}
else
{
printf("RSA public exponent is OK.\n");
result = 0;
}
}
RSA_free(rsa);
}
else
{
printf("Error : RSA is NULL\n");
}
return result;
}
int main()
{
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
// read the PEM from disk (assumes current working directory)
FILE *fp = fopen("testpublic_key.pem", "r");
if (fp == NULL)
{
perror("testpublic_key.pem");
return EXIT_FAILURE;
}
// load from disk
RSA *pub_key = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
if (pub_key == NULL)
{
perror("Failed to load RSA public key from PEM file");
return EXIT_FAILURE;
}
// no longer need this
fclose(fp);
// from here we can use pub_key however we want. in this case we're
// goin ot store it in a memory buffer in DER form.
unsigned char buff[4*1024], *p = buff;
int len = i2d_RSA_PUBKEY(pub_key, &p);
if (len > 0)
{
// show the content of the buffer in the console using BIO-dump
BIO* bio = BIO_new_fp(stdout, BIO_NOCLOSE);
BIO_dump(bio, (const char*)buff, len);
BIO_flush(bio);
BIO_free(bio);
}
RSA_free(pub_key);
// run get_key
printf("get_key returned %d\n", get_key(buff, len));
return EXIT_SUCCESS;
}
输出
0000 - 30 82 01 22 30 0d 06 09-2a 86 48 86 f7 0d 01 01 0.."0...*.H.....
0010 - 01 05 00 03 82 01 0f 00-30 82 01 0a 02 82 01 01 ........0.......
0020 - 00 9c b5 e2 ff c0 1b e8-c1 4d cc bb 76 c1 8b d6 .........M..v...
0030 - eb b6 ec 92 a3 e3 38 82-50 16 13 3d 2c bc ef 49 ......8.P..=,..I
0040 - 21 3c d6 83 ae 4d be b7-d5 7c 67 11 84 a4 ed 4e !<...M...|g....N
0050 - 86 b4 c8 41 3e c4 70 e5-a1 cf 9d 13 26 6c bf f2 ...A>.p.....&l..
0060 - 5c 7e 4f 04 a6 0e e0 9d-90 55 87 67 e7 f8 58 62 \~O......U.g..Xb
0070 - a6 ff 85 a0 99 68 62 58-0b 02 66 74 3d f6 19 05 .....hbX..ft=...
0080 - 7d e3 51 fa b1 c2 db e2-f3 e8 fa f5 5f 36 95 67 }.Q........._6.g
0090 - cf 8f eb 32 7e 39 5d e1-37 30 57 5a 1d 25 9d fa ...2~9].70WZ.%..
00a0 - ad 50 63 f5 23 14 b2 2a-de 10 7d b8 7e 83 2b b9 .Pc.#..*..}.~.+.
00b0 - 8c 8b aa 73 7b 4a 91 be-68 5d d8 ad d0 76 e0 de ...s{J..h]...v..
00c0 - 15 bc c6 9a 77 f2 31 a9-11 e3 b7 83 ce ae e2 96 ....w.1.........
00d0 - 6b 9c 2b 20 b9 e5 d7 22-27 46 10 2b 91 5c a3 67 k.+ ..."'F.+.\.g
00e0 - 7e ea 8c d0 69 e1 06 0e-eb 1a a4 dd 22 b9 5e f8 ~...i.......".^.
00f0 - f1 8a db 73 86 57 f2 d5-d1 70 10 24 f7 08 1d 76 ...s.W...p.$...v
0100 - 14 2e de d0 47 95 ce ac-52 fc 4a 16 c5 19 29 cd ....G...R.J...).
0110 - 94 40 f2 23 4d 63 03 5f-10 8a 21 6b 5d 5a 3c 30 .@.#Mc._..!k]Z<0
0120 - 1d 02 03 01 00 01 ......
BN : <010001> (hex) -- <65537> (dec)
RSA public exponent is OK.
get_key returned 0
删除不需要的代码
现实是,您一开始并不需要该缓冲中间层,我希望这是显而易见的。只需从磁盘加载适当制作的PEM,然后使用由此产生的RSA*
来检查公用指数。结果就是这样:
#include <stdio.h>
#include <stdlib.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
int check_key_exponent(RSA *rsa)
{
int result = 1;
if (rsa && rsa->e)
{
printf("BN : <%s> (hex) -- <%s> (dec)\n", BN_bn2hex(rsa->e), BN_bn2dec(rsa->e));
if (BN_is_odd(rsa->e) == 0)
{
printf("Error : RSA public exponent is even\n");
}
else
{
printf("RSA public exponent is OK.\n");
result = 0;
}
}
else
{
printf("Error : RSA is NULL\n");
}
return result;
}
int main()
{
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
// read the PEM from disk (assumes current working directory)
FILE *fp = fopen("testpublic_key.pem", "r");
if (fp == NULL)
{
perror("testpublic_key.pem");
return EXIT_FAILURE;
}
// load from disk
RSA *pub_key = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
if (pub_key == NULL)
{
perror("Failed to load RSA public key from PEM file");
return EXIT_FAILURE;
}
// no longer need this
fclose(fp);
// run get_key
printf("check_key_exponent returned %d\n", check_key_exponent(pub_key));
RSA_free(pub_key);
return EXIT_SUCCESS;
}
输出
BN : <010001> (hex) -- <65537> (dec)
RSA public exponent is OK.
check_key_exponent returned 0