Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to change byte order of 128 bit number

Tags:

c

gcc

I have an array of unsigned char that represents a 128 bit number in network byte order. How would I go about converting this to host byte order efficiently (in this case x86_64)?

There don't seem to be any macros available in endian.h and my attempt at converting the upper 64 bits and lower 64 bits independently didn't work. The only method I've found that definitely works is a loop like so:

unsigned __int128 num = 0;
for (int i = 0; i < 16; i++) {
    num = (num << 8) | byte[i];
}

I ended up doing the follow:

union {
    unsigned char b[MD5_DIGEST_LENGTH];
    uint64_t d[2];
    unsigned __int128 q;
} digest;
MD5((const unsigned char *)str, length, digest.b);
uint64_t tmp = digest.d[0];
digest.d[0] = be64toh(digest.d[1]);
digest.d[1] = be64toh(tmp);
/* digest.q is now in native byte order */
like image 908
btmorex Avatar asked Nov 04 '11 04:11

btmorex


2 Answers

If you can easily get the high and low __int64s, then you can reverse and swap them.  Otherwise, you'll probably have to look at every byte individually.

like image 127
Joshua Green Avatar answered Oct 06 '22 00:10

Joshua Green


union _128_as_32 {
    unsigned __int128 v;
    unsigned __int32 d[4];
} u1, u2;
u1.v = num;
u2.d[3] = ntohl(u1.d[0]);
u2.d[2] = ntohl(u1.d[1]);
u2.d[1] = ntohl(u1.d[2]);
u2.d[0] = ntohl(u1.d[3]);
// do something with u2.v

If your environment has betoh64/be64toh (linux/bsd endian.h), you can use

union _128_as_64 {
    unsigned __int128 v;
    unsigned __int64 q[2];
} u1, u2;
u1.v = num;
u2.q[1] = betoh64(u1.q[0]);
u2.q[0] = betoh64(u1.q[1]);
// do something with u2.v

Seeing as you're likely dealing with IN6 addresses, you should have the ntohl family of functions already available.

H.T.H.

like image 31
moshbear Avatar answered Oct 06 '22 01:10

moshbear