Я хочу зашифровать / расшифровать данные с помощью 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;
Проблема, с которой я сталкиваюсь, заключается в том, что вы, похоже, не знаете, что у вас есть, а некоторые параметры, которые вы используете, неверны при использовании других параметров. Так что это в значительной степени удар в темноте.
Во-первых, вы должны обернуть дисковые операции в try/catch
, Ввод / вывод всегда может вызвать проблемы, поэтому обязательно перехватывайте исключения, связанные с iostream
вещи. Вы должны также поймать исключение 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;
}
Во-вторых, это похоже на частный показатель, а не на закрытый ключ:
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";
Если это так, то вы должны быть в состоянии сделать это, но я не могу заставить его расшифровать точку (см. Минимизация размера ключа для постоянства в вики). 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. Увидеть Схема интегрированного шифрования эллиптической кривой. У них также есть обходные пути взаимодействия Bouncy Castle.
Вы также можете кодировать ключи PEM, но для этого нужен патч, потому что он не является частью библиотеки. Для патча, см. PEM Pack на Crypto ++ вики.
Я собираюсь добавить еще один ответ, чтобы показать вам, как сериализовать частные экспоненты и публичные точки в случае, если у вас возникли проблемы с общими точками. Это также показывает вам, как 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;
Как 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;
}