2015-09-19 32 views
4

我正在编写客户端/服务器加密程序并希望发送ECIES公钥。为此,我必须将公钥序列化为文件,将文件读取到字节数组,然后发送该字节数组。另一方面:接收字节数组,将其写入文件,从文件反序列化公钥。所以,我写了一些测试项目,尝试从伟大的系统中分离出来,并且(当所有这个模块都能成功运行时)将它插入到我的项目中。这个项目的代号是:ECIES公钥序列化

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; 
}; 

而且,严格地说,黄金(对问题)的方法:

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); 
} 

代码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; 
} 

但它与错误崩溃:

terminate called after throwing an instance of 'CryptoPP::BERDecoderErr' 
wait(): BER decode error 
Aborted (core dumped) 

Process returned 134 (0x86) execution time: 2.891 

为什么?

+1

您不检查是否有任何文件操作成功。如果'open'或'seekg'返回一个错误代码会怎么样? –

+0

@波佩尔松,谢谢:)但是,我故意这样做 - 它不是最终版本,我只是想告诉你一个问题。问题不在其中。 –

+2

你为什么使用临时文件?如果你想编码和解码到/从内存中使用CryptoPP的'StringSink'和'StringSource'。但是,如果您使用的是文件,您是否检查过该文件的内容?你可以尝试一下这个方便的ASN.1解码工具https://lapo.it/asn1js – buc

回答

1

我删除了对RSA的引用,因为它看起来像是在使用ECIES。好的工作。


terminate called after throwing an instance of 'CryptoPP::BERDecoderErr'

显然,你需要设置一个try/catch:

try 
{ 
    ... 
} 
catch(const BERDecoderErr& ex) 
{ 
    cerr << ex.what() << endl; 
} 

char *Encoder::getPublicKey() { 
    ... 
    char* buffer = ... 
    return buffer; 
} 

的ASN.1/DER编码将可能有一个嵌入的空,所以你无法使用传统C字符串对其进行操作。

这也许应该返回std::string所以输出没有在第一个NULL字符截断:

// 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; 

执行从文件读取可在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>()); 

另一种方法是确保NULL的不存在于输出和输入:

string Encoder::getPublicKey() { 
    string encodedKey; 
    HexEncoder sink(new StringSink(encodedKey)); 
    Encryptor.GetPublicKey().Save(sink); 
    return encodedKey; 
} 

和:

void Encoder::setPublicKey(const string& encodedKey) { 
    StringSource source(encodedKey, new HexDecoder()); 
    Encryptor.AccessPublicKey().Load(source); 
} 

上面的代码使用和StringSourceStringSink,所以它的内存中的东西进行操作。如果你想要想要在磁盘上的中间文件,然后用FileSourceFileSink

+0

非常感谢!)我现在试着去做:) –

+0

@ V.Panchenko - 如果你在Linux上,那么'sed'是你的朋友。 'sed -i“s | rsaDecryptor | eciesDecryptor | g”* .h * .cpp'可用于替换文本。如果在OS X上,那么你将使用相同的命令,但是使用'sed -i“”...'(你需要空的引用字符串)。 – jww

+0

是的,我在Linux上,但我想编写跨平台的代码,所以我也应该关注Windows) –