1#ifndef CRYPTOPP_MQV_H
2#define CRYPTOPP_MQV_H
3
4/** \file
5*/
6
7#include "gfpcrypt.h"
8
9NAMESPACE_BEGIN(CryptoPP)
10
11//! _
12template <class GROUP_PARAMETERS, class COFACTOR_OPTION = CPP_TYPENAME GROUP_PARAMETERS::DefaultCofactorOption>
13class MQV_Domain : public AuthenticatedKeyAgreementDomain
14{
15public:
16	typedef GROUP_PARAMETERS GroupParameters;
17	typedef typename GroupParameters::Element Element;
18	typedef MQV_Domain<GROUP_PARAMETERS, COFACTOR_OPTION> Domain;
19
20	MQV_Domain() {}
21
22	MQV_Domain(const GroupParameters &params)
23		: m_groupParameters(params) {}
24
25	MQV_Domain(BufferedTransformation &bt)
26		{m_groupParameters.BERDecode(bt);}
27
28	template <class T1, class T2>
29	MQV_Domain(T1 v1, T2 v2)
30		{m_groupParameters.Initialize(v1, v2);}
31
32	template <class T1, class T2, class T3>
33	MQV_Domain(T1 v1, T2 v2, T3 v3)
34		{m_groupParameters.Initialize(v1, v2, v3);}
35
36	template <class T1, class T2, class T3, class T4>
37	MQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4)
38		{m_groupParameters.Initialize(v1, v2, v3, v4);}
39
40	const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
41	GroupParameters & AccessGroupParameters() {return m_groupParameters;}
42
43	CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();}
44
45	unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
46	unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
47	unsigned int StaticPublicKeyLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(true);}
48
49	void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
50	{
51		Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
52		x.Encode(privateKey, StaticPrivateKeyLength());
53	}
54
55	void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
56	{
57		const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
58		Integer x(privateKey, StaticPrivateKeyLength());
59		Element y = params.ExponentiateBase(x);
60		params.EncodeElement(true, y, publicKey);
61	}
62
63	unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();}
64	unsigned int EphemeralPublicKeyLength() const {return StaticPublicKeyLength();}
65
66	void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
67	{
68		const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
69		Integer x(rng, Integer::One(), params.GetMaxExponent());
70		x.Encode(privateKey, StaticPrivateKeyLength());
71		Element y = params.ExponentiateBase(x);
72		params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
73	}
74
75	void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
76	{
77		memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
78	}
79
80	bool Agree(byte *agreedValue,
81		const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
82		const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
83		bool validateStaticOtherPublicKey=true) const
84	{
85		try
86		{
87			const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
88			Element WW = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey);
89			Element VV = params.DecodeElement(ephemeralOtherPublicKey, true);
90
91			Integer s(staticPrivateKey, StaticPrivateKeyLength());
92			Integer u(ephemeralPrivateKey, StaticPrivateKeyLength());
93			Element V = params.DecodeElement(ephemeralPrivateKey+StaticPrivateKeyLength(), false);
94
95			const Integer &r = params.GetSubgroupOrder();
96			Integer h2 = Integer::Power2((r.BitCount()+1)/2);
97			Integer e = ((h2+params.ConvertElementToInteger(V)%h2)*s+u) % r;
98			Integer tt = h2 + params.ConvertElementToInteger(VV) % h2;
99
100			if (COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION)
101			{
102				Element P = params.ExponentiateElement(WW, tt);
103				P = m_groupParameters.MultiplyElements(P, VV);
104				Element R[2];
105				const Integer e2[2] = {r, e};
106				params.SimultaneousExponentiate(R, P, e2, 2);
107				if (!params.IsIdentity(R[0]) || params.IsIdentity(R[1]))
108					return false;
109				params.EncodeElement(false, R[1], agreedValue);
110			}
111			else
112			{
113				const Integer &k = params.GetCofactor();
114				if (COFACTOR_OPTION::ToEnum() == COMPATIBLE_COFACTOR_MULTIPLICTION)
115					e = ModularArithmetic(r).Divide(e, k);
116				Element P = m_groupParameters.CascadeExponentiate(VV, k*e, WW, k*(e*tt%r));
117				if (params.IsIdentity(P))
118					return false;
119				params.EncodeElement(false, P, agreedValue);
120			}
121		}
122		catch (DL_BadElement &)
123		{
124			return false;
125		}
126		return true;
127	}
128
129private:
130	DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;}
131	const DL_GroupParameters<Element> & GetAbstractGroupParameters() const {return m_groupParameters;}
132
133	GroupParameters m_groupParameters;
134};
135
136//! Menezes-Qu-Vanstone in GF(p) with key validation, AKA <a href="http://www.weidai.com/scan-mirror/ka.html#MQV">MQV</a>
137typedef MQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> MQV;
138
139NAMESPACE_END
140
141#endif
142