使用Crypto ++的ECDH类的公钥坐标

时间:2015-10-18 13:19:28

标签: c++ crypto++ elliptic-curve diffie-hellman

我使用crypto ++进行ECDH密钥协议

ECDH.Agree(key, privateKey, outherpublicKey);

鉴于公钥,我只有X和Y坐标。如何从这个值生成publicKey?

ECDH.Agree(key,privateKey, getPublicKey(X,Y))

提前致谢

1 个答案:

答案 0 :(得分:0)

  

鉴于公钥,我只有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}坐标,我们需要弄清楚库是如何使用它的。短暂的公钥和私钥是在第1380行的pubkey.h中创建的。它们的代码如下:

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> &params = GetAbstractGroupParameters();
    Integer x(privateKey, PrivateKeyLength());
    Element y = params.ExponentiateBase(x);
    params.EncodeElement(true, y, publicKey);
}

上面的兴趣点是params.EncodeElement(true, y, publicKey)。要查看正在发生的情况,我们需要查看第70行周围的eccrypto.h,并注意reversibletrue

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。为了看看它是做什么的,我们可以在第120行检查ecp.cpp。例程写一个未压缩的点,但阻塞xy公共元素的最大大小,应该是字段大小或子组顺序。

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[]

最后一个问题是字段元素的最大大小。这似乎是模数大小减去1,以字节为单位:

$ grep -I -A 1 MaxElementByteLength modarith.h 
    unsigned int MaxElementByteLength() const
        {return (m_modulus-1).ByteCount();}

<强> 协议

鉴于以上信息,这是你应该做的。您需要在x中提供yECP::Point q(x,y)的值。它们只是Crypto ++ Integers。

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 ++的Elliptic Curve Diffie-Hellman维基页面,以便其他人不必为此进行搜索。