How to use Crypto++ to perfom DH key exchange (CryptoPP::DH::Agree returns false)

1.3k views Asked by At

I'm trying to use Crypto++ to perform Diffie-Hellman key exchange. I have written a simple program to check if this is working. As you can guess, it is not.

This program was written based on wiki article: https://www.cryptopp.com/wiki/Diffie-Hellman It is generating public and private keys and then uses them to cal function CryptoPP::DH::Agree. It was working when I was using the same pair of keys for both sides like it is on the wiki. This does not have much practical sense though. However, when I trying to use different keys, CryptoPP::DH::Agree returns false.

I suspect that I'm doing something incorrectly but I have no idea what.

#include <crypto++/cryptlib.h>
#include <crypto++/dh.h>
#include <cryptopp/dh2.h>
#include <crypto++/osrng.h>
#include <crypto++/integer.h>
#include <crypto++/nbtheory.h>
#include <iostream>


static CryptoPP::AutoSeededRandomPool rnd;
static CryptoPP::DH dhA, dhB;
static CryptoPP::SecByteBlock privKeyA, pubKeyA, privKeyB, pubKeyB;


static void createDomainParameters(CryptoPP::DH &dh)
{
    CryptoPP::PrimeAndGenerator pg;
    pg.Generate(1, rnd, 512, 511);
    const CryptoPP::Integer p = pg.Prime();
    const CryptoPP::Integer q = pg.SubPrime();
    const CryptoPP::Integer g = pg.Generator();

    std::cout << "P: " << p << '\n';
    std::cout << "Q: " << q << '\n';
    std::cout << "G: " << g << '\n';

    dh = CryptoPP::DH(p, q, g);
}

static void createAsymetricKey(const CryptoPP::DH &dh, CryptoPP::SecByteBlock &privKey, CryptoPP::SecByteBlock &pubKey)
{
    privKey = CryptoPP::SecByteBlock(dh.PrivateKeyLength());
    pubKey = CryptoPP::SecByteBlock(dh.PublicKeyLength());
    dh.GenerateKeyPair(rnd, privKey, pubKey);

    CryptoPP::Integer a, b;

    a.Decode(privKey.BytePtr(), privKey.SizeInBytes());
    std::cout << "privKey: " << a << std::endl;

    b.Decode(pubKey.BytePtr(), pubKey.SizeInBytes());
    std::cout << "pubKey:  " << b << std::endl;
}

static void createSymetricKey(const CryptoPP::DH &dh, const CryptoPP::SecByteBlock &privKey, const CryptoPP::SecByteBlock &pubKey)
{
    CryptoPP::SecByteBlock shared(dh.AgreedValueLength());
    if(!dh.Agree(shared, privKey, pubKey))
        throw std::runtime_error("Failed to reach shared secret");

    CryptoPP::Integer x;
    x.Decode(shared.BytePtr(), shared.SizeInBytes());
    std::cout << "shared: " << x << std::endl;
}

int main()
{
    std::cout << std::hex;

    createDomainParameters(dhA);
    std::cout << std::endl;
    createDomainParameters(dhB);

    std::cout << "\n------------------------------\n" << std::endl;
    createAsymetricKey(dhA, privKeyA, pubKeyA);
    std::cout << std::endl;
    createAsymetricKey(dhB, privKeyB, pubKeyB);

    if(dhA.AgreedValueLength() != dhB.AgreedValueLength())
        throw std::runtime_error("Shared secret size mismatch");

    std::cout << "\n------------------------------\n" << std::endl;
    createSymetricKey(dhA, privKeyA, pubKeyB);
    std::cout << std::endl;
    createSymetricKey(dhB, privKeyB, pubKeyA);

    return 0;
}

When you change calls of createSymetricKey so it uses key from the same pair, it works.

createSymetricKey(dhA, privKeyA, pubKeyA);
std::cout << std::endl;
createSymetricKey(dhB, privKeyB, pubKeyB);

AFAIK this has no sense though. What is the correct way to use CryptoPP::DH::Agree?

0

There are 0 answers