我想使用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;
为了回应@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;
}
但是当我尝试使用公钥加密消息时,我收到了错误
这是我的代码:
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;
答案 0 :(得分:2)
我遇到的问题是你似乎不知道自己拥有什么,而且当你使用其他参数时,你使用的一些参数是错误的。所以它几乎是在黑暗中刺伤。
首先,您应该将磁盘操作包装在try/catch
中。 I / O总是会导致问题,因此请务必捕获与iostream
内容相关的异常。您还应该捕获与密钥加载相关的Crypto ++异常。这将处理&#34;崩溃&#34;没有信息。
所以你的代码看起来像是:
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;
}
其次,这看起来像私有指数,而不是私钥:
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
如您所见, 键不是 "02C200102C180F9E6A4E7A2F58B5BE86BC179478"
。
12位领先的0看起来很可疑。虽然指数有效,但您应该验证指数和字段。我能找到的最接近的是曲线secp160r2
(当然,像secp192k1
和secp224k1
这样的曲线也可以。)
上面的私钥是ecies.priv.der
的十六进制编码,如下所示。
第三,由于领先02
,这可能是压缩形式的公共点。
std::string privatekeyString="02C200102C180F9E6A4E7A2F58B5BE86BC179478";
如果是这种情况,那么你应该可以做到这一点,但是我无法解决这个问题(请参阅维基上的Minimizing Key Size for Persistence)。手术后x
和y
为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);
第四,你应该保存整个密钥,而不仅仅是指数。这是一个程序,向您展示如何保存和加载密钥。它还向您展示了如何在单行中执行加密和解密。
/////////////////////////////////////////////////
// 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-256
与P-128
对比P-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编码,但是您需要一个补丁来执行此操作,因为它不是库的一部分。有关修补程序,请参阅Crypto ++ wiki上的PEM Pack。
答案 1 :(得分:1)
我要添加另一个答案,告诉您如何在公共点出现问题时序列化私人指数和公共点。它还向您展示了如何Save
PrivateKeyInfo 和 SubjectPublicKeyInfo 。
它产生类似于下面的输出。您需要Base64URLEncoder
的补丁。它不是图书馆的一部分。
$ ./ecies-test.exe
Private exponent
Hex: 57E91FA3EF48706D07E56D8CB566204A4416B833EFB9687D75A37D572EC42277
Base64: V+kfo+9IcG0H5W2MtWYgSkQWuDPvuWh9daN9Vy7EInc=
Base64 (URL safe): V-kfo-9IcG0H5W2MtWYgSkQWuDPvuWh9daN9Vy7EInc=
Pubic point
Hex: 037142DE6143B6AD44C74135FE71222AC1406F541E53CB635112DE4928EC94763C
Base64: A3FC3mFDtq1Ex0E1/nEiKsFAb1QeU8tjURLeSSjslHY8
Base64 (URL safe): A3FC3mFDtq1Ex0E1_nEiKsFAb1QeU8tjURLeSSjslHY8
Private key (PrivateKeyInfo)
3059301306072A8648CE3D020106082A8648CE3D030107034200047142DE6143B6AD44C74135FE71
222AC1406F541E53CB635112DE4928EC94763CFA903D9282691AE47A2D718297465EF44E905A89ED
2D4553ED1DF906A6E2383B
Public key (SubjectPublicKeyInfo)
3041020100301306072A8648CE3D020106082A8648CE3D03010704273025020101042057E91FA3EF
48706D07E56D8CB566204A4416B833EFB9687D75A37D572EC42277
使用上面的私有指数和公共点,以下工作正常:
string pub_point("A7EDDUXAA4/6kOZ8H+firJ95YtKZvDrPFmyVoisyBfuW");
StringSource ss(pub_point, true, new Base64Decoder);
ECIES<ECP>::Encryptor encryptor;
encryptor.AccessKey().AccessGroupParameters().Initialize(ASN1::secp256r1());
ECP::Point point;
encryptor.GetKey().GetGroupParameters().GetCurve().DecodePoint(point, ss, ss.MaxRetrievable());
encryptor.AccessKey().SetPublicElement(point);
encryptor.AccessKey().ThrowIfInvalid(prng, 3);
ECIES<ECP>::Decryptor decryptor;
decryptor.AccessKey().Initialize(prng, ASN1::secp256r1());
const Integer& priv_exp = decryptor.GetKey().GetPrivateExponent();
SecByteBlock x(priv_exp.MinEncodedSize());
priv_exp.Encode(x, x.size());
string s1, s2, s3;
HexEncoder f1(new StringSink(s1));
Base64Encoder f2(new StringSink(s2));
Base64URLEncoder f3(new StringSink(s3));
ChannelSwitch cs1;
cs1.AddDefaultRoute(f1);
cs1.AddDefaultRoute(f2);
cs1.AddDefaultRoute(f3);
ArraySource as1(x, x.size(), true /*pumpAll*/, new Redirector(cs1));
cout << "Private exponent" << endl;
cout << " Hex: " << s1 << endl;
cout << " Base64: " << s2 << endl;
cout << " Base64 (URL safe): " << s3 << endl;
//////////////////////////////////////////
ECIES<ECP>::Encryptor encryptor(decryptor);
ECP::Point pub_point = encryptor.GetKey().GetGroupParameters().ExponentiateBase(priv_exp);
SecByteBlock y(encryptor.GetKey().GetGroupParameters().GetCurve().EncodedPointSize(true /*compressed*/));
encryptor.GetKey().GetGroupParameters().GetCurve().EncodePoint(y, pub_point, true /*compressed*/);
string s4, s5, s6;
HexEncoder f4(new StringSink(s4));
Base64Encoder f5(new StringSink(s5));
Base64URLEncoder f6(new StringSink(s6));
ChannelSwitch cs2;
cs2.AddDefaultRoute(f4);
cs2.AddDefaultRoute(f5);
cs2.AddDefaultRoute(f6);
ArraySource as2(y, y.size(), true /*pumpAll*/, new Redirector(cs2));
cout << "Pubic point" << endl;
cout << " Hex: " << s4 << endl;
cout << " Base64: " << s5 << endl;
cout << " Base64 (URL safe): " << s6 << endl;
//////////////////////////////////////////
string s10, s11;
HexEncoder hex1(new StringSink(s10));
HexEncoder hex2(new StringSink(s11));
encryptor.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
encryptor.GetKey().Save(hex1);
decryptor.AccessKey().AccessGroupParameters().SetEncodeAsOID(true);
decryptor.GetKey().Save(hex2);
cout << "Private key" << endl;
cout << s10 << endl;
cout << "Public key" << endl;
cout << s11 << endl;
答案 2 :(得分:0)
正如jww建议我已成功完成加密和解密。 如果有人想要,下面是代码片段。
string decrypt(std::string encryptedMessage , std::string privateKeyExponent)
{
string decryptedMessage;
try
{
AutoSeededRandomPool prng;
//since the 'privateKeyExponent' is in base-64 format use Base64Decoder
StringSource ss(privateKeyExponent, true /*pumpAll*/, new CryptoPP::Base64Decoder);
Integer x;
x.Decode(ss, ss.MaxRetrievable(), Integer::UNSIGNED);
ECIES<ECP>::Decryptor decryptor;
//curve used is secp256k1
//make decryptor's access key using decoded private exponent's value
decryptor.AccessKey().Initialize(ASN1::secp256k1(), x);
//check whether decryptor's access key is valid or not
bool valid = decryptor.AccessKey().Validate(prng, 3);
if(!valid)
decryptor.AccessKey().ThrowIfInvalid(prng, 3);
cout << "Exponent is valid for P-256k1" << endl;
//decrypt the message using private key
StringSource ss2 (encryptedMessage, true, new PK_DecryptorFilter(prng, decryptor, new StringSink(decryptedMessage) ) );
cout <<"decrypted msg: "<< decryptedMessage<<" and its length: "<<decryptedMessage.length() << endl;
}
catch(const CryptoPP::Exception& ex)
{
std::cerr << ex.what() << endl;
}
return decryptedMessage;
}
string encrypt(std::string message , std::string compressedPublicKeyPoint)
{
string encryptedMessage;
try
{
AutoSeededRandomPool prng;
//public key is a point consisting of "public key point x" and "public key point y"
//compressed public key also known as "public-point" formed using point-compression of public key
//since the key is in base-64 format use Base64Decoder
StringSource ss(compressedPublicKeyPoint, true, new CryptoPP::Base64Decoder);
ECIES<ECP>::Encryptor encryptor;
//curve used is secp256k1
encryptor.AccessKey().AccessGroupParameters()
.Initialize(ASN1::secp256k1());
//get point on the used curve
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;
//set encryptor's public element
encryptor.AccessKey().SetPublicElement(point);
//check whether the encryptor's access key thus formed is valid or not
encryptor.AccessKey().ThrowIfInvalid(prng, 3);
// encrypted message
StringSource ss1(message, true, new PK_EncryptorFilter(prng, encryptor, new StringSink(encryptedMessage) ) );
cout<<"encrypted msg: "<<encryptedMessage<<" and its length: "<<encryptedMessage.length()<<endl;
}
catch(const CryptoPP::Exception& ex)
{
std::cerr << ex.what() << endl;
}
return encryptedMessage;
}