使用 Crypto++ 库仅从 x 压缩坐标中检索 ECDSA public 密钥
Retrieve ECDSA public key from only x-compressed coordinate using Crypto++ library
我正在车载通信范围内实施安全守护程序。
我可以收到一条带有签名的消息和一个点的压缩 X 坐标来验证该签名。椭圆曲线可以是secp256也可以是brainpoolp256r1算法是ECDSA
我的问题是:我如何才能恢复 ECC 点(以及 public 密钥),仅给出压缩的 X 坐标与 Crypto++ 库?
我点击了一些解释它的链接(以及许多其他链接)https://www.cryptopp.com/wiki/Point_Compression Crypto++ and Compressed EC keys,但它们不适合我的问题。
我尝试生成代码来解决问题,但它不起作用:
#include <string>
#include <iostream>
#include <cryptopp/cryptlib.h>
#include <cryptopp/ecp.h>
#include <cryptopp/eccrypto.h>
#include <cryptopp/hex.h>
#include <cryptopp/oids.h>
#include <cryptopp/osrng.h>
using namespace CryptoPP;
using std::cout;
using std::endl;
using std::string;
int main()
{
string compactPoint = "937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3";
AutoSeededRandomPool generator;
ECDSA<ECP, SHA256>::PublicKey pubKey;
OID curve = ASN1::secp256r1();
StringSource ss (compactPoint, true, new CryptoPP::HexDecoder);
ECP::Point point;
pubKey.GetGroupParameters().GetCurve().DecodePoint (point, ss, ss.MaxRetrievable());
std::cout << "Result after decompression X: " << std::hex << point.x << std::endl;
std::cout << "Result after decompression Y: " << std::hex << point.y << std::endl;
return 0;
}
你能帮帮我吗?
最简单的解决方案可能是在 compact representation 前面加上 "02"
oe "03"
。 Crypto++ 然后将其解码为压缩的 public 密钥。
$ cat test.cxx
#include "cryptlib.h"
#include "eccrypto.h"
#include "ecp.h"
#include "hex.h"
#include "oids.h"
#include <string>
#include <iostream>
#include <iomanip>
int main(int argc, char* argv[])
{
using namespace CryptoPP;
ECDSA<ECP, SHA256>::PublicKey pubKey;
pubKey.AccessGroupParameters().Initialize(ASN1::secp256r1());
std::string compactPoint = "02" /* compressed */
"937120662418500f3ad7c892b1db7e7c"
"2d85ec48c74e99d64dcb7083082bb4f3";
StringSource ss (compactPoint, true, new HexDecoder);
ECP::Point point;
pubKey.GetGroupParameters().GetCurve().DecodePoint (point, ss, ss.MaxRetrievable());
std::cout << "Result after decompression X: " << std::hex << point.x << std::endl;
std::cout << "Result after decompression Y: " << std::hex << point.y << std::endl;
return 0;
}
然后构建和 运行 程序。请注意,库解决了坐标的 y
部分。
cryptopp$ g++ test.cxx ./libcryptopp.a -o test.exe
cryptopp$ ./test.exe
Result after decompression X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Result after decompression Y: cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h
为了省去查找的麻烦,您可以使用以下方法为 publicKey
设置 public 元素:
pubKey.SetPublicElement(point);
std::cout << "X: " << std::hex << pubKey.GetPublicElement().x << std::endl;
std::cout << "Y: " << std::hex << pubKey.GetPublicElement().y << std::endl;
运行 附加代码产生预期结果:
$ ./test.exe
Result after decompression X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Result after decompression Y: cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h
X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Y: cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h
如果有兴趣,这里是您用来解码来自 ecp.cpp
的点的代码:
bool ECP::DecodePoint(ECP::Point &P, BufferedTransformation &bt, size_t encodedPointLen) const
{
byte type;
if (encodedPointLen < 1 || !bt.Get(type))
return false;
switch (type)
{
case 0:
P.identity = true;
return true;
case 2:
case 3:
{
if (encodedPointLen != EncodedPointSize(true))
return false;
Integer p = FieldSize();
P.identity = false;
P.x.Decode(bt, GetField().MaxElementByteLength());
P.y = ((P.x*P.x+m_a)*P.x+m_b) % p;
if (Jacobi(P.y, p) !=1)
return false;
P.y = ModularSquareRoot(P.y, p);
if ((type & 1) != P.y.GetBit(0))
P.y = p-P.y;
return true;
}
case 4:
{
if (encodedPointLen != EncodedPointSize(false))
return false;
unsigned int len = GetField().MaxElementByteLength();
P.identity = false;
P.x.Decode(bt, len);
P.y.Decode(bt, len);
return true;
}
default:
return false;
}
}
如果您想自己解决 y
坐标,请填充 point
,然后直接调用 SetPublicElement
。
您也可以在前面加上 03
而不是 02
。不同之处在于,解码 returns 要么 y
要么 p-y
。由于上面显示的模块化平方根,引入了可变性。我们需要查看生成算法来确定该值应该是多少。
这是使用 03
而不是 02
的区别:
$ ./test.exe
X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Y: 303508b051c3113b66c6d70fb68f3010cbc46595dd8d8057e6d942de0da913a9h
注意 03
生成 y
坐标 303508b051c3113b66c6d70fb68f3010cbc46595dd8d8057e6d942de0da913a9h
而不是 02
和 cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h
.
我正在车载通信范围内实施安全守护程序。
我可以收到一条带有签名的消息和一个点的压缩 X 坐标来验证该签名。椭圆曲线可以是secp256也可以是brainpoolp256r1算法是ECDSA
我的问题是:我如何才能恢复 ECC 点(以及 public 密钥),仅给出压缩的 X 坐标与 Crypto++ 库?
我点击了一些解释它的链接(以及许多其他链接)https://www.cryptopp.com/wiki/Point_Compression Crypto++ and Compressed EC keys,但它们不适合我的问题。
我尝试生成代码来解决问题,但它不起作用:
#include <string>
#include <iostream>
#include <cryptopp/cryptlib.h>
#include <cryptopp/ecp.h>
#include <cryptopp/eccrypto.h>
#include <cryptopp/hex.h>
#include <cryptopp/oids.h>
#include <cryptopp/osrng.h>
using namespace CryptoPP;
using std::cout;
using std::endl;
using std::string;
int main()
{
string compactPoint = "937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3";
AutoSeededRandomPool generator;
ECDSA<ECP, SHA256>::PublicKey pubKey;
OID curve = ASN1::secp256r1();
StringSource ss (compactPoint, true, new CryptoPP::HexDecoder);
ECP::Point point;
pubKey.GetGroupParameters().GetCurve().DecodePoint (point, ss, ss.MaxRetrievable());
std::cout << "Result after decompression X: " << std::hex << point.x << std::endl;
std::cout << "Result after decompression Y: " << std::hex << point.y << std::endl;
return 0;
}
你能帮帮我吗?
最简单的解决方案可能是在 compact representation 前面加上 "02"
oe "03"
。 Crypto++ 然后将其解码为压缩的 public 密钥。
$ cat test.cxx
#include "cryptlib.h"
#include "eccrypto.h"
#include "ecp.h"
#include "hex.h"
#include "oids.h"
#include <string>
#include <iostream>
#include <iomanip>
int main(int argc, char* argv[])
{
using namespace CryptoPP;
ECDSA<ECP, SHA256>::PublicKey pubKey;
pubKey.AccessGroupParameters().Initialize(ASN1::secp256r1());
std::string compactPoint = "02" /* compressed */
"937120662418500f3ad7c892b1db7e7c"
"2d85ec48c74e99d64dcb7083082bb4f3";
StringSource ss (compactPoint, true, new HexDecoder);
ECP::Point point;
pubKey.GetGroupParameters().GetCurve().DecodePoint (point, ss, ss.MaxRetrievable());
std::cout << "Result after decompression X: " << std::hex << point.x << std::endl;
std::cout << "Result after decompression Y: " << std::hex << point.y << std::endl;
return 0;
}
然后构建和 运行 程序。请注意,库解决了坐标的 y
部分。
cryptopp$ g++ test.cxx ./libcryptopp.a -o test.exe
cryptopp$ ./test.exe
Result after decompression X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Result after decompression Y: cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h
为了省去查找的麻烦,您可以使用以下方法为 publicKey
设置 public 元素:
pubKey.SetPublicElement(point);
std::cout << "X: " << std::hex << pubKey.GetPublicElement().x << std::endl;
std::cout << "Y: " << std::hex << pubKey.GetPublicElement().y << std::endl;
运行 附加代码产生预期结果:
$ ./test.exe
Result after decompression X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Result after decompression Y: cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h
X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Y: cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h
如果有兴趣,这里是您用来解码来自 ecp.cpp
的点的代码:
bool ECP::DecodePoint(ECP::Point &P, BufferedTransformation &bt, size_t encodedPointLen) const
{
byte type;
if (encodedPointLen < 1 || !bt.Get(type))
return false;
switch (type)
{
case 0:
P.identity = true;
return true;
case 2:
case 3:
{
if (encodedPointLen != EncodedPointSize(true))
return false;
Integer p = FieldSize();
P.identity = false;
P.x.Decode(bt, GetField().MaxElementByteLength());
P.y = ((P.x*P.x+m_a)*P.x+m_b) % p;
if (Jacobi(P.y, p) !=1)
return false;
P.y = ModularSquareRoot(P.y, p);
if ((type & 1) != P.y.GetBit(0))
P.y = p-P.y;
return true;
}
case 4:
{
if (encodedPointLen != EncodedPointSize(false))
return false;
unsigned int len = GetField().MaxElementByteLength();
P.identity = false;
P.x.Decode(bt, len);
P.y.Decode(bt, len);
return true;
}
default:
return false;
}
}
如果您想自己解决 y
坐标,请填充 point
,然后直接调用 SetPublicElement
。
您也可以在前面加上 03
而不是 02
。不同之处在于,解码 returns 要么 y
要么 p-y
。由于上面显示的模块化平方根,引入了可变性。我们需要查看生成算法来确定该值应该是多少。
这是使用 03
而不是 02
的区别:
$ ./test.exe
X: 937120662418500f3ad7c892b1db7e7c2d85ec48c74e99d64dcb7083082bb4f3h
Y: 303508b051c3113b66c6d70fb68f3010cbc46595dd8d8057e6d942de0da913a9h
注意 03
生成 y
坐标 303508b051c3113b66c6d70fb68f3010cbc46595dd8d8057e6d942de0da913a9h
而不是 02
和 cfcaf74eae3ceec5993928f04970cfef343b9a6b22727fa81926bd21f256ec56h
.