2015-06-03 139 views
3

假设我有这样的如何PEM公共密钥转换成OpenSSL的RSA *结构

-----BEGIN PUBLIC KEY----- 
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7vbqajDw4o6gJy8UtmIbkcpnk 
O3Kwc4qsEnSZp/TR+fQi62F79RHWmwKOtFmwteURgLbj7D/WGuNLGOfa/2vse3G2 
eHnHl5CB8ruRX9fBl/KgwCVr2JaEuUm66bBQeP5XeBotdR4cvX38uPYivCDdPjJ1 
QWPdspTBKcxeFbccDwIDAQAB 
-----END PUBLIC KEY----- 

公共PEM关键,我想使用OpenSSL的

int RSA_public_decrypt(int flen, const unsigned char *from, unsigned char *to,RSA *rsa, int padding)。我如何将Pem键翻译成RSA *rsa结构?

供参考:我不能使用BIO,因为我只是想将openssl移植到没有UNIX文件系统的引导加载程序中。我能做的唯一方法是将公钥转换为C数组。

+0

PEM证书文件包含一个64位编码的X509证书。 X509结构包含PUBKEY,通常是RSA密钥,但还有其他使用DSA或elleptic曲线的证书......不幸的是,OpenSSL似乎依靠FILE作为PEM读取数据的输入,至少是我发现的功能。 – Robert

+0

@Robert这就是我遇到的问题 – demonguy

回答

6

我不能使用BIO因为我只是想移植到的OpenSSL不具有UNIX文件系统

我觉得你还是可以使用BIO,它只是成为一个引导程序内存BIO,而不是文件BIO

如果你不能使用内存BIO,那么我不确定你可以在这里使用OpenSSL。


如何PEM公共密钥转换成OpenSSL的RSA *结构

使用PEM_read_PUBKEYPEM_read_bio_PUBKEY(或*_PUBKEY例程之一)。他们返回EVP_PKEY。然后,使用EVP_PKEY_get1_RSA将其转换为RSA

喜欢的东西:

static const char key[] = "-----BEGIN PUBLIC KEY-----\n" 
    "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7vbqajDw4o6gJy8UtmIbkcpnk\n" 
    "O3Kwc4qsEnSZp/TR+fQi62F79RHWmwKOtFmwteURgLbj7D/WGuNLGOfa/2vse3G2\n" 
    "eHnHl5CB8ruRX9fBl/KgwCVr2JaEuUm66bBQeP5XeBotdR4cvX38uPYivCDdPjJ1\n" 
    "QWPdspTBKcxeFbccDwIDAQAB\n" 
    "-----END PUBLIC KEY-----\n"; 

BIO* bio = BIO_new_mem_buf(key, (int)sizeof(key)); 
ASSERT(bio != NULL); 

EVP_PKEY* pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); 
ASSERT(pkey != NULL); 

int type = EVP_PKEY_get_type(pkey); 
ASSERT(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA2); 

RSA* rsa = EVP_PKEY_get1_RSA(pkey); 
ASSERT(rsa != NULL); 

... 

EVP_PKEY_free(pkey); 
RSA_free(rsa); 
BIO_free(bio); 

这里您需要的帮手。 EVP_PKEY_get_type不是库的一部分:

int EVP_PKEY_get_type(EVP_PKEY *pkey) 
{ 
    ASSERT(pkey); 
    if (!pkey) 
     return EVP_PKEY_NONE; 

    return EVP_PKEY_type(pkey->type); 
} 

相关,您也可以使用非PEM版本,这是关键的ASN.1/DER编码。这将允许您在图像中保存一些尺寸。然后,您将使用d2i_PUBKEY_bio来读取密钥。

从PEM转换为ASN.1/DER将节省约110字节:

$ ls -al pubkey.* 
-rw-r--r-- 1 user staff 162 Jun 5 00:36 pubkey.der 
-rw-r--r-- 1 user staff 272 Jun 5 00:52 pubkey.pem 

要转换编码的公钥来ASN.1/DER的PEM,请按照下列步骤。首先,将密钥复制到剪贴板。其次,像pbpaste在OS X或xclip Linux上的工具管道将它导入openssl pkey

$ pbpaste | openssl pkey -pubin -inform PEM -out pubkey.der -outform DER 

然后,检查公共密钥:

$ dumpasn1 pubkey.der 
    0 159: SEQUENCE { 
    3 13: SEQUENCE { 
    5 9:  OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) 
16 0:  NULL 
     :  } 
18 141: BIT STRING, encapsulates { 
22 137:  SEQUENCE { 
25 129:  INTEGER 
     :   00 BB BD BA 9A 8C 3C 38 A3 A8 09 CB C5 2D 98 86 
     :   E4 72 99 E4 3B 72 B0 73 8A AC 12 74 99 A7 F4 D1 
     :   F9 F4 22 EB 61 7B F5 11 D6 9B 02 8E B4 59 B0 B5 
     :   E5 11 80 B6 E3 EC 3F D6 1A E3 4B 18 E7 DA FF 6B 
     :   EC 7B 71 B6 78 79 C7 97 90 81 F2 BB 91 5F D7 C1 
     :   97 F2 A0 C0 25 6B D8 96 84 B9 49 BA E9 B0 50 78 
     :   FE 57 78 1A 2D 75 1E 1C BD 7D FC B8 F6 22 BC 20 
     :   DD 3E 32 75 41 63 DD B2 94 C1 29 CC 5E 15 B7 1C 
     :   0F 
157 3:  INTEGER 65537 
     :  } 
     :  } 
     : } 

最后,这样做:

int main(int argc, char* argv[]) 
{ 
    UNUSED(argc), UNUSED(argv); 

    static const unsigned char key[] = { 
     0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 
     0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0xbd, 0xba, 
     0x9a, 0x8c, 0x3c, 0x38, 0xa3, 0xa8, 0x09, 0xcb, 0xc5, 0x2d, 0x98, 0x86, 0xe4, 0x72, 0x99, 0xe4, 
     0x3b, 0x72, 0xb0, 0x73, 0x8a, 0xac, 0x12, 0x74, 0x99, 0xa7, 0xf4, 0xd1, 0xf9, 0xf4, 0x22, 0xeb, 
     0x61, 0x7b, 0xf5, 0x11, 0xd6, 0x9b, 0x02, 0x8e, 0xb4, 0x59, 0xb0, 0xb5, 0xe5, 0x11, 0x80, 0xb6, 
     0xe3, 0xec, 0x3f, 0xd6, 0x1a, 0xe3, 0x4b, 0x18, 0xe7, 0xda, 0xff, 0x6b, 0xec, 0x7b, 0x71, 0xb6, 
     0x78, 0x79, 0xc7, 0x97, 0x90, 0x81, 0xf2, 0xbb, 0x91, 0x5f, 0xd7, 0xc1, 0x97, 0xf2, 0xa0, 0xc0, 
     0x25, 0x6b, 0xd8, 0x96, 0x84, 0xb9, 0x49, 0xba, 0xe9, 0xb0, 0x50, 0x78, 0xfe, 0x57, 0x78, 0x1a, 
     0x2d, 0x75, 0x1e, 0x1c, 0xbd, 0x7d, 0xfc, 0xb8, 0xf6, 0x22, 0xbc, 0x20, 0xdd, 0x3e, 0x32, 0x75, 
     0x41, 0x63, 0xdd, 0xb2, 0x94, 0xc1, 0x29, 0xcc, 0x5e, 0x15, 0xb7, 0x1c, 0x0f, 0x02, 0x03, 0x01, 
     0x00, 0x01 
    }; 

    BIO* bio = BIO_new_mem_buf(key, (int)sizeof(key)); 
    ASSERT(bio != NULL); 

    EVP_PKEY* pkey = d2i_PUBKEY_bio(bio, NULL); 
    ASSERT(pkey != NULL); 

    int type = EVP_PKEY_get_type(pkey); 
    ASSERT(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA2); 

    RSA* rsa = EVP_PKEY_get1_RSA(pkey); 
    ASSERT(rsa != NULL); 

    // ... 

    EVP_PKEY_free(pkey); 
    RSA_free(rsa); 
    BIO_free(bio); 

    return 0; 
} 
+0

PEM_read_PUBKEY的第一个参数仍然是一个文件句柄 – demonguy

+1

EVP_PKEY_base_id()看起来完全符合您的EVP_PKEY_get_type()函数的功能。他们为什么这么说,我不知道。 – Gammadyne

+0

@Gammadyne - 是的,我认为你是对的。如果使用它,请小心。它会尝试解引用NULL指针。 – jww

1

从pem文件加载RSA pub文件密钥

int loadKey(string &fileName, RSA ** pubkey) 
{ 

    FILE *fp = fopen(fileName.data(), "r"); 
    if (fp < 0){ 
    printf("%s\n","Invalide certificate file name"); 
    return -1; 
} 

*pubkey = PEM_read_RSA_PUBKEY(fp,pubkey, NULL, NULL); 

if(*pubkey == NULL){ 
    printf("%s\n","error reading Public key"); 
    return -1; 
} 

若要验证签名

int verify_signature(vector<uint8_t> &msg, vector<uint8_t> &sig, RSA* pkey) 
{ 
    /* Returned to caller */ 
    int result = -1; 
    vector <uint8_t> pDecrypted(PACKAGE_SIGNATURE_SIZE); 


    result = RSA_public_decrypt(PACKAGE_SIGNATURE_SIZE, sig.data(), pDecrypted.data(), pkey, RSA_NO_PADDING); 
    if (result == -1) 
    { 
    printf("RSA_public_decrypt failed with error %s\n", ERR_error_string(ERR_get_error(), NULL)); 
    // goto prog_end; 
    } 


    /* verify the data */ 
    result = RSA_verify_PKCS1_PSS(pkey,msg.data() , EVP_sha256(), pDecrypted.data(), -2 /* salt length recovered from signature*/); 
    if (result == 1) 
    { 
    printf("Signature verification successfull!\n"); 
    } 
    else 
    { 
    printf("RSA_verify_PKCS1_PSS failed with error %s\n", ERR_error_string(ERR_get_error(), NULL)); 
    } 

    return !!result; 

} 
相关问题