需要更高性能的 hex2bytes bytes2hex 编码/解码

问题描述 投票:0回答:1

我编写了一个基于openssl(libcrypto.so)使用AES256 CBC的加密库。我的库是用 C++ 编写的(实际上是 C++11) 使用 valgrind 进行分析表明,加密/解密非常快,但我将结果字节编码/解码为十六进制字符串的速度很慢。

加密时,encode_bytes2hex需要总程序运行时间的50%。解密 decode_hex2bytes 甚至需要总运行时间的 75%。 我希望至少让 decode_hex2bytesencode_bytes2hex 一样快。但将运行时间减少 10 倍左右也不错。我希望这些“小”函数仅使用总运行时间中无关紧要的部分。

这是我的实现:

std::string encode_bytes2hex(const std::vector<unsigned char>& rData){
  //encode as hex 
  std::stringstream ss;
  ss << std::hex << std::setfill('0');
  for (auto& c : rData)
  {
      ss << std::setw(2) << static_cast<int>(c);
  }
  return ss.str();
}

std::vector<unsigned char> decode_hex2bytes(const std::string& rHex){
  std::vector<unsigned char> oBytes(rHex.length()/2);
  std::stringstream ssConv;
  for(size_t n = 0; n < rHex.length(); n+=2)
  {
      ssConv << std::hex << rHex.substr(n,2);
      int byte;
      ssConv >> byte;
      oBytes[n/2] = byte & 0xFF;
      ssConv.str(std::string());
      ssConv.clear();
  }
  return oBytes;
}

我想删除 std::stringstream 可以大大加快一切速度。但如何呢?

c++ openssl hex aes
1个回答
0
投票

当您通过

std::stringstream
时,您会产生大量不必要的开销,并且当您往返于
std::string
时,会产生额外的副本。

直接使用字符串,并在自己的循环中读/写每个半字节:

#include <sstream>
#include <iomanip>

std::string encode_bytes2hex(const std::vector<unsigned char>& rData)
{
    std::string result;
    result.reserve(rData.size() * 2);

    static auto const to_hex = [](unsigned char c) {
        return "0123456789abcdef"[c];
    };
    for (auto c: rData) {
        result.push_back(to_hex(c / 16));
        result.push_back(to_hex(c % 16));
    }
    return result;
}

std::vector<unsigned char> decode_hex2bytes(const std::string& rHex)
{
    if (rHex.size() % 2) {
        throw std::invalid_argument("hex string of odd length");
    }
    std::vector<unsigned char> result;
    result.reserve(rHex.size()/2);

    static auto const from_hex = [](char c) {
        switch (c) {
        case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3;
        case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7;
        case '8': return 8; case '9': return 9; case 'a': return 10; case 'b': return 11;
        case 'c': return 12; case 'd': return 13; case 'e': return 14; case 'f': return 15;
        case 'A': return 10; case 'B': return 11; case 'C': return 12;
        case 'D': return 13; case 'E': return 14; case 'F': return 15;
        }
        throw std::invalid_argument("not a hex digit");
    };

    for (std::size_t i = 0;  i < rHex.size();  i += 2) {
        result.push_back(static_cast<unsigned char>(from_hex(rHex[i]) * 16u + from_hex(rHex[i+1])));
    }
    return result;
}

这通过了相同的测试:

int main()
{
    const auto v = std::vector<unsigned char>{ 0xFF, 0x0a, 0x00, 0x12 };
    const auto s = std::string{"ff0a0012"};

    return encode_bytes2hex(v) != s
        || decode_hex2bytes(s) != v;
}
© www.soinside.com 2019 - 2024. All rights reserved.