【问题标题】:Using public key coordinate with Crypto++'s ECDH class在 Crypto++ 的 ECDH 类中使用公钥坐标
【发布时间】:2015-10-18 13:19:28
【问题描述】:

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

ECDH.Agree(key, privateKey, outherpublicKey);

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

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

提前致谢

【问题讨论】:

  • “鉴于公钥我只有 X 和 Y 坐标...” - 原谅我的无知(所以我很清楚...),哪个公钥是吗?它是用于 ECDH 协议的临时临时密钥,还是长期静态密钥?
  • 临时性的,在每个密钥建立时,我将 X,Y 坐标发送到此函数以生成新的会话密钥
  • 如果您能告诉我如何从公钥生成 X、Y 以及如何使用它们(我的主要目标),那就太好了。谢谢

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


【解决方案1】:

鉴于公钥我只有 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,并注意 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。要查看它的作用,我们可以在第 120 行附近检查 ecp.cpp。该例程写入一个未压缩的点,但在公共元素的最大大小(应该是字段大小或子组顺序)上阻止 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();}

协议

鉴于以上信息,您应该这样做。您需要在ECP::Point q(x,y) 中提供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++ 的 Elliptic Curve Diffie-Hellman wiki 页面,这样其他人就不必去翻找它了。

【讨论】:

  • 我从您的知识中受益,并问您,当我使用 GenerateKeyPair 时,如何从生成的公钥中获取 X,Y 坐标?
  • @Singa - 问一个新问题。我不介意回答它们,但我们应该保持问题/答案的针对性和重点。
  • @SingaCpp 如何从生成的公钥中获取 X、Y 坐标?你找到解决方案了吗
猜你喜欢
  • 2019-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多