Search code examples
c++cryptographycrypto++

Compute shared secret for ECDSA<ECP, SHA256> keys with Crypto++


I'm trying to do the following:

  1. Receive x and y coordinates of a EC public key
  2. Generate a random EC public key
  3. Compute the shared secret of the two keys

I'm stuck at the last step, from the Documentation is seems like I have to use ECDH<ECP>::Domain but nowhere is it explained how to convert the keys into the required SecByteBlock objects, how can I do this? Pseudocode follows.

std::string x = ...
std::string y = ...

auto make_curve = []{ return ASN1::secp256r1(); };

// Public key
ECDSA<ECP, SHA256>::PublicKey g_a;
g_a.Initialize(make_curve(),
               ECP::Point {
                   Integer { x.data() },
                   Integer { y.data() }
               });

// Private key
ECDSA<ECP, SHA256>::PrivateKey g_b;
g_b.Initialize(RANDOM_POOL, make_curve());

// Compute shared secret
ECDH<ECP>::Domain agreement { make_curve() };

SecByteBlock shared_secret_buf { agreement.AgreedValueLength() };

agreement.Agree(shared_secret_buf, ???, ???);

Solution

  • The Wikipedia page shows you show to do this:

    So first create a new key pair (you never generate just one private key):

    ECDH < ECP >::Domain dhB( CURVE );
    SecByteBlock privB(dhB.PrivateKeyLength()), pubB(dhB.PublicKeyLength());
    dhB.GenerateKeyPair(rng, privB, pubB);
    

    and then you can perform the key agreement like this:

    if(!dhB.Agree(shared_secret_buf, privB, pubA))
        throw runtime_error("Failed to reach shared secret (B)");
    

    OK, so now you are left with one issue: encoding the public point. Fortunately that has been explained in the Wiki as well, here, basically you should just be able to use:

    void ECP::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed)
    

    Where your pubA buffer is put in &bt (I hope the input for &P is clear, use false for compressed).

    Basically this returns a byte 04, then the concatenation of X and Y encoded with the size of the field (big endian).

    Note that this just requires an ECP::Point and as the key pair generation also doesn't use ECDSA, that part of the code can be stripped out entirely. That's good, because ECDH is a different algorithm and using ECDSA could make the code less portable, e.g. when using the X25519 curve.