Reputation: 5259
Forgive me if this is completely obvious, but I am sending data over the network using a byte array, and I need to stuff an integer into it and then get it back out at the other side.
Type definitions in the example:
uint8_t *dest;
uint8_t *ciphertext;
size_t cbytes; // length of ciphertext
uint8_t iv[16];
uint8_t tag[16];
Relevant portion of the writer:
size_t bytes = 0;
memcpy(&dest[bytes], iv, sizeof(iv));
bytes = sizeof(iv);
memcpy(&dest[bytes], (void*)htonl(cbytes), sizeof(uint32_t));
bytes += sizeof(uint32_t);
memcpy(&dest[bytes], ciphertext, cbytes);
bytes += cbytes;
memcpy(&dest[bytes], tag, sizeof(tag));
bytes += sizeof(tag);
Is this a correct way of stuffing cbytes
, as an integer into the byte array? If not, what is a better way of doing it?
Now, with this byte array, how do I read cbytes
back out into an integer (or size_t)? The rest of it can just be copied back out, but not sure what to do about the integer.
Upvotes: 0
Views: 336
Reputation: 134066
You're asking about this piece of code:
memcpy(&dest[bytes], (void*)htonl(cbytes), sizeof(uint32_t));
No, it is not correct at all. You're converting the return value of htonl
to a pointer. It is not a valid pointer however. You have to have an object of type uint32_t
for sending:
uint32_t cbytes32 = htonl(cbytes);
memcpy(&dest[bytes], &cbytes32, sizeof(uint32_t));
It is possible to do this on one line too, in modern C, using a compound literal to create an array of one uint32_t
inline:
memcpy(&dest[bytes], (uint32_t[]){ htonl(cbytes) }, sizeof(uint32_t));
but the syntax really does not look any nicer.
To read it in, you need to read it to an object of type uint32_t
, then ntohl
it, and the return value you can store into size_t
:
uint32_t size32;
size_t size;
memcpy(&size32, src, sizeof size32)
size = ntohl(size32);
Then, I'd be extra careful with that you're using a possibly 64-bit size_t
elsewhere but truncating it to 32 bits here. It might be OK but that would need to be documented. 64 bits should be enough for everyone, but unfortunately there is no htonll
function.
Finally, instead of &dest[bytes]
you can write dest + bytes
for less keypresses. And for even less, you can make another pointer:
uint8_t *cur = dest;
memcpy(cur, iv, sizeof iv);
cur += sizeof iv;
uint32_t cbytes32 = htonl(cbytes);
memcpy(cur, &cbytes32, sizeof cbytes32);
cur += sizeof cbytes32;
memcpy(cur, ciphertext, cbytes32);
cur += cbytes32;
memcpy(cur, tag, sizeof tag);
cur += sizeof tag;
size_t nbytes = cur - dest;
Note that if you're using a streaming socket (TCP) there is usually no need to copy them into an intermediate buffer - just send the 4, 8 bytes using a separate read
call - or at least, do not bother copying a long array into the same buffer after the size call.
Upvotes: 1