Skip to content

Commit

Permalink
src, deps: move hex_encode/decode/forceAscii to nbytes
Browse files Browse the repository at this point in the history
  • Loading branch information
jasnell committed Jun 19, 2024
1 parent dff4a35 commit 05e5cde
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 145 deletions.
100 changes: 100 additions & 0 deletions deps/nbytes/nbytes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,106 @@ const int8_t unbase64_table[256] =
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};

// ============================================================================
// Hex

const int8_t unhex_table[256] =
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};

size_t HexEncode(
const char* src,
size_t slen,
char* dst,
size_t dlen) {
// We know how much we'll write, just make sure that there's space.
NBYTES_ASSERT_TRUE(
dlen >= MultiplyWithOverflowCheck<size_t>(slen, 2u) &&
"not enough space provided for hex encode");

dlen = slen * 2;
for (size_t i = 0, k = 0; k < dlen; i += 1, k += 2) {
static const char hex[] = "0123456789abcdef";
uint8_t val = static_cast<uint8_t>(src[i]);
dst[k + 0] = hex[val >> 4];
dst[k + 1] = hex[val & 15];
}

return dlen;
}

std::string HexEncode(const char* src, size_t slen) {
size_t dlen = slen * 2;
std::string dst(dlen, '\0');
HexEncode(src, slen, dst.data(), dlen);
return dst;
}

// ============================================================================

void ForceAsciiSlow(const char* src, char* dst, size_t len) {
for (size_t i = 0; i < len; ++i) {
dst[i] = src[i] & 0x7f;
}
}

void ForceAscii(const char* src, char* dst, size_t len) {
if (len < 16) {
ForceAsciiSlow(src, dst, len);
return;
}

const unsigned bytes_per_word = sizeof(uintptr_t);
const unsigned align_mask = bytes_per_word - 1;
const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask;
const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask;

if (src_unalign > 0) {
if (src_unalign == dst_unalign) {
const unsigned unalign = bytes_per_word - src_unalign;
ForceAsciiSlow(src, dst, unalign);
src += unalign;
dst += unalign;
len -= src_unalign;
} else {
ForceAsciiSlow(src, dst, len);
return;
}
}

#if defined(_WIN64) || defined(_LP64)
const uintptr_t mask = ~0x8080808080808080ll;
#else
const uintptr_t mask = ~0x80808080l;
#endif

const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
uintptr_t* dstw = reinterpret_cast<uintptr_t*>(dst);

for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
dstw[i] = srcw[i] & mask;
}

const unsigned remainder = len & align_mask;
if (remainder > 0) {
const size_t offset = len - remainder;
ForceAsciiSlow(src + offset, dst + offset, remainder);
}
}

} // namespace nbytes
81 changes: 78 additions & 3 deletions deps/nbytes/nbytes.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,44 @@
#pragma once

#include <stddef.h>
#include <stdint.h>
#include <cmath>
#include <string>
#include <cstddef>
#include <cstdint>
#include <cmath>

namespace nbytes {

#if NBYTES_DEVELOPMENT_CHECKS
#define NBYTES_STR(x) #x
#define NBYTES_REQUIRE(EXPR) \
{ \
if (!(EXPR) { abort(); }) }

#define NBYTES_FAIL(MESSAGE) \
do { \
std::cerr << "FAIL: " << (MESSAGE) << std::endl; \
abort(); \
} while (0);
#define NBYTES_ASSERT_EQUAL(LHS, RHS, MESSAGE) \
do { \
if (LHS != RHS) { \
std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \
NBYTES_FAIL(MESSAGE); \
} \
} while (0);
#define NBYTES_ASSERT_TRUE(COND) \
do { \
if (!(COND)) { \
std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \
<< std::endl; \
NBYTES_FAIL(NBYTES_STR(COND)); \
} \
} while (0);
#else
#define NBYTES_FAIL(MESSAGE)
#define NBYTES_ASSERT_EQUAL(LHS, RHS, MESSAGE)
#define NBYTES_ASSERT_TRUE(COND)
#endif

// The nbytes (short for "node bytes") is a set of utility helpers for
// working with bytes that are extracted from Node.js' internals. The
// motivation for extracting these into a separate library is to make it
Expand All @@ -26,6 +58,19 @@ constexpr T* AlignUp(T* ptr, U alignment) {
RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment));
}

template <typename T>
inline T MultiplyWithOverflowCheck(T a, T b) {
auto ret = a * b;
if (a != 0) {
NBYTES_ASSERT_TRUE(b == ret / a);
}

return ret;
}

void ForceAsciiSlow(const char* src, char* dst, size_t len);
void ForceAscii(const char* src, char* dst, size_t len);

// ============================================================================
// Byte Swapping

Expand Down Expand Up @@ -160,4 +205,34 @@ size_t Base64Decode(char* const dst, const size_t dstlen,
#pragma warning(pop)
#endif

// ============================================================================
// Hex (legacy)

extern const int8_t unhex_table[256];

template <typename TypeName>
static size_t HexDecode(char* buf,
size_t len,
const TypeName* src,
const size_t srcLen) {
size_t i;
for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) {
unsigned a = unhex_table[static_cast<uint8_t>(src[i * 2 + 0])];
unsigned b = unhex_table[static_cast<uint8_t>(src[i * 2 + 1])];
if (!~a || !~b)
return i;
buf[i] = (a << 4) | b;
}

return i;
}

size_t HexEncode(
const char* src,
size_t slen,
char* dst,
size_t dlen);

std::string HexEncode(const char* src, size_t slen);

} // namespace nbytes
9 changes: 5 additions & 4 deletions src/crypto/crypto_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "node_internals.h"
#include "string_bytes.h"
#include "v8.h"
#include "nbytes.h"

#include <openssl/ec.h>
#include <openssl/ecdh.h>
Expand Down Expand Up @@ -90,10 +91,10 @@ void LogSecret(
}

std::string line = name;
line += " " + StringBytes::hex_encode(reinterpret_cast<const char*>(crandom),
kTlsClientRandomSize);
line += " " + StringBytes::hex_encode(
reinterpret_cast<const char*>(secret), secretlen);
line += " " + nbytes::HexEncode(reinterpret_cast<const char*>(crandom),
kTlsClientRandomSize);
line += " " + nbytes::HexEncode(reinterpret_cast<const char*>(secret),
secretlen);
keylog_cb(ssl.get(), line.c_str());
}

Expand Down
9 changes: 5 additions & 4 deletions src/quic/cid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <node_mutex.h>
#include <string_bytes.h>
#include "quic/defs.h"
#include "nbytes.h"

namespace node {
namespace quic {
Expand Down Expand Up @@ -72,10 +73,10 @@ size_t CID::length() const {
std::string CID::ToString() const {
char dest[kMaxLength * 2];
size_t written =
StringBytes::hex_encode(reinterpret_cast<const char*>(ptr_->data),
ptr_->datalen,
dest,
arraysize(dest));
nbytes::HexEncode(reinterpret_cast<const char*>(ptr_->data),
ptr_->datalen,
dest,
arraysize(dest));
return std::string(dest, written);
}

Expand Down
9 changes: 5 additions & 4 deletions src/quic/tokens.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <string_bytes.h>
#include <util-inl.h>
#include <algorithm>
#include "nbytes.h"

namespace node {
namespace quic {
Expand Down Expand Up @@ -49,7 +50,7 @@ TokenSecret::operator const char*() const {

std::string TokenSecret::ToString() const {
char dest[QUIC_TOKENSECRET_LEN * 2];
size_t written = StringBytes::hex_encode(
size_t written = nbytes::HexEncode(
*this, QUIC_TOKENSECRET_LEN, dest, arraysize(dest));
DCHECK_EQ(written, arraysize(dest));
return std::string(dest, written);
Expand Down Expand Up @@ -117,7 +118,7 @@ std::string StatelessResetToken::ToString() const {
if (ptr_ == nullptr) return std::string();
char dest[kStatelessTokenLen * 2];
size_t written =
StringBytes::hex_encode(*this, kStatelessTokenLen, dest, arraysize(dest));
nbytes::HexEncode(*this, kStatelessTokenLen, dest, arraysize(dest));
DCHECK_EQ(written, arraysize(dest));
return std::string(dest, written);
}
Expand Down Expand Up @@ -230,7 +231,7 @@ std::string RetryToken::ToString() const {
if (ptr_.base == nullptr) return std::string();
MaybeStackBuffer<char, 32> dest(ptr_.len * 2);
size_t written =
StringBytes::hex_encode(*this, ptr_.len, dest.out(), dest.length());
nbytes::HexEncode(*this, ptr_.len, dest.out(), dest.length());
DCHECK_EQ(written, dest.length());
return std::string(dest.out(), written);
}
Expand Down Expand Up @@ -289,7 +290,7 @@ std::string RegularToken::ToString() const {
if (ptr_.base == nullptr) return std::string();
MaybeStackBuffer<char, 32> dest(ptr_.len * 2);
size_t written =
StringBytes::hex_encode(*this, ptr_.len, dest.out(), dest.length());
nbytes::HexEncode(*this, ptr_.len, dest.out(), dest.length());
DCHECK_EQ(written, dest.length());
return std::string(dest.out(), written);
}
Expand Down
Loading

0 comments on commit 05e5cde

Please sign in to comment.