Я использую crypto ++ для согласования ключей ECDH
ECDH.Agree(key, privateKey, outherpublicKey);
Учитывая, что для открытого ключа у меня есть только координаты X и Y. Как сгенерировать publicKey из этих значений?
ECDH.Agree(key,privateKey, getPublicKey(X,Y))
заранее спасибо
Учитывая, что для открытого ключа у меня есть только координаты X и Y. Как сгенерировать publicKey из этих значений?
ECDH.Agree(key,privateKey, getPublicKey(X,Y))
{x,y}
это точка на кривой, но с ней никогда не было так легко работать напрямую.
Это все, что мы действительно хотим сделать, но это не работает. Проблема в ECDH::Domain
только параметры домена. Публичная точка и частный показатель расположены сверху.
OID curve = ASN1::secp256r1();
DL_GroupParameters_EC<ECP> params(curve);
Integer x("...");
Integer y("...");
ECP::Point q(x, y);
DL_PublicKey_EC<ECP> pubKey;
pubKey.Initialize(params, q);
ECDH < ECP >::Domain theirs(pubKey);
Чтобы еще больше усложнить ситуацию, ключи, создаваемые протоколом ECDH, являются временными или эфемерными. Они не предназначены для сохранения; скорее они предназначены для однократного использования и выбрасываются. Таким образом, Crypto ++ не позволяет легко их сохранять (например, предоставляя DEREncode
).
Анализ
Чтобы использовать {x,y}
координат, нам нужно выяснить, как библиотека использует его. Эфемерный открытый и закрытый ключи создаются в pubkey.h
вокруг строки 1380. Код для них ниже:
void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey)
{
Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
x.Encode(privateKey, PrivateKeyLength());
}
void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey)
{
const DL_GroupParameters<T> ¶ms = GetAbstractGroupParameters();
Integer x(privateKey, PrivateKeyLength());
Element y = params.ExponentiateBase(x);
params.EncodeElement(true, y, publicKey);
}
Интересующая линия выше — это params.EncodeElement(true, y, publicKey)
, Чтобы увидеть, что там происходит, нам нужно посмотреть на eccrypto.h
вокруг линии 70, и обратите внимание, что reversible
является true
:
void EncodeElement(bool reversible, const Element &element, byte *encoded)
{
if (reversible)
GetCurve().EncodePoint(encoded, element, m_compress);
else
element.x.Encode(encoded, GetEncodedElementSize(false));
}
params.EncodeElement
звонки ECP::EncodePoint
, Чтобы увидеть, что это делает, мы можем изучить ecp.cpp
вокруг линии 120. Процедура записывает несжатую точку, но блокирует x
а также y
на максимальный размер публичного элемента, который должен быть размером поля или порядком подгруппы.
void ECP::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed)
{
if (P.identity)
NullStore().TransferTo(bt, EncodedPointSize(compressed));
else if (compressed)
{
bt.Put(2 + P.y.GetBit(0));
P.x.Encode(bt, GetField().MaxElementByteLength());
}
else
{
unsigned int len = GetField().MaxElementByteLength();
bt.Put(4); // uncompressed
P.x.Encode(bt, len);
P.y.Encode(bt, len);
}
}
Не беспокойся о BufferedTransformation
, Есть способы превратить byte[]
в один, и это произошло до кода, показанного выше. Если вы проследите код, вы увидите его преобразованный через ArraySource
:
byte myArray[PublicEphemeralKeyLength()];
ArraySource as(myArray, COUNTOF(myArray));
Выше, as
это BufferedTransformation
это оборачивает byte[]
Вы прошли в функцию.
Последний открытый вопрос — это максимальный размер элемента поля. Похоже, что это размер модуля меньше единицы в байтах:
$ grep -I -A 1 MaxElementByteLength modarith.h
unsigned int MaxElementByteLength() const
{return (m_modulus-1).ByteCount();}
соглашение
Учитывая вышеизложенную информацию, вот что вы должны сделать. Вы должны предоставить значения для x
а также y
в ECP::Point q(x,y)
, Это просто целые числа Crypto ++.
OID curve = ASN1::secp256r1();
DL_GroupParameters_EC<ECP> params(curve);
size_t size = params.GetEncodedElementSize(true);
vector<byte> othersPublicKey(size);
ECP::Point q(x,y);
params.EncodeElement(true, q, &othersPublicKey[0]);
Тогда вы можете позвонить:
ecdh.Agree(key, myPrivateKey, &othersPublicKey[0]);
Одна запись: params.GetEncodedElementSize(true)
должен равняться PublicEphemeralKeyLength()
, Если они не равны, значит что-то не так.
Если вам нужно изменить сжатие, то вы можете:
params.SetPointCompression(true);
Я добавлю это в Crypto ++ Эллиптическая кривая Диффи-Хеллмана вики-страница, так что другие не должны искать ее.
Других решений пока нет …