XTR-DH

From Crypto++ Wiki
Jump to navigation Jump to search
XTR_DH
Documentation
#include <cryptopp/xtr.h>

XTR-DH is a public key cryptosystem by Arjen Lenstra and Eric Verheul. The cryptosystem uses a compact subgroup trace representation to map elements of a subgroup of [math]\displaystyle{ GF(p^6) }[/math] to a trace over [math]\displaystyle{ GF(p^2) }[/math]. XTR-DH is a key agreement scheme so it uses SimpleKeyAgreementDomain and nearly everything from Diffie-Hellman applies; only the field and operations change.

As far as we know there are two questions on Stack Overflow for XTR key agreement. They are Parsing the GFP2Element in Crypto++ and Key agreement with XTR-DH Crypto++.

Crypto++ Validation

Crypto++ demonstrates the use of XTR-DH in validate7.cpp, functions ValidateXTR_DH and SimpleKeyAgreementValidate. SimpleKeyAgreementValidate has the following signature.

bool SimpleKeyAgreementValidate(SimpleKeyAgreementDomain &d)

The body for SimpleKeyAgreementValidate is shown next. The function validates the group parameters and then performs a pairwise consistency check that ensures two parties can arrive at the same shared secret.

bool SimpleKeyAgreementValidate(SimpleKeyAgreementDomain &d)
{
    if (d.GetCryptoParameters().Validate(GlobalRNG(), 3))
        std::cout << "passed ..." << std::endl;
    else
    {
        std::cout << "FAILED ..." << std::endl;
        return false;
    }

    SecByteBlock priv1(d.PrivateKeyLength()), priv2(d.PrivateKeyLength());
    SecByteBlock pub1(d.PublicKeyLength()), pub2(d.PublicKeyLength());
    SecByteBlock val1(d.AgreedValueLength()), val2(d.AgreedValueLength());

    d.GenerateKeyPair(GlobalRNG(), priv1, pub1);
    d.GenerateKeyPair(GlobalRNG(), priv2, pub2);

    memset(val1.begin(), 0x10, val1.size());
    memset(val2.begin(), 0x11, val2.size());

    if (!(d.Agree(val1, priv1, pub2) && d.Agree(val2, priv2, pub1)))
    {
        std::cout << "FAILED ..." << std::endl;
        return false;
    }

    if (memcmp(val1.begin(), val2.begin(), d.AgreedValueLength()))
    {
        std::cout << "FAILED ..." << std::endl;
        return false;
    }

    std::cout << "passed ..." << std::endl;
    return true;
}

Constructors

XTR-DH has three constructors shown below.

XTR_DH (const Integer &p, const Integer &q, const GFP2Element &g)

The constructor above initializes a XTR_DH object from existing integers p and q, and field element g.

XTR_DH (RandomNumberGenerator &rng, unsigned int pbits, unsigned int qbits)

The constructor above creates a new XTR_DH object with the required parameters.

XTR_DH (BufferedTransformation &domainParams)

The constructor above initializes a XTR_DH object from a serialized object created with void DEREncode (BufferedTransformation &domainParams).

Domain Parameters

The following creates XTR-DH domain parameters with security equivalent to a RSA-2048 modulus. It uses p=340 and q=224 (q=256 would work as well). The domain parameters should be generated once and shared between both parties.

AutoSeededRandomPool prng;
XTR_DH xtr_params(prng, 340, 224);

The constructor eventually calls XTR_FindPrimesAndGenerator from xtr.cpp.

The parameters can be serialized with DEREncode (BufferedTransformation &domainParams).

You can print the domain parameters with the following code:

$ cat test.cxx
#include "cryptlib.h"
#include "osrng.h"
#include "xtrcrypt.h"
#include <iostream>

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    AutoSeededRandomPool aSRP;
    XTR_DH xtr(aSRP, 340, 224);

    std::cout << "Prime: " << std::hex << xtr.GetModulus() << std::endl;
    std::cout << "Order: " << std::hex << xtr.GetSubgroupOrder() << std::endl;
    std::cout << "Generator" << std::endl;
    std::cout << "  c1: " << std::hex << xtr.GetSubgroupGenerator().c1 << std::endl;
    std::cout << "  c2: " << std::hex << xtr.GetSubgroupGenerator().c2 << std::endl;

    return 0;
}

Running the program with artificially small parameters results in:

$ ./test.exe
Prime: 2d4c4f9f4de9e32e84a7be42f019a1a4139e0fe7489h
Order: 89ab07fa5115443f51ce9a74283affaae2d7748fh
Generator
  c1: 684fedbae519cb297f3448d5e564838ede5ed1fb81h
  c2: 39112823212ccd7b01f10377536f51bf855752c7a3h

An easy way to serialize your domain parameters is to save them using ASN.1 as shown below.

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    AutoSeededRandomPool prng;
    XTR_DH xtr(prng, 170, 160);
    xtrA.DEREncode(FileSink("params.der").Ref());
    ...

    return 0;
}

Once the parameters have been generated then all clients use the same parameters during key agreement.

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    AutoSeededRandomPool prng;
    XTR_DH xtrA(FileSource("params.der", true).Ref());
    XTR_DH xtrB(FileSource("params.der", true).Ref());

    if(xtrA.Validate(prng, 3) == false)
        throw std::runtime_error("Failed to validate parameters");

    if(xtrB.Validate(prng, 3) == false)
        throw std::runtime_error("Failed to validate parameters");

    ...

    return 0;
}

You can inspect the serialized domain parameters with tools like dumpasn1 like shown below.

$ dumpasn1 params.der
  0  94: SEQUENCE {
  2  22:   INTEGER 02 EE 07 6B 32 54 C1 52 01 51 BB E0 39 1A 77 97 1F 92 E2 77 BA 37
 26  21:   INTEGER 00 F7 67 4A 8C 2D D6 8D 32 C3 DA 8E 74 87 4A 48 B9 AD F0 0F CB
 49  21:   INTEGER 2D 46 9E 63 B4 74 AC 45 57 8A 00 27 A3 88 64 F3 03 FA D0 3B A9
 72  22:   INTEGER 01 D5 E5 71 4B C1 9E F2 5E EE 05 35 58 41 76 88 9D F8 F2 6C 48 02
       :   }

Key Pair

The following creates a XTR-DH ephemeral keypair for an instance run using the domain parameters. Recall that "ephemeral" means "transient" or "temporary", and each run of the protocol should generate a new ephemeral keypair. The keys are not saved for subsequent use.

AutoSeededRandomPool prng;
XTR_DH params(prng, 340, 224);

SecByteBlock priv(params.PrivateKeyLength()), pub(params.PublicKeyLength());
params.GenerateKeyPair(GlobalRNG(), priv, pub);

You can then use Agree to arrive at a shared secret with the other party as shown in Crypto++ Validation. Note that the exchange is not authenticated so you should protect the exchange with signatures.