2017-01-27 12:05:45 +00:00
|
|
|
|
// mqv.h - originally written and placed in the public domain by Wei Dai
|
2015-11-23 00:17:15 +00:00
|
|
|
|
|
|
|
|
|
//! \file mqv.h
|
|
|
|
|
//! \brief Classes for Menezes–Qu–Vanstone (MQV) key agreement
|
|
|
|
|
|
2015-11-05 06:59:46 +00:00
|
|
|
|
#ifndef CRYPTOPP_MQV_H
|
|
|
|
|
#define CRYPTOPP_MQV_H
|
|
|
|
|
|
|
|
|
|
#include "cryptlib.h"
|
|
|
|
|
#include "gfpcrypt.h"
|
2015-11-18 20:32:28 +00:00
|
|
|
|
#include "modarith.h"
|
2015-11-05 06:59:46 +00:00
|
|
|
|
#include "integer.h"
|
2015-12-04 23:18:34 +00:00
|
|
|
|
#include "algebra.h"
|
2015-11-05 06:59:46 +00:00
|
|
|
|
#include "misc.h"
|
|
|
|
|
|
|
|
|
|
NAMESPACE_BEGIN(CryptoPP)
|
|
|
|
|
|
2015-11-23 00:17:15 +00:00
|
|
|
|
//! \class MQV_Domain
|
|
|
|
|
//! \brief MQV domain for performing authenticated key agreement
|
|
|
|
|
//! \tparam GROUP_PARAMETERS doamin parameters
|
|
|
|
|
//! \tparam COFACTOR_OPTION cofactor option
|
2016-12-27 17:34:57 +00:00
|
|
|
|
//! \details GROUP_PARAMETERS parameters include the curve coefcients and the base point.
|
2015-11-23 00:17:15 +00:00
|
|
|
|
//! Binary curves use a polynomial to represent its characteristic, while prime curves
|
|
|
|
|
//! use a prime number.
|
2016-09-08 18:30:01 +00:00
|
|
|
|
//! \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain
|
2016-12-03 10:05:56 +00:00
|
|
|
|
template <class GROUP_PARAMETERS, class COFACTOR_OPTION = typename GROUP_PARAMETERS::DefaultCofactorOption>
|
2015-11-05 06:59:46 +00:00
|
|
|
|
class MQV_Domain : public AuthenticatedKeyAgreementDomain
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
typedef GROUP_PARAMETERS GroupParameters;
|
|
|
|
|
typedef typename GroupParameters::Element Element;
|
|
|
|
|
typedef MQV_Domain<GROUP_PARAMETERS, COFACTOR_OPTION> Domain;
|
|
|
|
|
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \brief Construct a MQV domain
|
2015-11-05 06:59:46 +00:00
|
|
|
|
MQV_Domain() {}
|
|
|
|
|
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \brief Construct a MQV domain
|
|
|
|
|
//! \param params group parameters and options
|
2015-11-05 06:59:46 +00:00
|
|
|
|
MQV_Domain(const GroupParameters ¶ms)
|
|
|
|
|
: m_groupParameters(params) {}
|
|
|
|
|
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \brief Construct a MQV domain
|
|
|
|
|
//! \param bt BufferedTransformation with group parameters and options
|
2015-11-05 06:59:46 +00:00
|
|
|
|
MQV_Domain(BufferedTransformation &bt)
|
|
|
|
|
{m_groupParameters.BERDecode(bt);}
|
|
|
|
|
|
2016-01-19 00:21:38 +00:00
|
|
|
|
//! \brief Construct a MQV domain
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \tparam T1 template parameter used as a constructor parameter
|
|
|
|
|
//! \tparam T2 template parameter used as a constructor parameter
|
2016-07-13 19:47:58 +00:00
|
|
|
|
//! \param v1 first parameter
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \param v2 second parameter
|
|
|
|
|
//! \details v1 and v2 are passed directly to the GROUP_PARAMETERS object.
|
2015-11-05 06:59:46 +00:00
|
|
|
|
template <class T1, class T2>
|
|
|
|
|
MQV_Domain(T1 v1, T2 v2)
|
|
|
|
|
{m_groupParameters.Initialize(v1, v2);}
|
2016-01-18 22:03:20 +00:00
|
|
|
|
|
2016-01-19 00:21:38 +00:00
|
|
|
|
//! \brief Construct a MQV domain
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \tparam T1 template parameter used as a constructor parameter
|
|
|
|
|
//! \tparam T2 template parameter used as a constructor parameter
|
|
|
|
|
//! \tparam T3 template parameter used as a constructor parameter
|
2016-07-13 19:47:58 +00:00
|
|
|
|
//! \param v1 first parameter
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \param v2 second parameter
|
|
|
|
|
//! \param v3 third parameter
|
|
|
|
|
//! \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object.
|
2015-11-05 06:59:46 +00:00
|
|
|
|
template <class T1, class T2, class T3>
|
|
|
|
|
MQV_Domain(T1 v1, T2 v2, T3 v3)
|
|
|
|
|
{m_groupParameters.Initialize(v1, v2, v3);}
|
2016-01-18 22:03:20 +00:00
|
|
|
|
|
2016-01-19 00:21:38 +00:00
|
|
|
|
//! \brief Construct a MQV domain
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \tparam T1 template parameter used as a constructor parameter
|
|
|
|
|
//! \tparam T2 template parameter used as a constructor parameter
|
|
|
|
|
//! \tparam T3 template parameter used as a constructor parameter
|
|
|
|
|
//! \tparam T4 template parameter used as a constructor parameter
|
2016-07-13 19:47:58 +00:00
|
|
|
|
//! \param v1 first parameter
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \param v2 second parameter
|
|
|
|
|
//! \param v3 third parameter
|
|
|
|
|
//! \param v4 third parameter
|
|
|
|
|
//! \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object.
|
2015-11-05 06:59:46 +00:00
|
|
|
|
template <class T1, class T2, class T3, class T4>
|
|
|
|
|
MQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4)
|
|
|
|
|
{m_groupParameters.Initialize(v1, v2, v3, v4);}
|
|
|
|
|
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \brief Retrieves the group parameters for this domain
|
|
|
|
|
//! \return the group parameters for this domain as a const reference
|
2015-11-05 06:59:46 +00:00
|
|
|
|
const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
|
2016-01-18 22:03:20 +00:00
|
|
|
|
|
|
|
|
|
//! \brief Retrieves the group parameters for this domain
|
|
|
|
|
//! \return the group parameters for this domain as a non-const reference
|
2015-11-05 06:59:46 +00:00
|
|
|
|
GroupParameters & AccessGroupParameters() {return m_groupParameters;}
|
|
|
|
|
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \brief Retrieves the crypto parameters for this domain
|
|
|
|
|
//! \return the crypto parameters for this domain as a non-const reference
|
2015-11-05 06:59:46 +00:00
|
|
|
|
CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();}
|
|
|
|
|
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \brief Provides the size of the agreed value
|
|
|
|
|
//! \return size of agreed value produced in this domain
|
|
|
|
|
//! \details The length is calculated using <tt>GetEncodedElementSize(false)</tt>, which means the
|
|
|
|
|
//! element is encoded in a non-reversible format. A non-reversible format means its a raw byte array,
|
|
|
|
|
//! and it lacks presentation format like an ASN.1 BIT_STRING or OCTET_STRING.
|
2015-11-05 06:59:46 +00:00
|
|
|
|
unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
|
2016-01-18 22:03:20 +00:00
|
|
|
|
|
|
|
|
|
//! \brief Provides the size of the static private key
|
|
|
|
|
//! \return size of static private keys in this domain
|
|
|
|
|
//! \details The length is calculated using the byte count of the subgroup order.
|
2015-11-05 06:59:46 +00:00
|
|
|
|
unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
|
2016-01-18 22:03:20 +00:00
|
|
|
|
|
|
|
|
|
//! \brief Provides the size of the static public key
|
|
|
|
|
//! \return size of static public keys in this domain
|
|
|
|
|
//! \details The length is calculated using <tt>GetEncodedElementSize(true)</tt>, which means the
|
|
|
|
|
//! element is encoded in a reversible format. A reversible format means it has a presentation format,
|
|
|
|
|
//! and its an ANS.1 encoded element or point.
|
2015-11-05 06:59:46 +00:00
|
|
|
|
unsigned int StaticPublicKeyLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(true);}
|
|
|
|
|
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \brief Generate static private key in this domain
|
|
|
|
|
//! \param rng a RandomNumberGenerator derived class
|
|
|
|
|
//! \param privateKey a byte buffer for the generated private key in this domain
|
|
|
|
|
//! \details The private key is a random scalar used as an exponent in the range <tt>[1,MaxExponent()]</tt>.
|
|
|
|
|
//! \pre <tt>COUNTOF(privateKey) == PrivateStaticKeyLength()</tt>
|
2015-11-05 06:59:46 +00:00
|
|
|
|
void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
|
|
|
|
|
{
|
|
|
|
|
Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
|
|
|
|
|
x.Encode(privateKey, StaticPrivateKeyLength());
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-18 22:03:20 +00:00
|
|
|
|
//! \brief Generate a static public key from a private key in this domain
|
|
|
|
|
//! \param rng a RandomNumberGenerator derived class
|
|
|
|
|
//! \param privateKey a byte buffer with the previously generated private key
|
|
|
|
|
//! \param publicKey a byte buffer for the generated public key in this domain
|
|
|
|
|
//! \details The public key is an element or point on the curve, and its stored in a revrsible format.
|
|
|
|
|
//! A reversible format means it has a presentation format, and its an ANS.1 encoded element or point.
|
|
|
|
|
//! \pre <tt>COUNTOF(publicKey) == PublicStaticKeyLength()</tt>
|
2015-11-05 06:59:46 +00:00
|
|
|
|
void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
|
|
|
|
|
{
|
|
|
|
|
CRYPTOPP_UNUSED(rng);
|
|
|
|
|
const DL_GroupParameters<Element> ¶ms = GetAbstractGroupParameters();
|
|
|
|
|
Integer x(privateKey, StaticPrivateKeyLength());
|
|
|
|
|
Element y = params.ExponentiateBase(x);
|
|
|
|
|
params.EncodeElement(true, y, publicKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();}
|
|
|
|
|
unsigned int EphemeralPublicKeyLength() const {return StaticPublicKeyLength();}
|
|
|
|
|
|
|
|
|
|
void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
|
|
|
|
|
{
|
|
|
|
|
const DL_GroupParameters<Element> ¶ms = GetAbstractGroupParameters();
|
|
|
|
|
Integer x(rng, Integer::One(), params.GetMaxExponent());
|
|
|
|
|
x.Encode(privateKey, StaticPrivateKeyLength());
|
|
|
|
|
Element y = params.ExponentiateBase(x);
|
|
|
|
|
params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
|
|
|
|
|
{
|
|
|
|
|
CRYPTOPP_UNUSED(rng);
|
|
|
|
|
memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Agree(byte *agreedValue,
|
2016-07-13 19:47:58 +00:00
|
|
|
|
const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
|
2015-11-05 06:59:46 +00:00
|
|
|
|
const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
|
|
|
|
|
bool validateStaticOtherPublicKey=true) const
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
const DL_GroupParameters<Element> ¶ms = GetAbstractGroupParameters();
|
|
|
|
|
Element WW = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey);
|
|
|
|
|
Element VV = params.DecodeElement(ephemeralOtherPublicKey, true);
|
|
|
|
|
|
|
|
|
|
Integer s(staticPrivateKey, StaticPrivateKeyLength());
|
|
|
|
|
Integer u(ephemeralPrivateKey, StaticPrivateKeyLength());
|
|
|
|
|
Element V = params.DecodeElement(ephemeralPrivateKey+StaticPrivateKeyLength(), false);
|
|
|
|
|
|
|
|
|
|
const Integer &r = params.GetSubgroupOrder();
|
|
|
|
|
Integer h2 = Integer::Power2((r.BitCount()+1)/2);
|
|
|
|
|
Integer e = ((h2+params.ConvertElementToInteger(V)%h2)*s+u) % r;
|
|
|
|
|
Integer tt = h2 + params.ConvertElementToInteger(VV) % h2;
|
|
|
|
|
|
|
|
|
|
if (COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION)
|
|
|
|
|
{
|
|
|
|
|
Element P = params.ExponentiateElement(WW, tt);
|
|
|
|
|
P = m_groupParameters.MultiplyElements(P, VV);
|
|
|
|
|
Element R[2];
|
|
|
|
|
const Integer e2[2] = {r, e};
|
|
|
|
|
params.SimultaneousExponentiate(R, P, e2, 2);
|
|
|
|
|
if (!params.IsIdentity(R[0]) || params.IsIdentity(R[1]))
|
|
|
|
|
return false;
|
|
|
|
|
params.EncodeElement(false, R[1], agreedValue);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const Integer &k = params.GetCofactor();
|
|
|
|
|
if (COFACTOR_OPTION::ToEnum() == COMPATIBLE_COFACTOR_MULTIPLICTION)
|
|
|
|
|
e = ModularArithmetic(r).Divide(e, k);
|
|
|
|
|
Element P = m_groupParameters.CascadeExponentiate(VV, k*e, WW, k*(e*tt%r));
|
|
|
|
|
if (params.IsIdentity(P))
|
|
|
|
|
return false;
|
|
|
|
|
params.EncodeElement(false, P, agreedValue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (DL_BadElement &)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;}
|
|
|
|
|
const DL_GroupParameters<Element> & GetAbstractGroupParameters() const {return m_groupParameters;}
|
|
|
|
|
|
|
|
|
|
GroupParameters m_groupParameters;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//! Menezes-Qu-Vanstone in GF(p) with key validation, AKA <a href="http://www.weidai.com/scan-mirror/ka.html#MQV">MQV</a>
|
2016-09-08 18:30:01 +00:00
|
|
|
|
//! \sa MQV, HMQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain
|
2015-11-05 06:59:46 +00:00
|
|
|
|
typedef MQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> MQV;
|
|
|
|
|
|
|
|
|
|
NAMESPACE_END
|
|
|
|
|
|
|
|
|
|
#endif
|