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
?