如何将pem公钥转换为openssl RSA *结构

时间:2015-06-03 13:25:08

标签: c encryption openssl cryptography rsa

假设我必须像这样公开pem键

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

我想使用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数组。

2 个答案:

答案 0 :(得分:7)

  

我无法使用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

要将PEM编码的公钥转换为ASN.1 / DER,请执行以下步骤。首先,将密钥复制到剪贴板。其次,使用OS X上的pbpaste或Linux上的xclip等工具将其传递到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;
}

答案 1 :(得分: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;

}