Elliptic Curve Diffie Hellman + AES256

302 views
Skip to first unread message

Damias

unread,
May 29, 2014, 8:57:56 AM5/29/14
to cryptop...@googlegroups.com
Hi all, I need to implement an AES256 code with EC-DH key agreement.

At the moment I have the encryption and decryption with AES256 done 
but generating the key and the IV with a random number generator (in my case AutoSeededRandomPool). 
Now, looking at this http://www.cryptopp.com/wiki/Elliptic_Curve_Diffie-Hellman I guess I must load my private key and the couterparty's public key in order
to use the function "Agree" from the class DH_Domain. I'm going in the right direction? My questions are: 

How I declare an EC key in my code? Then I will be able to use .Load? I know that in RSA is RSA::PrivateKey name but in ECC I don't have any idea...
How do I use the public key and the private to use as parameters in the function Agree?

Jean-Pierre Münch

unread,
Jun 2, 2014, 11:48:57 AM6/2/14
to cryptop...@googlegroups.com
Hi Damias,

to Question 1 - 3: ECDH consists of 2 parts: the curve and the transmitted data. You load the curve as described in the article, using OIDs and pre-defined curves. The Keydata is different: Keydata are just raw byte arrays of appropriate size ( call
.PublicKeyLength() and .PrivateKeyLength to get those). If you use SecByteBlocks you might be able to use a load-like function but I'd recommend using just BytePtr()
to Question 4: In The Agree function you just pass in your private key, the other's public key and a pointer to an array receiving the agreed value and all the magic is done.

BR

JPM
Message has been deleted

Damias

unread,
Jun 10, 2014, 7:03:49 AM6/10/14
to cryptop...@googlegroups.com
I do not find any function to load the public key. I've tried to use BERDecode on DH Domain http://www.cryptopp.com/docs/ref/class_d_h___domain.html but without success. I've tried too declaring a CryptoPP::ECIES< CryptoPP::ECP >::PublicKey and using .Load, but nothing. I've managed to pass from SecByteBlock to Byte but now i would need to load a public key in .der format on this.

Here's is the code I have at the moment.

int main( int, char** ) {

    OID CURVE = secp256k1();
    AutoSeededX917RNG<AES> rng;

    /* A */
    ECDH < ECP >::Domain dhA( CURVE );

    byte privA[dhA.PrivateKeyLength()];
    byte pubA[dhA.PublicKeyLength()];

    dhA.GenerateKeyPair(rng, privA, pubA);

    byte sharedA[dhA.AgreedValueLength()];    

    /* B */
    ECDH < ECP >::Domain dhB( CURVE );

    byte privB[dhB.PrivateKeyLength()];
    byte pubB[dhB.PublicKeyLength()];

    dhB.GenerateKeyPair(rng, privB, pubB);

    byte sharedB[dhB.AgreedValueLength()];    

    /* AGREEMENT */
    dhA.Agree (sharedA, privA, pubB);
    dhB.Agree (sharedB, privB, pubA);

    if ((dhA.AgreedValueLength() != dhB.AgreedValueLength()) || (memcmp (sharedB, sharedA, dhA.AgreedValueLength()) != 0)) {
        cout << "Something wrong" << endl;
    }
    else {
        cout << "Agreed to shared secret" << endl;
    }

    return 0;
}

If I use:

    CryptoPP::ECIES< CryptoPP::ECP >::PublicKey pubA;
    CryptoPP::ECIES< CryptoPP::ECP >::PrivateKey privA;

    string namepub = "ec-pubkey.der";
    string namepriv = "ec-privkey.der";
    pubA.Load(FileSource( namepub.c_str(), true, NULL, true /*binary*/ ).Ref());
    privA.Load(FileSource( namepriv.c_str(), true, NULL, true /*binary*/ ).Ref());

Instead of:

    byte privA[dhA.PrivateKeyLength()];
    byte pubA[dhA.PublicKeyLength()];

    dhA.GenerateKeyPair(rng, privA, pubA);

    byte sharedA[dhA.AgreedValueLength()];

The code compiles but when I execute it:
terminate called after throwing an instance of 'CryptoPP::BERDecodeErr'
  what():  BER decode error

Jean-Pierre Münch

unread,
Jun 10, 2014, 10:24:42 AM6/10/14
to cryptop...@googlegroups.com
You're close, you just generated the public key into a SecByteBlock now you just need to call BytePtr() on this block and maybe somehow retrieve it's size and send this bytes to the party you're adressing.
When loading from a file you would just store the curve (-> Curve-Size?), the key size (Privatekeylength & publickeylength) and load the key-bytes from the file.
AND I'd really doubt that it's clever to store the public and private key in a file. Normally you would just send the public key via network and be happy and generate a new pair for each execution.

BR

JPM

Damias

unread,
Jun 12, 2014, 6:29:34 AM6/12/14
to cryptop...@googlegroups.com
I've managed to save the keys and load them, but on binary. It is possible to save the keys on .der? Because in cryptopp-ecies-test.zip the keys saved are on binary too.

Jean-Pierre Münch

unread,
Jun 12, 2014, 11:04:17 AM6/12/14
to cryptop...@googlegroups.com
Binary encoding suffices most purposes, if you really need to DER-Ecnode, try converting the byte sequence to a CryptoPP::Integer using the byte-wise constructor. If this works successful you can DER encode the integer and store or send it.

BR

JPM

Damias

unread,
Jun 12, 2014, 1:15:01 PM6/12/14
to cryptop...@googlegroups.com
Ok, i've managed to convert the bytes to Integers and use function DEREncode with BufferedTransformation (FileSink). But when I try to load the keys with BERDecode... this happens: 
terminate called after throwing an instance of 'CryptoPP::BERDecodeErr'
  what():  BER decode error

I've tried this:
    string filename5 = "ecc-pubkeyA.der";
    string filename6 = "ecc-pubkeyB.der";
    FileSource fs5(filename5.c_str(), true);
    FileSource fs6(filename6.c_str(), true);
    Integer pubkey_A(fs5);
    Integer pubkey_B(fs6);

and this:
    Integer pubkey_A(pubA, dhA.PublicKeyLength());
    Integer pubkey_B(pubB, dhB.PublicKeyLength());
    string filename5 = "ecc-pubkeyA.der";
    string filename6 = "ecc-pubkeyB.der";
    FileSource fs5(filename5.c_str(), true);
    FileSource fs6(filename6.c_str(), true);
    pubkey_A.BERDecode(fs5);
    pubkey_B.BERDecode(fs6);

Jeffrey Walton

unread,
Jun 17, 2014, 6:21:37 AM6/17/14
to cryptop...@googlegroups.com

Try DEREncodePrivateKey, DEREncodePublicKey and friends. See the Crypto++ wiki on Keys and Formats at http://www.cryptopp.com/wiki/Keys_and_Formats#DER_Encoding.

Jeff

Jeffrey Walton

unread,
Jun 17, 2014, 7:45:09 AM6/17/14
to cryptop...@googlegroups.com


On Tuesday, June 17, 2014 6:21:37 AM UTC-4, Jeffrey Walton wrote:


On Thursday, June 12, 2014 1:15:01 PM UTC-4, Damias wrote:
Ok, i've managed to convert the bytes to Integers and use function DEREncode with BufferedTransformation (FileSink). But when I try to load the keys with BERDecode... this happens: 
terminate called after throwing an instance of 'CryptoPP::BERDecodeErr'
  what():  BER decode error

....

Try DEREncodePrivateKey, DEREncodePublicKey and friends. See the Crypto++ wiki on Keys and Formats at http://www.cryptopp.com/wiki/Keys_and_Formats#DER_Encoding.
My bad, I was not clear here.... the ECDH class performs Diffie-Hellman over elliptic curves. The keys created below:

    OID CURVE = secp256r1();
    AutoSeededRandomPool rng;
   
    ECDH < ECP >::Domain dhA( CURVE ), dhB( CURVE );
    SecByteBlock privA(dhA.PrivateKeyLength()), pubA(dhA.PublicKeyLength());
    SecByteBlock privB(dhB.PrivateKeyLength()), pubB(dhB.PublicKeyLength());
   
    dhA.GenerateKeyPair(rng, privA, pubA);
    dhB.GenerateKeyPair(rng, privB, pubB);

The keys are ephemeral. They are intended to be used once and thrown away. As such, there is no Load() or Save() defined on them.

The idea is you already have a long term or static key. It can be a RSA key, DSS key or ECDSA key, etc. When performing key agreement, you generate the ephemeral key pair using the ECDH class. Then, you send the other party your temporary ECDH public key, and you sign it with you RSA , DSS or ECDSA key. That is, you sign the ephemeral key with the static or long term key.

The RSA key, DSS key or ECDSA key allows you to Save() and Load() because they are static or long term keys. That's where you use DEREncodePrivateKey, DEREncodePublicKey and friends.

Jeff
Reply all
Reply to author
Forward
0 new messages