REDACTED-rig/src/base/tools/Cvt.cpp
2021-01-15 19:18:52 +07:00

291 lines
6.6 KiB
C++

/* XMRig
* Copyright (c) 2013-2020 Frank Denis <j at pureftpd dot org>
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "base/tools/Cvt.h"
#include "3rdparty/rapidjson/document.h"
#include <cassert>
#include <random>
#ifdef XMRIG_SODIUM
# include <sodium.h>
#endif
namespace xmrig {
static char *cvt_bin2hex(char *const hex, const size_t hex_maxlen, const unsigned char *const bin, const size_t bin_len)
{
size_t i = 0U;
unsigned int x;
int b;
int c;
if (bin_len >= SIZE_MAX / 2 || hex_maxlen < bin_len * 2U) {
return nullptr; /* LCOV_EXCL_LINE */
}
while (i < bin_len) {
c = bin[i] & 0xf;
b = bin[i] >> 4;
x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8 |
(unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U));
hex[i * 2U] = (char) x;
x >>= 8;
hex[i * 2U + 1U] = (char) x;
i++;
}
if (i * 2U < hex_maxlen) {
hex[i * 2U] = 0U;
}
return hex;
}
#ifndef XMRIG_SODIUM
static std::random_device randomDevice;
static std::mt19937 randomEngine(randomDevice());
static int cvt_hex2bin(unsigned char *const bin, const size_t bin_maxlen, const char *const hex, const size_t hex_len, const char *const ignore, size_t *const bin_len, const char **const hex_end)
{
size_t bin_pos = 0U;
size_t hex_pos = 0U;
int ret = 0;
unsigned char c;
unsigned char c_acc = 0U;
unsigned char c_alpha0;
unsigned char c_alpha;
unsigned char c_num0;
unsigned char c_num;
unsigned char c_val;
unsigned char state = 0U;
while (hex_pos < hex_len) {
c = (unsigned char) hex[hex_pos];
c_num = c ^ 48U;
c_num0 = (c_num - 10U) >> 8;
c_alpha = (c & ~32U) - 55U;
c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8;
if ((c_num0 | c_alpha0) == 0U) {
if (ignore != nullptr && state == 0U && strchr(ignore, c) != nullptr) {
hex_pos++;
continue;
}
break;
}
c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha);
if (bin_pos >= bin_maxlen) {
ret = -1;
errno = ERANGE;
break;
}
if (state == 0U) {
c_acc = c_val * 16U;
} else {
bin[bin_pos++] = c_acc | c_val;
}
state = ~state;
hex_pos++;
}
if (state != 0U) {
hex_pos--;
errno = EINVAL;
ret = -1;
}
if (ret != 0) {
bin_pos = 0U;
}
if (hex_end != nullptr) {
*hex_end = &hex[hex_pos];
} else if (hex_pos != hex_len) {
errno = EINVAL;
ret = -1;
}
if (bin_len != nullptr) {
*bin_len = bin_pos;
}
return ret;
}
#define sodium_hex2bin cvt_hex2bin
#endif
template<typename T>
inline bool fromHexImpl(T &buf, const char *in, size_t size)
{
assert(in != nullptr && size > 0);
if (in == nullptr || size == 0) {
return false;
}
buf.resize(size / 2);
return sodium_hex2bin(reinterpret_cast<uint8_t *>(&buf.front()), buf.size(), in, size, nullptr, nullptr, nullptr) == 0;
}
} // namespace xmrig
bool xmrig::Cvt::fromHex(Buffer &buf, const char *in, size_t size)
{
return fromHexImpl(buf, in, size);
}
bool xmrig::Cvt::fromHex(Buffer &buf, const rapidjson::Value &value)
{
if (!value.IsString()) {
return false;
}
return fromHexImpl(buf, value.GetString(), value.GetStringLength());
}
bool xmrig::Cvt::fromHex(std::string &buf, const char *in, size_t size)
{
return fromHexImpl(buf, in, size);
}
bool xmrig::Cvt::fromHex(uint8_t *bin, size_t bin_maxlen, const char *hex, size_t hex_len)
{
assert(hex != nullptr && hex_len > 0);
if (hex == nullptr || hex_len == 0) {
return false;
}
return sodium_hex2bin(bin, bin_maxlen, hex, hex_len, nullptr, nullptr, nullptr) == 0;
}
bool xmrig::Cvt::fromHex(uint8_t *bin, size_t max, const rapidjson::Value &value)
{
if (!value.IsString()) {
return false;
}
return fromHex(bin, max, value.GetString(), value.GetStringLength());
}
xmrig::Buffer xmrig::Cvt::fromHex(const char *in, size_t size)
{
Buffer buf;
if (!fromHex(buf, in, size)) {
return {};
}
return buf;
}
bool xmrig::Cvt::toHex(char *hex, size_t hex_maxlen, const uint8_t *bin, size_t bin_len)
{
return cvt_bin2hex(hex, hex_maxlen, bin, bin_len) != nullptr;
}
xmrig::Buffer xmrig::Cvt::randomBytes(const size_t size)
{
Buffer buf(size);
# ifndef XMRIG_SODIUM
std::uniform_int_distribution<> dis(0, 255);
for (size_t i = 0; i < size; ++i) {
buf[i] = static_cast<char>(dis(randomEngine));
}
# else
randombytes_buf(buf.data(), size);
# endif
return buf;
}
rapidjson::Value xmrig::Cvt::toHex(const Buffer &data, rapidjson::Document &doc)
{
return toHex(data.data(), data.size(), doc);
}
rapidjson::Value xmrig::Cvt::toHex(const std::string &data, rapidjson::Document &doc)
{
return toHex(reinterpret_cast<const uint8_t *>(data.data()), data.size(), doc);
}
rapidjson::Value xmrig::Cvt::toHex(const uint8_t *in, size_t size, rapidjson::Document &doc)
{
return toHex(in, size).toJSON(doc);
}
xmrig::String xmrig::Cvt::toHex(const uint8_t *in, size_t size)
{
assert(in != nullptr && size > 0);
if (in == nullptr || size == 0) {
return {};
}
const size_t hex_maxlen = size * 2 + 1;
char *buf = new char[hex_maxlen];
if (!toHex(buf, hex_maxlen, in, size)) {
delete [] buf;
return {};
}
return buf;
}
void xmrig::Cvt::randomBytes(void *buf, size_t size)
{
# ifndef XMRIG_SODIUM
std::uniform_int_distribution<> dis(0, 255);
for (size_t i = 0; i < size; ++i) {
static_cast<uint8_t *>(buf)[i] = static_cast<char>(dis(randomEngine));
}
# else
randombytes_buf(buf, size);
# endif
}