Search code examples
c#.netopensslcryptographydiffie-hellman

Diffie-Hellman: How To Load the Generator and Prime values from .pem file in .Net


I generated a .pem file that contains Diffie-Hellman parameters. I used this command line:

openssl dhparam -outform PEM 2048 -out dhparam.pem

The file looks like this:

-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA6gS7LGwOkRMfJJX2sBK+NRwSL1OaegjVeEh+FJJbWRLG7pB9W7JX
[4 lines omitted]
7LyTYZEvaaAK27xuf4uo4YCFnaOkxp/R6wIBAg==
-----END DH PARAMETERS-----

How can I extract the Generator and Prime values from this file using .Net Framework code?

Note that there is an answer How to extract DH parameters from a DH key in PEM format for how to accomplish this task on the command line.


Solution

  • For .NET Framework it is most convenient to retrieve the data using BouncyCastle's Utilities.IO.Pem.PemReader and ASN.1 parser:

    using Org.BouncyCastle.Asn1;
    using Org.BouncyCastle.Math;
    using Org.BouncyCastle.Utilities.IO.Pem;
    using System;
    using System.IO;
    
    ...
    
    string dhParamsPem = @"-----BEGIN DH PARAMETERS-----
    MIIBCAKCAQEAnyWVRlZpZ0P6aVzTS25m1SR+HqJAXsGqRhVSPlijljZ+8B/2d1m7
    /HlyZIXIkRkgiBvarl7BK95Uj4A34+rabFaab0aukJm8DgI0Za3MuiPG2+1EsZPm
    9IQnGo+VRXv/VZ4ooMUmOw/NLU3lJ4P8ViK9R+1e5OnLK3FWxQWFfidAhDnx8Xzc
    vp8Y9qR0DuiQQc3cZaS0Ko+LDxqQJkHobsKdpdd2DGxdeRjg4f65j/WVixSEmSyI
    rMwDu4svdk7Bjd9cjlSui3mm7Trf1ME0Ox18Ir5FRuzpZvkuD11oDF0fc3A2gCdx
    hiuj5z75xtXMGqcTlzMicWTal6MtLfmWCwIBAg==
    -----END DH PARAMETERS-----";
    
    PemReader pemReader = new PemReader(new StringReader(dhParamsPem));
    PemObject pemObject = pemReader.ReadPemObject();
    Asn1Sequence asn1Seq = Asn1Sequence.GetInstance(pemObject.Content); 
    BigInteger p = ((DerInteger)asn1Seq[0]).PositiveValue;
    BigInteger g = ((DerInteger)asn1Seq[1]).PositiveValue;
    
    Console.WriteLine(p); // 20090423409171421154387714584555511320868268871945482725661544541530332355839089164300271096651615230651244725677611659751244269997811212265593049309472107745660505171223135113566045750129565437460985935927850461605237593196654771593662837177817015214051951556984885103642631543107288713880526529543092219393162039732425952951349374625402000680805514079485639328869699772680730890272312298949384709284994133124244952710119496271097947248984953575915669174208183280906980298889356605342059216347892537283618180485781467407114828705793629928947579235056616468247708144579207430255173737359957970195317686357288487065099
    Console.WriteLine(g); // 2
    

    The data can be checked with an ASN.1 online parser, e.g. https://lapo.it/asn1js:

    enter image description here


    Edit: As of .NET 5, e.g. the native classes PemEncoding and AsnReader can be used, so BouncyCastle is no longer needed:

    using System;
    using System.Formats.Asn1;
    using System.Numerics;
    using System.Security.Cryptography;
    ...
    PemFields pemFields = PemEncoding.Find(dhParamsPem);
    byte[] derData = Convert.FromBase64String(dhParamsPem[pemFields.Base64Data]);
    AsnReader asn1Seq = new AsnReader(derData, AsnEncodingRules.DER).ReadSequence();
    BigInteger p = asn1Seq.ReadInteger();
    BigInteger g = asn1Seq.ReadInteger();