Skip to content

Commit 05e5cde

Browse files
committed
src, deps: move hex_encode/decode/forceAscii to nbytes
1 parent dff4a35 commit 05e5cde

7 files changed

Lines changed: 197 additions & 145 deletions

File tree

deps/nbytes/nbytes.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,106 @@ const int8_t unbase64_table[256] =
146146
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
147147
};
148148

149+
// ============================================================================
150+
// Hex
151+
152+
const int8_t unhex_table[256] =
153+
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
154+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
155+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
156+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
157+
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
158+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
159+
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
160+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
161+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
162+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
163+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
164+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
165+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
166+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
167+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
168+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
169+
};
170+
171+
size_t HexEncode(
172+
const char* src,
173+
size_t slen,
174+
char* dst,
175+
size_t dlen) {
176+
// We know how much we'll write, just make sure that there's space.
177+
NBYTES_ASSERT_TRUE(
178+
dlen >= MultiplyWithOverflowCheck<size_t>(slen, 2u) &&
179+
"not enough space provided for hex encode");
180+
181+
dlen = slen * 2;
182+
for (size_t i = 0, k = 0; k < dlen; i += 1, k += 2) {
183+
static const char hex[] = "0123456789abcdef";
184+
uint8_t val = static_cast<uint8_t>(src[i]);
185+
dst[k + 0] = hex[val >> 4];
186+
dst[k + 1] = hex[val & 15];
187+
}
188+
189+
return dlen;
190+
}
191+
192+
std::string HexEncode(const char* src, size_t slen) {
193+
size_t dlen = slen * 2;
194+
std::string dst(dlen, '\0');
195+
HexEncode(src, slen, dst.data(), dlen);
196+
return dst;
197+
}
198+
199+
// ============================================================================
200+
201+
void ForceAsciiSlow(const char* src, char* dst, size_t len) {
202+
for (size_t i = 0; i < len; ++i) {
203+
dst[i] = src[i] & 0x7f;
204+
}
205+
}
206+
207+
void ForceAscii(const char* src, char* dst, size_t len) {
208+
if (len < 16) {
209+
ForceAsciiSlow(src, dst, len);
210+
return;
211+
}
212+
213+
const unsigned bytes_per_word = sizeof(uintptr_t);
214+
const unsigned align_mask = bytes_per_word - 1;
215+
const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask;
216+
const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask;
217+
218+
if (src_unalign > 0) {
219+
if (src_unalign == dst_unalign) {
220+
const unsigned unalign = bytes_per_word - src_unalign;
221+
ForceAsciiSlow(src, dst, unalign);
222+
src += unalign;
223+
dst += unalign;
224+
len -= src_unalign;
225+
} else {
226+
ForceAsciiSlow(src, dst, len);
227+
return;
228+
}
229+
}
230+
231+
#if defined(_WIN64) || defined(_LP64)
232+
const uintptr_t mask = ~0x8080808080808080ll;
233+
#else
234+
const uintptr_t mask = ~0x80808080l;
235+
#endif
149236

237+
const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
238+
uintptr_t* dstw = reinterpret_cast<uintptr_t*>(dst);
239+
240+
for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
241+
dstw[i] = srcw[i] & mask;
242+
}
243+
244+
const unsigned remainder = len & align_mask;
245+
if (remainder > 0) {
246+
const size_t offset = len - remainder;
247+
ForceAsciiSlow(src + offset, dst + offset, remainder);
248+
}
249+
}
150250

151251
} // namespace nbytes

deps/nbytes/nbytes.h

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,44 @@
11
#pragma once
22

3-
#include <stddef.h>
4-
#include <stdint.h>
5-
#include <cmath>
3+
#include <string>
64
#include <cstddef>
5+
#include <cstdint>
6+
#include <cmath>
77

88
namespace nbytes {
99

10+
#if NBYTES_DEVELOPMENT_CHECKS
11+
#define NBYTES_STR(x) #x
12+
#define NBYTES_REQUIRE(EXPR) \
13+
{ \
14+
if (!(EXPR) { abort(); }) }
15+
16+
#define NBYTES_FAIL(MESSAGE) \
17+
do { \
18+
std::cerr << "FAIL: " << (MESSAGE) << std::endl; \
19+
abort(); \
20+
} while (0);
21+
#define NBYTES_ASSERT_EQUAL(LHS, RHS, MESSAGE) \
22+
do { \
23+
if (LHS != RHS) { \
24+
std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \
25+
NBYTES_FAIL(MESSAGE); \
26+
} \
27+
} while (0);
28+
#define NBYTES_ASSERT_TRUE(COND) \
29+
do { \
30+
if (!(COND)) { \
31+
std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \
32+
<< std::endl; \
33+
NBYTES_FAIL(NBYTES_STR(COND)); \
34+
} \
35+
} while (0);
36+
#else
37+
#define NBYTES_FAIL(MESSAGE)
38+
#define NBYTES_ASSERT_EQUAL(LHS, RHS, MESSAGE)
39+
#define NBYTES_ASSERT_TRUE(COND)
40+
#endif
41+
1042
// The nbytes (short for "node bytes") is a set of utility helpers for
1143
// working with bytes that are extracted from Node.js' internals. The
1244
// motivation for extracting these into a separate library is to make it
@@ -26,6 +58,19 @@ constexpr T* AlignUp(T* ptr, U alignment) {
2658
RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment));
2759
}
2860

61+
template <typename T>
62+
inline T MultiplyWithOverflowCheck(T a, T b) {
63+
auto ret = a * b;
64+
if (a != 0) {
65+
NBYTES_ASSERT_TRUE(b == ret / a);
66+
}
67+
68+
return ret;
69+
}
70+
71+
void ForceAsciiSlow(const char* src, char* dst, size_t len);
72+
void ForceAscii(const char* src, char* dst, size_t len);
73+
2974
// ============================================================================
3075
// Byte Swapping
3176

@@ -160,4 +205,34 @@ size_t Base64Decode(char* const dst, const size_t dstlen,
160205
#pragma warning(pop)
161206
#endif
162207

208+
// ============================================================================
209+
// Hex (legacy)
210+
211+
extern const int8_t unhex_table[256];
212+
213+
template <typename TypeName>
214+
static size_t HexDecode(char* buf,
215+
size_t len,
216+
const TypeName* src,
217+
const size_t srcLen) {
218+
size_t i;
219+
for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) {
220+
unsigned a = unhex_table[static_cast<uint8_t>(src[i * 2 + 0])];
221+
unsigned b = unhex_table[static_cast<uint8_t>(src[i * 2 + 1])];
222+
if (!~a || !~b)
223+
return i;
224+
buf[i] = (a << 4) | b;
225+
}
226+
227+
return i;
228+
}
229+
230+
size_t HexEncode(
231+
const char* src,
232+
size_t slen,
233+
char* dst,
234+
size_t dlen);
235+
236+
std::string HexEncode(const char* src, size_t slen);
237+
163238
} // namespace nbytes

src/crypto/crypto_common.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "node_internals.h"
99
#include "string_bytes.h"
1010
#include "v8.h"
11+
#include "nbytes.h"
1112

1213
#include <openssl/ec.h>
1314
#include <openssl/ecdh.h>
@@ -90,10 +91,10 @@ void LogSecret(
9091
}
9192

9293
std::string line = name;
93-
line += " " + StringBytes::hex_encode(reinterpret_cast<const char*>(crandom),
94-
kTlsClientRandomSize);
95-
line += " " + StringBytes::hex_encode(
96-
reinterpret_cast<const char*>(secret), secretlen);
94+
line += " " + nbytes::HexEncode(reinterpret_cast<const char*>(crandom),
95+
kTlsClientRandomSize);
96+
line += " " + nbytes::HexEncode(reinterpret_cast<const char*>(secret),
97+
secretlen);
9798
keylog_cb(ssl.get(), line.c_str());
9899
}
99100

src/quic/cid.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <node_mutex.h>
66
#include <string_bytes.h>
77
#include "quic/defs.h"
8+
#include "nbytes.h"
89

910
namespace node {
1011
namespace quic {
@@ -72,10 +73,10 @@ size_t CID::length() const {
7273
std::string CID::ToString() const {
7374
char dest[kMaxLength * 2];
7475
size_t written =
75-
StringBytes::hex_encode(reinterpret_cast<const char*>(ptr_->data),
76-
ptr_->datalen,
77-
dest,
78-
arraysize(dest));
76+
nbytes::HexEncode(reinterpret_cast<const char*>(ptr_->data),
77+
ptr_->datalen,
78+
dest,
79+
arraysize(dest));
7980
return std::string(dest, written);
8081
}
8182

src/quic/tokens.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <string_bytes.h>
88
#include <util-inl.h>
99
#include <algorithm>
10+
#include "nbytes.h"
1011

1112
namespace node {
1213
namespace quic {
@@ -49,7 +50,7 @@ TokenSecret::operator const char*() const {
4950

5051
std::string TokenSecret::ToString() const {
5152
char dest[QUIC_TOKENSECRET_LEN * 2];
52-
size_t written = StringBytes::hex_encode(
53+
size_t written = nbytes::HexEncode(
5354
*this, QUIC_TOKENSECRET_LEN, dest, arraysize(dest));
5455
DCHECK_EQ(written, arraysize(dest));
5556
return std::string(dest, written);
@@ -117,7 +118,7 @@ std::string StatelessResetToken::ToString() const {
117118
if (ptr_ == nullptr) return std::string();
118119
char dest[kStatelessTokenLen * 2];
119120
size_t written =
120-
StringBytes::hex_encode(*this, kStatelessTokenLen, dest, arraysize(dest));
121+
nbytes::HexEncode(*this, kStatelessTokenLen, dest, arraysize(dest));
121122
DCHECK_EQ(written, arraysize(dest));
122123
return std::string(dest, written);
123124
}
@@ -230,7 +231,7 @@ std::string RetryToken::ToString() const {
230231
if (ptr_.base == nullptr) return std::string();
231232
MaybeStackBuffer<char, 32> dest(ptr_.len * 2);
232233
size_t written =
233-
StringBytes::hex_encode(*this, ptr_.len, dest.out(), dest.length());
234+
nbytes::HexEncode(*this, ptr_.len, dest.out(), dest.length());
234235
DCHECK_EQ(written, dest.length());
235236
return std::string(dest.out(), written);
236237
}
@@ -289,7 +290,7 @@ std::string RegularToken::ToString() const {
289290
if (ptr_.base == nullptr) return std::string();
290291
MaybeStackBuffer<char, 32> dest(ptr_.len * 2);
291292
size_t written =
292-
StringBytes::hex_encode(*this, ptr_.len, dest.out(), dest.length());
293+
nbytes::HexEncode(*this, ptr_.len, dest.out(), dest.length());
293294
DCHECK_EQ(written, dest.length());
294295
return std::string(dest.out(), written);
295296
}

0 commit comments

Comments
 (0)