Использовать ранее сгенерированный закрытый ключ в ECIES

Я хочу зашифровать / расшифровать данные с помощью 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;

4

Решение

Проблема, с которой я сталкиваюсь, заключается в том, что вы, похоже, не знаете, что у вас есть, а некоторые параметры, которые вы используете, неверны при использовании других параметров. Так что это в значительной степени удар в темноте.


Во-первых, вы должны обернуть дисковые операции в 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 ++ вики.

2

Другие решения

Я собираюсь добавить еще один ответ, чтобы показать вам, как сериализовать частные экспоненты и публичные точки в случае, если у вас возникли проблемы с общими точками. Это также показывает вам, как 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;
1

Как 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;
}
0
По вопросам рекламы [email protected]