计算RSA并以十六进制保存到文件

时间:2017-06-09 09:33:37

标签: c++ encryption hex rsa crypto++

我正在尝试使用rsa加密缓冲区,然后将数据以十六进制格式保存到文件中。我正在使用Crypto ++ 5.6.5。

加载密钥(工作):

try
{
    // Read RSA public
    FileSource fs1("public.pem", true);
    PEM_Load(fs1, pubKey);

    // Read RSA encrypted private
    FileSource fs2("private.pem", true);
    PEM_Load(fs2, privKey, "1234", 4);
}
catch(const Exception& ex)
{
    cout << "ERROR: RSA:" << ex.what() << endl;
    SystemLog_Print("RSA: Couldn't load keys");
}

加密(好吗?):

std::string RSA_Encrypt(unsigned char *buf, uint8_t len)
{
    AutoSeededRandomPool rng;
    std::string plain;
    std::string cipher, recovered;

    for(int i = 0; i < len; ++i) {
        plain.push_back(buf[i]);
    }

    // Encryption
    RSAES_OAEP_SHA_Encryptor e(pubKey);

    StringSource ss1(plain, true, new PK_EncryptorFilter(rng, e, new StringSink(cipher)));

    // Test Decryption
    RSAES_OAEP_SHA_Decryptor d(privKey);

    StringSource ss2(cipher, true, new PK_DecryptorFilter(rng, d, new StringSink(recovered)));

    if(memcmp(plain.data(), recovered.data(), plain.size()) != 0) {
        cout << "RSA Mismatch" << endl;
    }

    return cipher;
}

现在我坚持将加密数据写入可读HEX中的文件,如:

  

AB123CDE456

使用像std :: hex这样的流运算符似乎不起作用。 你能给我任何建议怎么做吗?

不工作:

unsigned char *buf[] = "123456789";
file << std::hex << RSA_Encrypt(buf, 9);

仅打印一些不可读的二进制数据;

3 个答案:

答案 0 :(得分:1)

好的,对任何有兴趣的人...... 我在这里找到了一个通用的十六进制格式化程序:Integer to hex string in C++

我稍微修改了它:

template< typename T >
std::string int2hex(T i)
{
  std::stringstream stream;
  stream << std::setfill ('0') << std::setw(sizeof(T)*2)
         << std::hex << (int32_t)i;
  return stream.str();
}

现在我打电话给我这样的惯例:

buf = RSA_Encrypt(data, 32);

// Write hash to sig file
for(unsigned int i = 0 ; i < buf.size() ; ++i) {
    uint8_t val = buf[i];
    file << int2hex(val);
}

现在我的文件中有HEX字符。

答案 1 :(得分:0)

十六进制输出函数可能如下所示:

void writeHex(std::ostream &out, const char *data, size_t len)
{
  char digits[] = "0123456789ABCDEF";
  for (size_t i = 0; i < len; ++i) {
    unsigned byte = (unsigned)data[i];
    out << digits[byte >> 4] << digits[byte & 0xf];
  }
}

用一个小样本来测试它:

#include <iostream>

void writeHex(std::ostream &out, const char *data, size_t len)
{
  char digits[] = "0123456789ABCDEF";
  for (size_t i = 0; i < len; ++i) {
    unsigned byte = (unsigned)data[i];
    out << digits[byte >> 4] << digits[byte & 0xf];
  }
}

int main()
{
  // sample data
  char data[] =
    "This is some test data:\n"
    "\x00\x01\x02\x03\0x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
    "\x10\x11\x12\x13\0x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
    "\x20\x21\x22\x23\0x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
    "\x30\x31\x32\x33\0x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f";
  // test writeHex()
  writeHex(std::cout, data, sizeof data);
  std::cout << std::endl;
  // done
  return 0;
}

在Windows 10(64位)上使用VS2013进行编译和测试:

5468697320697320736F6D65207465737420646174613A0A000102030078303405060708090A0B0C0D0E0F101112130078313415161718191A1B1C1D1E1F202122230078323425262728292A2B2C2D2E2F303132330078333435363738393A3B3C3D3E3F00

可以使用ASCII表检查我的测试data[]开头的人类可读文本。我只是搜索&#34; 000102&#34;并看到&#34; 0A&#34; (之前为\n)。 &#34; 00&#34;在输出的末尾是字符串0-terminator(也被sizeof认为)。

答案 2 :(得分:0)

  

现在我坚持将加密数据写入可读的文件中   HEX喜欢:

AB123CDE456

添加HexEncoder并在管道中使用FileSink

StringSource ss(plain, true, new PK_EncryptorFilter(rng, enc, new HexEncoder(new FileSink("file.enc"))));  

通过上述更改,数据在通过管道时会进行十六进制编码。

稍后,当您准备好阅读数据时,可以使用FileSource并在管道中添加HexDecoder。广告解码器在解密器之前添加,而不是在加密之后添加。

FileSource fs("file.enc", true, new HexDecoder, new PK_DecryptorFilter(rng, dec, new StringSink(recovered))));  

你应该避免这种情况,因为是一个恒定的时间比较:

if(memcmp(plain.data(), recovered.data(), plain.size()) != 0) {
    cout << "RSA Mismatch" << endl;
}

改为使用VerifyBufsEqual

bool equal = VerifyBufsEqual(plain.data(), recovered.data(), plain.size());

VerifyBufsEqual需要相同大小的缓冲区,所以可能是这样的:

bool equal = (plain.size() == recovered.size());
size_t size = STDMIN(plain.size(), recovered.size());
equal = VerifyBufsEqual(plain.data(), recovered.data(), size) && equal;

这可能会有所帮助......

而不是使用中间std::string

std::string RSA_Encrypt(unsigned char *buf, uint8_t len)
{
    ...    
    for(int i = 0; i < len; ++i) {
        plain.push_back(buf[i]);
    }  
    ...    
    StringSource ss(plain, true, new PK_EncryptorFilter(rng, enc, new StringSink(cipher)));    
    ...
}

您可以改为使用buflen

std::string RSA_Encrypt(unsigned char *buf, uint8_t len)
{ 
    ...    
    ArraySource as(buf, len, true, new PK_EncryptorFilter(rng, enc, new StringSink(cipher)));    
    ...
}

使用构造函数重载,ArraySource实际上是StringSource的typedef。