【问题标题】:Calculate RSA and save to file in HEX计算 RSA 并以 HEX 格式保存到文件
【发布时间】:2017-06-10 08:52:57
【问题描述】:

我正在尝试使用 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);

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

【问题讨论】:

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


【解决方案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 字符。

【讨论】:

【解决方案2】:

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

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[]。我只是搜索了“000102”,之前看到了“0A”(\n)。输出末尾的“00”用于字符串 0 终止符(sizeof 也考虑)。

【讨论】:

    【解决方案3】:

    现在我坚持将加密数据写入可读文件 十六进制如:

    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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-07
      • 1970-01-01
      • 1970-01-01
      • 2017-08-22
      • 1970-01-01
      相关资源
      最近更新 更多