使用 Crypto++ 计算 ECDSA<ECP, SHA256> 密钥的共享秘密

Compute shared secret for ECDSA<ECP, SHA256> keys with Crypto++

我正在尝试执行以下操作:

  1. 接收 EC public 键的 x 和 y 坐标
  2. 生成随机 EC public 密钥
  3. 计算两个密钥的共享密钥

我卡在了最后一步,从文档看来我必须使用 ECDH<ECP>::Domain 但没有任何地方解释如何将密钥转换为所需的 SecByteBlock 对象,如何我可以这样做吗?伪代码如下。

std::string x = ...
std::string y = ...

auto make_curve = []{ return ASN1::secp256r1(); };

// Public key
ECDSA<ECP, SHA256>::PublicKey g_a;
g_a.Initialize(make_curve(),
               ECP::Point {
                   Integer { x.data() },
                   Integer { y.data() }
               });

// Private key
ECDSA<ECP, SHA256>::PrivateKey g_b;
g_b.Initialize(RANDOM_POOL, make_curve());

// Compute shared secret
ECDH<ECP>::Domain agreement { make_curve() };

SecByteBlock shared_secret_buf { agreement.AgreedValueLength() };

agreement.Agree(shared_secret_buf, ???, ???);

Wikipedia page 显示您要执行此操作:

所以首先创建一个新的密钥对(你永远不会只生成一个私钥):

ECDH < ECP >::Domain dhB( CURVE );
SecByteBlock privB(dhB.PrivateKeyLength()), pubB(dhB.PublicKeyLength());
dhB.GenerateKeyPair(rng, privB, pubB);

然后你可以像这样执行密钥协议:

if(!dhB.Agree(shared_secret_buf, privB, pubA))
    throw runtime_error("Failed to reach shared secret (B)");

好的,现在剩下一个问题:对 public 点进行编码。幸运的是,这在 Wiki 中也有解释,here,基本上你应该可以使用:

void ECP::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed)

你的 pubA 缓冲区放在 &bt 中(我希望 &P 的输入很清楚,使用 false 进行压缩)。

基本上这个returns一个字节04,然后用字段的大小(big endian)编码的X和Y的串联。

请注意,这只需要一个 ECP::Point,并且由于密钥对生成也不使用 ECDSA,因此可以完全删除这部分代码。这很好,因为 ECDH 是一种不同的算法,使用 ECDSA 可能会使代码的可移植性降低,例如使用X25519曲线时。