Skip to content

Commit 0839c5b

Browse files
committed
protocol: Make T_DATUM_PROTOCOL_HEADER serialisation explicit
Should improve portability In particular, this fixes big endian systems, as well as: warning: bit-field ___ of type ___ has a different storage size than the preceding bit-field and will not be packed under the Microsoft ABI [-Wms-bitfield-padding]
1 parent c8cb0da commit 0839c5b

File tree

2 files changed

+46
-28
lines changed

2 files changed

+46
-28
lines changed

src/datum_protocol.c

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,6 @@ unsigned char datum_protocol_setup_new_job_idx(void *sx) {
149149
return a;
150150
}
151151

152-
static inline void datum_xor_header_key(void *h, uint32_t key) {
153-
*((uint32_t *)h) ^= key;
154-
}
155-
156152
uint32_t datum_header_xor_feedback(const uint32_t i) {
157153
uint32_t s = 0xb10cfeed;
158154
uint32_t h = s;
@@ -172,6 +168,32 @@ uint32_t datum_header_xor_feedback(const uint32_t i) {
172168
return h;
173169
}
174170

171+
static
172+
void datum_header_pk(uint8_t * const dst, const size_t offset, const T_DATUM_PROTOCOL_HEADER * const h, uint32_t * const xor_key) {
173+
uint32_t raw = (h->cmd_len & 0x3fffffUL) |
174+
((uint32_t)h->is_signed << 24) |
175+
((uint32_t)h->is_encrypted_pubkey << 25) |
176+
((uint32_t)h->is_encrypted_channel << 26) |
177+
((uint32_t)(h->proto_cmd & 0x1f) << 27);
178+
raw ^= *xor_key;
179+
*xor_key = datum_header_xor_feedback(*xor_key);
180+
181+
pk_u32le(dst, offset, raw);
182+
}
183+
184+
static
185+
void datum_header_upk(T_DATUM_PROTOCOL_HEADER * const h, const uint8_t * const src, const size_t offset, uint32_t * const xor_key) {
186+
uint32_t raw = upk_u32le(src, offset);
187+
raw ^= *xor_key;
188+
*xor_key = datum_header_xor_feedback(*xor_key);
189+
190+
h->cmd_len = raw & 0x003fffffUL;
191+
h->is_signed = raw & 0x01000000UL;
192+
h->is_encrypted_pubkey = raw & 0x02000000UL;
193+
h->is_encrypted_channel = raw & 0x04000000UL;
194+
h->proto_cmd = (raw >> 27) & 0x1f;
195+
}
196+
175197
// Take the hexidecimal public key string and store it in a DATUM_ENC_KEYS
176198
int datum_pubkey_to_struct(const char *input, DATUM_ENC_KEYS *key) {
177199
int i;
@@ -229,6 +251,7 @@ int datum_protocol_mining_cmd(void *data, int len) {
229251
// encypt and send a standard mining sub-command
230252
// this can be called from other threads so must be thread safe!
231253
T_DATUM_PROTOCOL_HEADER h;
254+
unsigned char wire_h[T_DATUM_PROTOCOL_HEADER_WIRE_BYTES];
232255
int i;
233256

234257
memset(&h, 0, sizeof(T_DATUM_PROTOCOL_HEADER));
@@ -244,11 +267,10 @@ int datum_protocol_mining_cmd(void *data, int len) {
244267

245268
crypto_box_easy_afternm(data, data, len, session_nonce_sender, session_precomp.precomp_remote);
246269
//DLOG_DEBUG("mining cmd 5--- len %d, send header key %8.8x, raw %8.8lx", h.cmd_len, sending_header_key, (unsigned long)upk_u32le(h, 0));
247-
datum_xor_header_key(&h, sending_header_key);
248-
sending_header_key = datum_header_xor_feedback(sending_header_key);
270+
datum_header_pk(wire_h, 0, &h, &sending_header_key);
249271
datum_increment_session_nonce(session_nonce_sender);
250272

251-
i = datum_protocol_chars_to_server((unsigned char *)&h, sizeof(T_DATUM_PROTOCOL_HEADER));
273+
i = datum_protocol_chars_to_server(wire_h, sizeof(wire_h));
252274
if (i < 1) {
253275
pthread_mutex_unlock(&datum_protocol_sender_stage1_lock);
254276
return -1;
@@ -1038,16 +1060,12 @@ int datum_protocol_send_hello(int sockfd) {
10381060
i+=crypto_sign_BYTES;
10391061

10401062
// seal it up
1041-
crypto_box_seal(&enc_hello_msg[sizeof(T_DATUM_PROTOCOL_HEADER)], hello_msg, i, pool_keys.pk_x25519);
1063+
crypto_box_seal(&enc_hello_msg[T_DATUM_PROTOCOL_HEADER_WIRE_BYTES], hello_msg, i, pool_keys.pk_x25519);
10421064
i+=crypto_box_SEALBYTES;
10431065

10441066
h.cmd_len = i;
10451067

1046-
memcpy(enc_hello_msg, &h, sizeof(T_DATUM_PROTOCOL_HEADER));
1047-
1048-
// apply our initial xor key to the header, just to obfuscate it a tiny bit
1049-
// kinda pointless, but ok
1050-
datum_xor_header_key(&enc_hello_msg[0], sending_header_key);
1068+
datum_header_pk(enc_hello_msg, 0, &h, &sending_header_key);
10511069

10521070
DLOG_DEBUG("Sending handshake init (%d bytes)", h.cmd_len);
10531071

@@ -1070,7 +1088,7 @@ int datum_protocol_send_hello(int sockfd) {
10701088
// FIXME: why is this mixed-endian?
10711089
//DLOG_DEBUG("Session Nonce: %8.8X%8.8X%8.8X%8.8X%8.8X%8.8X", upk_u32le(session_nonce_receiver, 0), upk_u32le(session_nonce_receiver, 4), upk_u32le(session_nonce_receiver, 8), upk_u32le(session_nonce_receiver, 12), upk_u32le(session_nonce_receiver, 16), upk_u32le(session_nonce_receiver, 20));
10721090

1073-
return datum_protocol_chars_to_server(enc_hello_msg, i+sizeof(T_DATUM_PROTOCOL_HEADER));
1091+
return datum_protocol_chars_to_server(enc_hello_msg, T_DATUM_PROTOCOL_HEADER_WIRE_BYTES + i);
10741092
}
10751093

10761094
int datum_protocol_decrypt_sealed(T_DATUM_PROTOCOL_HEADER *h, unsigned char *data) {
@@ -1464,6 +1482,7 @@ void *datum_protocol_client(void *args) {
14641482
bool break_again = false;
14651483
int sent = 0;
14661484
T_DATUM_PROTOCOL_HEADER s_header;
1485+
unsigned char wire_h[T_DATUM_PROTOCOL_HEADER_WIRE_BYTES];
14671486

14681487
pthread_rwlock_wrlock(&datum_jobs_rwlock);
14691488
for(i=0;i<MAX_DATUM_PROTOCOL_JOBS;i++) {
@@ -1709,7 +1728,7 @@ void *datum_protocol_client(void *args) {
17091728
case 1:
17101729
case 2:
17111730
case 3: {
1712-
n = recv(sockfd, ((unsigned char *)&s_header) + (sizeof(T_DATUM_PROTOCOL_HEADER) - protocol_state), protocol_state, MSG_DONTWAIT);
1731+
n = recv(sockfd, &wire_h[sizeof(wire_h) - protocol_state], protocol_state, MSG_DONTWAIT);
17131732
if (n <= 0) {
17141733
if ((n < 0) && ((errno == EAGAIN || errno == EWOULDBLOCK))) {
17151734
continue;
@@ -1718,34 +1737,34 @@ void *datum_protocol_client(void *args) {
17181737
break_again = true; break;
17191738
}
17201739

1721-
if ((n+(sizeof(T_DATUM_PROTOCOL_HEADER) - protocol_state)) != sizeof(T_DATUM_PROTOCOL_HEADER)) {
1740+
if ((n + (sizeof(wire_h) - protocol_state)) != sizeof(wire_h)) {
17221741
if ((n+protocol_state) > 4) {
17231742
DLOG_DEBUG("recv() issue. too many header bytes. protocol_state=%d, n=%d, errno=%d (%s)", protocol_state, n, errno, strerror(errno));
17241743
break_again = true; break;
17251744
}
17261745

1727-
protocol_state = sizeof(T_DATUM_PROTOCOL_HEADER) - n - (sizeof(T_DATUM_PROTOCOL_HEADER) - protocol_state); // should give us a state equal to the number of. consoluted to show the process. (compiler optimizes)
1746+
protocol_state = sizeof(wire_h) - n - (sizeof(wire_h) - protocol_state); // should give us a state equal to the number of. consoluted to show the process. (compiler optimizes)
17281747
continue;
17291748
}
17301749

17311750
protocol_state = 4;
17321751
continue; // cant fall through to 0, so loop around back to this to jump to 4
17331752
}
17341753
case 0: {
1735-
n = recv(sockfd, &s_header, sizeof(T_DATUM_PROTOCOL_HEADER), MSG_DONTWAIT);
1754+
n = recv(sockfd, &wire_h[0], sizeof(wire_h), MSG_DONTWAIT);
17361755
if (n <= 0) {
17371756
if ((n < 0) && ((errno == EAGAIN || errno == EWOULDBLOCK))) {
17381757
continue;
17391758
}
17401759
DLOG_DEBUG("recv() issue. protocol_state=%d, n=%d, errno=%d (%s)", protocol_state, n, errno, strerror(errno));
17411760
break_again = true; break;
17421761
}
1743-
if (n != sizeof(T_DATUM_PROTOCOL_HEADER)) {
1762+
if (n != sizeof(wire_h)) {
17441763
if (n > 4) {
17451764
DLOG_DEBUG("recv() issue. too many header bytes (B). protocol_state=%d, n=%d, errno=%d (%s)", protocol_state, n, errno, strerror(errno));
17461765
break_again = true; break;
17471766
}
1748-
protocol_state = sizeof(T_DATUM_PROTOCOL_HEADER)-n;
1767+
protocol_state = sizeof(wire_h) - n;
17491768
continue;
17501769
}
17511770

@@ -1755,9 +1774,8 @@ void *datum_protocol_client(void *args) {
17551774
}
17561775

17571776
case 4: {
1758-
datum_xor_header_key(&s_header, receiving_header_key);
1759-
//DLOG_DEBUG("Server CMD: cmd=%u, len=%u, raw = %8.8x ... rkey = %8.8x", s_header.proto_cmd, s_header.cmd_len, upk_u32le(s_header, 0), receiving_header_key);
1760-
receiving_header_key = datum_header_xor_feedback(receiving_header_key);
1777+
datum_header_upk(&s_header, wire_h, 0, &receiving_header_key);
1778+
//DLOG_DEBUG("Server CMD: cmd=%u, len=%u, raw = %8.8x ... rkey(after) = %8.8x", s_header.proto_cmd, s_header.cmd_len, upk_u32le(s_header, 0), receiving_header_key);
17611779
protocol_state = 5;
17621780
server_in_buf = 0;
17631781
if (!s_header.cmd_len) {

src/datum_protocol.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@
5858
// It's likely possible to brute force the XOR key to break packets down into individual commands, but the contents and nature of the
5959
// cmd is still obfuscated and unrecoverable without the session keys.
6060

61-
typedef struct __attribute__((packed)) T_DATUM_PROTOCOL_HEADER {
61+
typedef struct T_DATUM_PROTOCOL_HEADER {
6262
uint32_t cmd_len:22; // max cmd size is 2^22 (~4MB), which is roughly the max block size for a raw submission or a raw template validation
63-
uint8_t reserved:2; // save for later use
64-
bool is_signed:1;
65-
bool is_encrypted_pubkey:1;
66-
bool is_encrypted_channel:1;
63+
bool is_signed;
64+
bool is_encrypted_pubkey;
65+
bool is_encrypted_channel;
6766
uint8_t proto_cmd:5; // 32 protocol level commands
6867
} T_DATUM_PROTOCOL_HEADER;
68+
#define T_DATUM_PROTOCOL_HEADER_WIRE_BYTES 4
6969

7070
typedef struct {
7171
bool is_remote;

0 commit comments

Comments
 (0)