Reputation: 814
I'm write Client/Server encrypted program and want to send ECIES public key. For this I must serialize public key to file, read file to byte array, send this byte array. In other side: receive byte array, write it to file, deserialize public key from file. So, I'm written some test project, for try do it separately from great system, and (when all this module will work successfully) just insert it in my project. Code of this project are:
class EncoderRSA
{
public:
EncoderRSA();
void keyGeneration();
std::string encrypt(std::string plainText);
std::string decrypt(std::string cypher);
void setRsaPublicKey(char *publicKeyInCharArray);
char *getRsaPublicKey();
private:
AutoSeededRandomPool prng; // Pseudo Random Number Generator
ECIES<ECP>::Decryptor rsaDecryptor;
ECIES<ECP>::Encryptor rsaEncryptor;
};
And, strictly speaking, prime (for problem) methods:
char *EncoderRSA::getRsaPublicKey() {
std::string file = "publicKey.txt";
//Save public key in file
FileSink sink(file.c_str());
this->rsaEncryptor.GetPublicKey().Save(sink);
//Read file with public key into the buffer
std::ifstream infile (file.c_str(),std::ifstream::binary);
if (!infile.is_open()) {
std::cout << "Can't open file to write" << std::endl;
exit(1);
}
// get size of file
infile.seekg (0,infile.end);
long size = infile.tellg();
infile.seekg (0);
// allocate memory for file content
char* buffer = new char[size];
infile.read (buffer,size);
infile.close();
return buffer;
}
void EncoderRSA::setRsaPublicKey(char *publicKeyInCharArray) {
std::string file = "publicKey.txt";
int size = strlen(publicKeyInCharArray);
//Write received public key in file
std::ofstream outfile (file.c_str(),std::ofstream::binary);
if (!outfile.is_open()) {
std::cout << "Can't open file to write" << std::endl;
exit(1);
}
outfile.write (publicKeyInCharArray,size);
outfile.close();
// release dynamically-allocated memory
delete[] publicKeyInCharArray;
//Load public key from file
FileSource source(file.c_str(), true);
this->rsaEncryptor.AccessPublicKey().Load(source);
}
Code of main.cpp
:
int main() {
char *buffer = keysEncoder.getRsaPublicKey();
cout << "buffer: " << buffer << endl;
//...
//send buffer
//receive buffer from other side
//..
keysEncoder.setRsaPublicKey(buffer);
string decoded = keysEncoder.decrypt(cypher);
cout << "decoded: " << decoded << endl;
return 0;
}
But it crashed with error:
terminate called after throwing an instance of 'CryptoPP::BERDecoderErr'
wait(): BER decode error
Aborted (core dumped)
Process returned 134 (0x86) execution time: 2.891
Why?
Upvotes: 4
Views: 576
Reputation: 102205
I removed references to RSA since it looks like you are using ECIES. Good job on that.
terminate called after throwing an instance of 'CryptoPP::BERDecoderErr'
Obviously, you need to setup a try/catch:
try
{
...
}
catch(const BERDecoderErr& ex)
{
cerr << ex.what() << endl;
}
char *Encoder::getPublicKey() { ... char* buffer = ... return buffer; }
The ASN.1/DER encoding will likely have an embedded NULL, so you can't operate on it using traditional C-strings.
This should probably return a std::string
so the output is not truncated at the first NULL character:
// get size of file
infile.seekg (0,infile.end);
long size = infile.tellg();
infile.seekg (0);
// allocate memory for file content
string buffer(size, '0');
infile.read (&buffer[0], size);
infile.close();
return buffer;
Another way to perform the read from the file can be found at Read whole ASCII file into C++ std::string:
std::ifstream infile (file.c_str(), std::ifstream::binary);
std::string buffer((std::istreambuf_iterator<char>(infile)),
std::istreambuf_iterator<char>());
Another way is to ensure the NULL
's are not present in the output and input:
string Encoder::getPublicKey() {
string encodedKey;
HexEncoder sink(new StringSink(encodedKey));
Encryptor.GetPublicKey().Save(sink);
return encodedKey;
}
And:
void Encoder::setPublicKey(const string& encodedKey) {
StringSource source(encodedKey, new HexDecoder());
Encryptor.AccessPublicKey().Load(source);
}
The code above uses StringSource
and StringSink
, so it operates on stuff in-memory. If you really want the on-disk intermediate files, then use a FileSource
and FileSink
.
Upvotes: 1