gpt4 book ai didi

c++ - 在 ECIES 中使用之前生成的私钥

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:01:33 25 4
gpt4 key购买 nike

我想使用 ECIES 加密/解密数据,为此我正在使用 cryptopp。

AutoSeededRandomPool prng;

//get private key generated
ECIES<ECP>::Decryptor d0(prng, ASN1::secp256r1());
PrintPrivateKey(d0.GetKey());

//get public key
ECIES<ECP>::Encryptor e0(d0);
PrintPublicKey(e0.GetKey());

//encrypt the message
string em0; // encrypted message
StringSource ss1 (message, true, new PK_EncryptorFilter(prng, e0, new StringSink(em0) ) );

//decrypt the message
string dm0; // decrypted message
StringSource ss2 (em0, true, new PK_DecryptorFilter(prng, d1, new StringSink(dm0) ) );

其他一切都很好,但我想使用已经生成的“私钥”而不是随机生成的“私钥”来完成上述相同的事情,这与上面的情况不同。我该怎么做?

我试过下面的代码,但它只是简单地崩溃了

AutoSeededRandomPool prng;

std::string privatekeyString="02C200102C180F9E6A4E7A2F58B5BE86BC179478";

CryptoPP::HexDecoder decoder;
decoder.Put((byte*)privatekeyString.data(), privatekeyString.size());
decoder.MessageEnd();

ECIES<ECP> ::Decryptor d0;
d0.AccessKey().AccessGroupParameters().Initialize(ASN1::secp128r1());

崩溃点

//load private key  
d0.AccessKey().Load(decoder);
PrintPrivateKey(d0.GetKey());

//get public key
ECIES<ECP>::Encryptor e0(d0);
PrintPublicKey(e0.GetKey());

string em0; // encrypted message
StringSource ss1(message, true, new PK_EncryptorFilter(prng, e0, new StringSink(em0) ) );
cout<<"encrypted msg: "<<em0<<" and its length: "<<em0.length()<<endl;

string dm0; // decrypted message
StringSource ss2 (em0, true, new PK_DecryptorFilter(prng, d0, new StringSink(dm0) ) );
cout <<"decrypted msg: "<< dm0<<" and its length: "<<dm0.length() << endl;

编辑2

作为对@jww 回答的回应,我设法使用私钥将消息解码为:

  try
{
AutoSeededRandomPool prng;

std::string exponent="AsIAECwYD55qTnovWLW+hrwXlHg=";
StringSource ss(exponent, true /*pumpAll*/, new CryptoPP::HexDecoder);


Integer x;
x.Decode(ss, ss.MaxRetrievable(), Integer::UNSIGNED);
// cout << "Exponent: " << std::hex << x << endl;

ECIES<ECP>::Decryptor decryptor;
decryptor.AccessKey().Initialize(ASN1::secp128r1(), x);

bool valid = decryptor.AccessKey().Validate(prng, 3);
if(!valid)
{
cout<<"Exponent is not valid for P-128"<<endl;
return;
}
// throw Exception(CryptoPP::Exception::OTHER_ERROR, "Exponent is not valid for P-256");

// Or: decryptor.AccessKey().ThrowIfInvalid(prng, 3);

cout << "Exponent is valid for P-128" << endl;

PrintPrivateKey(decryptor.GetKey());


//get public key
ECIES<ECP>::Encryptor encryptor(decryptor);
PrintPublicKey(encryptor.GetKey());



string em0; // encrypted message
StringSource ss1(message, true, new PK_EncryptorFilter(prng, encryptor, new StringSink(em0) ) );
cout<<"encrypted msg: "<<em0<<" and its length: "<<em0.length()<<endl;

string dm0; // decrypted message
StringSource ss2 (em0, true, new PK_DecryptorFilter(prng, decryptor, new StringSink(dm0) ) );
cout <<"decrypted msg: "<< dm0<<" and its length: "<<dm0.length() << endl;

}
catch(const CryptoPP::Exception& ex)
{
std::cerr << ex.what() << endl;
}

但是当我尝试使用公钥加密消息时出现错误

CryptoPP::CryptoMaterial::InvalidMaterial:CryptoMaterial:此对象包含无效值

这是我的代码:

std::string     public_point="AsIAEFjzIcX+Kvhe8AmLoGUc8aYAEAwf5ecREGZ2u4RLxQuav/A=";
StringSource ss(public_point, true, new CryptoPP::HexDecoder);

ECIES<ECP>::Encryptor encryptor;
encryptor.AccessKey().AccessGroupParameters().Initialize(ASN1::secp128r1());

ECP::Point point;
encryptor.GetKey().GetGroupParameters().GetCurve().DecodePoint(point, ss, ss.MaxRetrievable());
cout << "X: " << std::hex << point.x << endl;
cout << "Y: " << std::hex << point.y << endl;

encryptor.AccessKey().SetPublicElement(point);


encryptor.AccessKey().ThrowIfInvalid(prng, 3);

PrintPublicKey(encryptor.GetKey());



string em0; // encrypted message
StringSource ss1(message, true, new PK_EncryptorFilter(prng, encryptor, new StringSink(em0) ) );
cout<<"encrypted msg: "<<em0<<" and its length: "<<em0.length()<<endl;

最佳答案

我遇到的问题是您似乎不知道自己拥有什么,并且您使用的某些参数在与其他参数一起使用时是错误的。所以它几乎是在黑暗中刺伤。


首先,您应该将磁盘操作包装在 try/catch 中。 I/O 总是会导致问题,所以一定要捕获与 iostream 相关的异常。您还应该捕获与 key 加载相关的 Crypto++ 异常。这将处理没有信息的“崩溃”。

因此您的代码可能类似于:

try
{
// Read key from disk, load it into Crypto++ object
}
catch(const Exception& ex)
{
cerr << "Caught Crypto++ exception " << ex.what() << endl;
}
catch(const std::runtime_error& ex)
{
cerr << "Caught C++ runtime error " << ex.what() << endl;
}

其次,这看起来像一个私有(private)指数,而不是一个私钥:

std::string  privatekeyString="02C200102C180F9E6A4E7A2F58B5BE86BC179478";

它太大了,不能放在 P-128 中。也许你应该这样做:

try
{
AutoSeededRandomPool prng;

std::string exponent="02C200102C180F9E6A4E7A2F58B5BE86BC179478";
StringSource ss(exponent, true /*pumpAll*/, new HexDecoder);

Integer x;
x.Decode(ss, ss.MaxRetrievable(), Integer::UNSIGNED);
// cout << "Exponent: " << std::hex << x << endl;

ECIES<ECP>::Decryptor decryptor;
decryptor.AccessKey().Initialize(ASN1::secp256r1(), x);

bool valid = decryptor.AccessKey().Validate(prng, 3);
if(!valid)
throw Exception(Exception::OTHER_ERROR, "Exponent is not valid for P-256");

// Or: decryptor.AccessKey().ThrowIfInvalid(prng, 3);

cout << "Exponent is valid for P-256" << endl;
}
catch(const Exception& ex)
{
cerr << ex.what() << endl;
}

或者,您可以:

ECIES<ECP>::Decryptor decryptor;
decryptor.AccessKey().AccessGroupParameters().Initialize(ASN1::secp256r1());
decryptor.AccessKey().SetPrivateExponent(x);

如果将以下内容添加到上面的程序中:

// Encode key, use OID versus domain paramters
string encoded;
HexEncoder encoder(new StringSink(encoded));

decryptor.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
decryptor.GetKey().Save(encoder);

cout << "Private key: " << encoded << endl;

您将获得以下私钥:

$ ./ecies-test.exe
Exponent: 2c200102c180f9e6a4e7a2f58b5be86bc179478h
Private key: 3041020100301306072A8648CE3D020106082A8648CE3D030107042730250201010
42000000000000000000000000002C200102C180F9E6A4E7A2F58B5BE86BC179478

如您所见, key 不是 "02C200102C180F9E6A4E7A2F58B5BE86BC179478"

12 个前导 0 在我看来很可疑。虽然指数有效,但您应该验证指数和字段。我能找到的最接近的拟合是曲线 secp160r2(当然,secp192k1secp224k1 等曲线也适用)。

上面的私钥是ecies.priv.der的十六进制编码,如下所示。


第三,由于前导 02,这可能是压缩形式的公共(public)点。

std::string  privatekeyString="02C200102C180F9E6A4E7A2F58B5BE86BC179478";

如果是这样的话,那么你应该能够做到这一点,但我无法让它解码这一点(参见 wiki 上的 Minimizing Key Size for Persistence)。 xy运算后为0;也许问题出在这个领域:

std::string public_point="02C200102C180F9E6A4E7A2F58B5BE86BC179478";
StringSource ss(public_point, true, new HexDecoder);

ECIES<ECP>::Encryptor encryptor;
encryptor.AccessKey().AccessGroupParameters().Initialize(ASN1::secp128r1());

ECP::Point point;
encryptor.GetKey().GetGroupParameters().GetCurve().DecodePoint(point, ss, ss.MaxRetrievable());
cout << "X: " << std::hex << point.x << endl;
cout << "Y: " << std::hex << point.y << endl;

encryptor.AccessKey().SetPublicElement(point);
encryptor.AccessKey().ThrowIfInvalid(prng, 3);

第四,您可能应该保存整个 key ,而不仅仅是指数。这是为您准备的程序,它向您展示了如何保存和加载 key 。它还向您展示了如何在一行中执行加密和解密。

/////////////////////////////////////////////////
// Part one - generate keys

ECIES<ECP>::Decryptor decryptor(prng, ASN1::secp256r1());
ECIES<ECP>::Encryptor encryptor(decryptor);

/////////////////////////////////////////////////
// Part two - save keys

FileSink fs1("ecies.priv.der", true /*binary*/);
decryptor.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
decryptor.GetKey().Save(fs1);

FileSink fs2("ecies.pub.der", true /*binary*/);
encryptor.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
encryptor.GetKey().Save(fs2);

/////////////////////////////////////////////////
// Part three - encrypt/decrypt

string message, encrypted, recovered;

if(argc >= 2 && argv[1] != NULL)
message = argv[1];
else
message = "Attack at dawn!";

StringSource ss1 (message, true /*pumpAll*/, new PK_EncryptorFilter(prng, encryptor, new StringSink(encrypted)));
StringSource ss2 (encrypted, true /*pumpAll*/, new FileSink("ecies.encrypted.bin", true /*binary*/));
StringSource ss3 (encrypted, true /*pumpAll*/, new PK_DecryptorFilter(prng, decryptor, new StringSink(recovered)));

cout << recovered << endl;

这是上面测试程序中私钥的样子。请注意,它已将字段编码到结构中,因此您不必猜测它(P-256P-128P-521).

$ dumpasn1 ecies.priv.der 
0 65: SEQUENCE {
2 1: INTEGER 0
5 19: SEQUENCE {
7 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
16 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
: }
26 39: OCTET STRING, encapsulates {
28 37: SEQUENCE {
30 1: INTEGER 1
33 32: OCTET STRING
: 00 00 00 00 00 00 00 00 00 00 00 00 02 C2 00 10
: 2C 18 0F 9E 6A 4E 7A 2F 58 B5 BE 86 BC 17 94 78
: }
: }
: }

和公钥:

$ dumpasn1 ecies.pub.der 
0 89: SEQUENCE {
2 19: SEQUENCE {
4 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
13 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
: }
23 66: BIT STRING
: 04 08 9B D2 1C 3A DC 08 8B 1F F1 D0 F4 97 A0 87
: FE 4F 78 EA E2 B8 30 B8 E7 06 37 68 27 4C 71 CD
: 63 C3 E2 90 66 64 2B 1C F6 79 00 36 AF 72 4C 61
: 69 FA E9 06 00 9A 15 32 0B 85 B5 88 B2 C5 88 46
: 5E
: }

Crypto++ 在 ECIES 上有一个 wiki 页面。参见 Elliptic Curve Integrated Encryption Scheme .他们还有 Bouncy CaSTLe 互操作变通办法。


您也可以使用 PEM 对 key 进行编码,但您需要一个补丁来执行此操作,因为它不是库的一部分。有关补丁,请参阅 PEM Pack在 Crypto++ wiki 上。

关于c++ - 在 ECIES 中使用之前生成的私钥,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30860777/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com