使用 OpenSSL 生成私钥

Generate private key with OpenSSL

我正在尝试使用 openssl 生成 RSA 私钥,到目前为止它运行良好。 我想获取 PEM 中密钥的格式。 将密钥写入文件时,格式似乎没问题,但是当我将密钥保存在 PEM 中的字符数组中时,它似乎与写入文件的格式不同!? 这是一个简短的例子:

#include <iomanip>
#include <string>
#include <string.h>
#include <iostream>
#include <openssl/pem.h>
#include <openssl/x509.h>

int main() {
    EVP_PKEY *pkey = EVP_PKEY_new();
    if (!pkey) {
        return 0;
    }

    RSA *rsa = RSA_generate_key(2048, 3, NULL, NULL);
    if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
        return 0;
    }

    BIO *bio = BIO_new(BIO_s_mem());
    PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL);

    int pem_pkey_size = BIO_pending(bio);
    char *pem_pkey = (char*) calloc((pem_pkey_size)+1, 1);
    BIO_read(bio, pem_pkey, pem_pkey_size);


    FILE *pkey_file = fopen("key.pem", "wb");
    if (!pkey_file) {
        std::cerr << "Unable to open \"key.pem\" for writing." << std::endl;
        return false;
    }

    bool ret = PEM_write_PrivateKey(pkey_file, pkey, NULL, NULL, 0, NULL, NULL);
    fclose(pkey_file);

    if(!ret) {
        std::cerr << "Unable to write private key to disk." << std::endl;
        return false;
    }


    std::cout << pem_pkey << std::endl;

    return 0;
}

使用

编译
 g++ -std=c++11 test.cpp -o test -lssl -lcrypto

但是打印的密钥和保存到文件中的密钥不匹配!?

文件中的结果如下所示

-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCpV8dtaMtTy3AO
Oa+yKuZVHATDScyNtuqIdVuQlF5iJfIWLgZK2gKykNdVCVIdFcPpaPF6NmNvmCSM
YyLdCuTZXFyEXM61uOvBcCDazUCZsSsFgt31bh9qvuxZufSRuHoEFgOiE9CgESyF
KgM1h0UugwHfDyE6UA1+Vbm4Oh4+pgqK5n+gYXxn4Cj8jsKDfF5A1MBV1fCnHnrX
c/1Tpr5pG4dBY2E1MgMA27MbRxxdkNeFCXM41uR4ncSGhaovI2bgUwIm4WyLLco/
xzR/D6pfiTuzlROGXfdTt+36NXCsj9BhKw59spxlZCrASRMVyAYguCctdJw2yaGB
kTiu3gndAgEDAoIBAHDlL55F3OKHoAl7ynbHRDi9WIIxMwkknFr457W4PuwZTA7J
WYc8Acxgj44GNr4OgpubS6bO7PUQGF2XbJNcmJDoPa2TNHkl8oD1azyI1bvLcgOs
k/j0FPHUnZEmowvQUVgOrRa34Gq2Ha4cAiOvg3RXVpS0wNGKs6mOe9AmvtRtm31t
APTEdYUnsvUPRXGqysxDn8GvAO1aQReKu5TI6866z2mRWUxwRw8ly/fBIhwHB/n6
78Pzo5V0tf9DKkyCNXvk+qgOp3Kv+vkcdBAqfGXmO+OFBirePTxgiYfbjMCQ3PXf
RCU8s3/DsV5jBIPZKSpeZVwK2VObFfyLgcSRVxMCgYEA3j39bvIvd91CWkS4dhoC
KlWlEV/+ml+4i4pwEeySiimyHUHEW0w5wGXQArPu25nOUnKP1l3TJSf1eeN6nlRU
rTeirobgfnAeYbemVCO8TZNIh9RxsoE1GdOZKoJ0RTv+b+LT9oYiYxJKN2BHjxM4
SHcSu97eAkiWzB5dAqpLiusCgYEAwxDFjz8LVELiQkg/ZD76A7jKP1NQ1ONejamz
0gfm0olRMuFE//ZP2ARS/nO2jZm3+RuBNTUWSfB5OaQmTGgLaW7Y26Pq8u8HcBJ2
MkMTojNnWgnb18TbgaWN9Sv32E+4FQ2IMb+1LBN0aVJs/TzJ/+oX00SGU/DKNGhi
8124fFcCgYEAlClTn0wfpT4sPC3QTrwBcY5uC5VUZup7B7GgC/MMXBvME4EtkjLR
Ku6KrHf0kmaJjExf5D6Mw2/4++z8aY2NyM/Bya9AVEq+68/EOBfS3mIwWo2hIat4
u+JmHFb4Lif+9UHipFlsQgwxekAvtLd62voMfT8+rDBkiBQ+AcbdB0cCgYEAggsu
X39c4tdBgYV/mCn8Ansxf4zgjezps8Z34VqZ4bDgzJYt//mKkALh/vfPCRElUL0A
ziNkMUr7e8LEMvAHm587PRfx90oE9WGkIYINFszvkVvn5S3nq8Oz+Mf6kDUlY15a
y9Ujcrei8OGd/iiGqpwP4i2u4qCGzZrsoj56/Y8CgYBeht5y3wey/ZsDXXd5MXwW
TWmhEQWbifn/P4rmydnVtYVJMaWdFPiPc9U4JFtkxKlxmtihy+0O/rTYUfiv6dzZ
kJApv+H1r2S6Hx7a8DFkug8DKFcfVZC3UYdYoirQ2IvOVMK+hD8vnNDXefRk31UJ
+us47+a7yXn3T5m8cSqm7g==
-----END PRIVATE KEY-----

而 std::cout 的输出是:

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAqVfHbWjLU8twDjmvsirmVRwEw0nMjbbqiHVbkJReYiXyFi4G
StoCspDXVQlSHRXD6WjxejZjb5gkjGMi3Qrk2VxchFzOtbjrwXAg2s1AmbErBYLd
9W4far7sWbn0kbh6BBYDohPQoBEshSoDNYdFLoMB3w8hOlANflW5uDoePqYKiuZ/
oGF8Z+Ao/I7Cg3xeQNTAVdXwpx5613P9U6a+aRuHQWNhNTIDANuzG0ccXZDXhQlz
ONbkeJ3EhoWqLyNm4FMCJuFsiy3KP8c0fw+qX4k7s5UThl33U7ft+jVwrI/QYSsO
fbKcZWQqwEkTFcgGILgnLXScNsmhgZE4rt4J3QIBAwKCAQBw5S+eRdzih6AJe8p2
x0Q4vViCMTMJJJxa+Oe1uD7sGUwOyVmHPAHMYI+OBja+DoKbm0umzuz1EBhdl2yT
XJiQ6D2tkzR5JfKA9Ws8iNW7y3IDrJP49BTx1J2RJqML0FFYDq0Wt+Bqth2uHAIj
r4N0V1aUtMDRirOpjnvQJr7UbZt9bQD0xHWFJ7L1D0VxqsrMQ5/BrwDtWkEXiruU
yOvOus9pkVlMcEcPJcv3wSIcBwf5+u/D86OVdLX/QypMgjV75PqoDqdyr/r5HHQQ
Knxl5jvjhQYq3j08YImH24zAkNz130QlPLN/w7FeYwSD2SkqXmVcCtlTmxX8i4HE
kVcTAoGBAN49/W7yL3fdQlpEuHYaAipVpRFf/ppfuIuKcBHskoopsh1BxFtMOcBl
0AKz7tuZzlJyj9Zd0yUn9Xnjep5UVK03oq6G4H5wHmG3plQjvE2TSIfUcbKBNRnT
mSqCdEU7/m/i0/aGImMSSjdgR48TOEh3Erve3gJIlsweXQKqS4rrAoGBAMMQxY8/
C1RC4kJIP2Q++gO4yj9TUNTjXo2ps9IH5tKJUTLhRP/2T9gEUv5zto2Zt/kbgTU1
FknweTmkJkxoC2lu2Nuj6vLvB3ASdjJDE6IzZ1oJ29fE24GljfUr99hPuBUNiDG/
tSwTdGlSbP08yf/qF9NEhlPwyjRoYvNduHxXAoGBAJQpU59MH6U+LDwt0E68AXGO
bguVVGbqewexoAvzDFwbzBOBLZIy0Sruiqx39JJmiYxMX+Q+jMNv+Pvs/GmNjcjP
wcmvQFRKvuvPxDgX0t5iMFqNoSGreLviZhxW+C4n/vVB4qRZbEIMMXpAL7S3etr6
DH0/PqwwZIgUPgHG3QdHAoGBAIILLl9/XOLXQYGFf5gp/AJ7MX+M4I3s6bPGd+Fa
meGw4MyWLf/5ipAC4f73zwkRJVC9AM4jZDFK+3vCxDLwB5ufOz0X8fdKBPVhpCGC
DRbM75Fb5+Ut56vDs/jH+pA1JWNeWsvVI3K3ovDhnf4ohqqcD+ItruKghs2a7KI+
ev2PAoGAXobect8Hsv2bA113eTF8Fk1poREFm4n5/z+K5snZ1bWFSTGlnRT4j3PV
OCRbZMSpcZrYocvtDv602FH4r+nc2ZCQKb/h9a9kuh8e2vAxZLoPAyhXH1WQt1GH
WKIq0NiLzlTCvoQ/L5zQ13n0ZN9VCfrrOO/mu8l590+ZvHEqpu4=
-----END RSA PRIVATE KEY-----   

在文件中写了这个结构:

  PrivateKeyInfo ::= SEQUENCE {
    version                   Version,
    privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
    privateKey                PrivateKey,
    attributes           [0]  IMPLICIT Attributes OPTIONAL }

而在 pem_key 中仅存储上述结构的 PrivateKey 部分,因此:

  RSAPrivateKey ::= SEQUENCE {
      version           Version,
      modulus           INTEGER,  -- n
      publicExponent    INTEGER,  -- e
      privateExponent   INTEGER,  -- d
      prime1            INTEGER,  -- p
      prime2            INTEGER,  -- q
      exponent1         INTEGER,  -- d mod (p-1)
      exponent2         INTEGER,  -- d mod (q-1)
      coefficient       INTEGER,  -- (inverse of q) mod p
      otherPrimeInfos   OtherPrimeInfos OPTIONAL
  }

如果要保存第一个结构,则需要保存EVP_PKEY *pkey。像这样调用:

PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, 0, NULL);