Search code examples
c++opensslcryptographypemdiffie-hellman

How to store Diffie HellMan Object's Keys in PEM Format using openSSL C++


I am facing one silly issue in storing my DH Keys in PEM Format. Here is working code snippet to generate Keys in Diffie Hellman format, I can store the DH Params in PEM Format. However I don't find any function in openSSL which can store the Keys also in PEM Format.

DH *privkey = DH_new();
/* Generate the parameters to be used */
DH_generate_parameters_ex(privkey, 2048, DH_GENERATOR_2, NULL)

/* Generate the public and private key pair */
DH_generate_key(privkey)

/* Store DH Params in PEM Format */
FILE* fptr = fopen("dhp.pem", "w");
PEM_write_DHparams(fptr, privkey);

/* Get PublicKey of Peer To generate Shared Secret ----*/
BIGNUM *pubkeyPeer = NULL;
BN_dec2bn(&pubkeyPeer, BN_bn2dec(GetPubKeyPeer());

/* Generate Shared Secret by getting Public Key of Peer */
unsigned char *secret;
int secret_size;
if (NULL == (secret= (unsigned char *)OPENSSL_malloc(sizeof(unsigned char) * (DH_size(privkey))))) {
        printf("Can Not Allocate Memory for Shared Secret ");
    }
if (0 > (secret_size = DH_compute_key(secret, pubkeyPeer, privkey))) {
        printf("Shared Secret Generation Failure ");
}

/* DUMP Shared Secret ---*/
BIO_dump_fp(stdout, (const char *)secret, secret_size);

This all is fine, But I need to share my Public Key with Peer in PEM Format. Is there some function to convert my DH Public Key to PEM Format?


Solution

  • OpenSSL has a generic function PEM_write_PKCS8PrivateKey that is capable of writing EVP_PKEY keys to a PKCS8 structure in PEM format. In order to leverage that, you would have to wrap your DH key like this, with the error checking omitted for the sake of brevity:

    EVP_PKEY *pkey = EVP_PKEY_new();
    EVP_PKEY_set1_DH(pkey, privkey);
    PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, NULL, NULL);
    

    PKCS8 allows you to encrypt the contents, those trailing parameters that I did not set in that call are for setting the encryption details. I omitted them here, but you typically do want your private key material stored encrypted in practice.

    Trying it out (after removing your BIO_dump_fp call):

    > dh_key
    -----BEGIN PRIVATE KEY-----
    MIICZAIBADCCAjkGByqGSM4+AgEwggIsAoIBAQCHqOYdtLZmPP+70ZxlGVmZjO72
    CGYN0PJdLO7UQ147AOAN+PHWGVfU+vffRWGyqjAWw9kRNAlvqjv0KW2DDpp8IJ4M
    ZJdRer1aip0wa89n7ZH55nJbR1jAIuCx70J1v3tsW/wR1F+QiLlB9U6x5Zu4vDmg
    vxIwf1xP23DFgbI/drY6yuHKpreQLVJSZzVIig7xPG2aUb+kqzrYNHeWUk2O9qFn
    taQYJdln4UTlFAVkJRzKy4PmtIb2s8o/eXFQYCbAuFf2iZYoVt7UAQq9C+Yhw6OW
    ClTnEMN18mN11wFBA6S1QzDBmK8SYRbSJ24RcV9pOHf61+8JytsJSukeGhWXAoIB
    AD+zLJtzE00LLndQZmDtvUhMp7GPIe8gVAf0eToaC6ElENvBUHe+Rj//T+1KrAu1
    Vb46bBsMa0exvDdzv36Mb2KQEij4woy7GKVa4xNBAAplAZb5Mcd6V/Ld9GPl6ewU
    S3d95iqquKhiisN20oLW7Thk5nmCQo68gx0UNI9vL5GTtQRa8nZxZOHfyWfB+z8u
    VaS9G//oO5yA0FK5hdGC6grbKjtzE9P+FMhISx4FJYi5t9K70t8BYZns0G4VV80J
    FbM1O7tk4Ow3f9AoNw35K1LHiRQozcZ+thhLUj0dskbDL2MHhJDwDvjWR9FI1HlU
    UV4jJ8/vmMWCZktMD2zEFlkCIQCM+DZCpwmgl7RHmXZAEp2imbGkfR6zdQujCLD+
    ZPX70wQiAiBvWQZVf0vXQPl+ovrzFwbia4oDGbPwYtQ83yaLtFo0hw==
    -----END PRIVATE KEY-----
    

    shows the PEM output. Piping it through asn1parse shows its contents:

    > dh_key | openssl asn1parse
        0:d=0  hl=4 l= 612 cons: SEQUENCE
        4:d=1  hl=2 l=   1 prim: INTEGER           :00
        7:d=1  hl=4 l= 569 cons: SEQUENCE
       11:d=2  hl=2 l=   7 prim: OBJECT            :X9.42 DH
       20:d=2  hl=4 l= 556 cons: SEQUENCE
       24:d=3  hl=4 l= 257 prim: INTEGER           :87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597
      285:d=3  hl=4 l= 256 prim: INTEGER           :3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659
      545:d=3  hl=2 l=  33 prim: INTEGER           :8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3
      580:d=1  hl=2 l=  34 prim: OCTET STRING      [HEX DUMP]:0220537AF1D957AB4D23D3779A22F2DD20F3330A0179DCF50AE922491EFB08976517
    

    This actually includes the parameters as well.