From f734149af2c1abfb3e5bde9ca1deeae007cf0465 Mon Sep 17 00:00:00 2001 From: wiire-a Date: Fri, 24 Nov 2017 18:48:40 +0100 Subject: [PATCH] Switched to compile-time endianness detection --- src/config.h | 3 + src/endianness.h | 263 +++++++++++++++++++++++++++++++++++++++++++++++ src/pixiewps.c | 10 +- src/utils.h | 37 ------- src/wps.h | 13 +-- 5 files changed, 278 insertions(+), 48 deletions(-) create mode 100644 src/endianness.h diff --git a/src/config.h b/src/config.h index 47bcc43..3486f29 100644 --- a/src/config.h +++ b/src/config.h @@ -19,6 +19,9 @@ #include +#define ENDIANNESS_PORTABLE_CONVERSION +#include "endianness.h" + typedef unsigned char uint8_t; #include "mbedtls/md_internal.h" diff --git a/src/endianness.h b/src/endianness.h new file mode 100644 index 0000000..dabe75d --- /dev/null +++ b/src/endianness.h @@ -0,0 +1,263 @@ +#ifndef ENDIANNESS_H +#define ENDIANNESS_H + +/* Public domain implementation for endianness detection and byte ordering on + several platforms. In case the concept of public domain does not exist + under your jurisdiction, you can consider it to be dual licensed + under the MIT, Apache and WTFPL licenses. + + Grab it and drop it into your project, include it and use + the following macros to determine endianness: + + ENDIANNESS_LE, ENDIANNESS_BE + + e.g. #if ENDIANNESS_LE ... + + or, even nicer without littering your code with #ifdefs: + + if (ENDIANNESS_BE) { big_endian_code(); } else { little_endian_code(); } + + ... since the compiler can optimize away unused branches, this makes your + code easier to read while not loosing any of the advantage of using + conditional compilation, plus you get a free compile-time check of the + unused code path (rarely used conditonally compiled code paths often get + defunct over time if nobody checks them all the time). + + To debug this header yourself, you can define ENDIANNESS_DEBUG to see + warnings from where we take the defs for the specific target. + + If you need only the conversion functions from big to little endian + and vice versa, you may want to #define ENDIANNESS_PORTABLE_CONVERSION + prior to including this header. That way, when the endiannes can't be + determined at compile time, the code will fallback to a slower, + but portable version of those functions. + However, if using it, it's not guaranteed that ENDIANNESS_LE/BE + will be defined. + Most people however need only the conversion functions in their code, + so if you stick to them you can safely turn the portable conversion on. +*/ + +/* This should catch all modern GCCs and Clang */ +#if (defined __BYTE_ORDER__) && (defined __ORDER_LITTLE_ENDIAN__) +# ifdef ENDIANNESS_DEBUG +# warning "Taking endiannes from built-in __BYTE_ORDER__" +# endif +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define ENDIANNESS_LE 1 +# define ENDIANNESS_BE 0 +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define ENDIANNESS_LE 0 +# define ENDIANNESS_BE 1 +# endif +/* Try to derive from arch/compiler-specific macros */ +#elif defined(_X86_) || defined(__x86_64__) || defined(__i386__) || \ + defined(__i486__) || defined(__i586__) || defined(__i686__) || \ + defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) || \ + defined(__ARMEL__) || \ + (defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__ == 1) || \ + (defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN == 1) || \ + defined(_M_IX86) || defined(_M_AMD64) /* MSVC */ +# ifdef ENDIANNESS_DEBUG +# warning "Detected Little Endian target CPU" +# endif +# define ENDIANNESS_LE 1 +# define ENDIANNESS_BE 0 +#elif defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) || \ + defined(__MICROBLAZEEB__) || defined(__ARMEB__) || \ + (defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ == 1) || \ + (defined(_BIG_ENDIAN) && _BIG_ENDIAN == 1) +# ifdef ENDIANNESS_DEBUG +# warning "Detected Big Endian target CPU" +# endif +# define ENDIANNESS_LE 0 +# define ENDIANNESS_BE 1 +/* Try to get it from a header */ +#else +# if defined(__linux) +# ifdef ENDIANNESS_DEBUG +# warning "Taking endiannes from endian.h" +# endif +# include +# else +# ifdef ENDIANNESS_DEBUG +# warning "Taking endiannes from machine/endian.h" +# endif +# include +# endif +#endif + +#ifndef ENDIANNESS_LE +# undef ENDIANNESS_BE +# if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define ENDIANNESS_LE 1 +# define ENDIANNESS_BE 0 +# elif __BYTE_ORDER == __BIG_ENDIAN +# define ENDIANNESS_LE 0 +# define ENDIANNESS_BE 1 +# endif +# elif defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) +# if BYTE_ORDER == LITTLE_ENDIAN +# define ENDIANNESS_LE 1 +# define ENDIANNESS_BE 0 +# elif BYTE_ORDER == BIG_ENDIAN +# define ENDIANNESS_LE 0 +# define ENDIANNESS_BE 1 +# endif +# endif +#endif + +/* In case the user passed one of -DENDIANNESS_LE or BE in CPPFLAS, + set the second one too */ +#if defined(ENDIANNESS_LE) && !(defined(ENDIANNESS_BE)) +# if ENDIANNESS_LE == 0 +# define ENDIANNESS_BE 1 +# else +# define ENDIANNESS_BE 0 +# endif +#elif defined(ENDIANNESS_BE) && !(defined(ENDIANNESS_LE)) +# if ENDIANNESS_BE == 0 +# define ENDIANNESS_LE 1 +# else +# define ENDIANNESS_LE 0 +# endif +#endif + +#if !(defined(ENDIANNESS_LE)) && !(defined(ENDIANNESS_PORTABLE_CONVERSION)) +# error "Sorry, we couldn't detect endiannes for your system! Please set -DENDIANNESS_LE=1 or 0 using your CPPFLAGS/CFLAGS and open an issue for your system on https://github.com/rofl0r/endianness.h - Thanks!" +#endif + +#include +#include + +static __inline uint16_t end_bswap16(uint16_t __x) +{ + return __x<<8 | __x>>8; +} + +static __inline uint32_t end_bswap32(uint32_t __x) +{ + return __x>>24 | __x>>8&0xff00 | __x<<8&0xff0000 | __x<<24; +} + +static __inline uint64_t end_bswap64(uint64_t __x) +{ + return end_bswap32(__x)+0ULL<<32 | end_bswap32(__x>>32); +} + +static __inline uint16_t end_net2host16(uint16_t net_number) +{ + uint16_t result = 0; + int i; + for (i = 0; i < (int)sizeof(result); i++) { + result <<= CHAR_BIT; + result += (((unsigned char *)&net_number)[i] & UCHAR_MAX); + } + return result; +} + +static __inline uint16_t end_host2net16(uint16_t native_number) +{ + uint16_t result = 0; + int i; + for (i = (int)sizeof(result) - 1; i >= 0; i--) { + ((unsigned char *)&result)[i] = native_number & UCHAR_MAX; + native_number >>= CHAR_BIT; + } + return result; +} + +static __inline uint32_t end_net2host32(uint32_t net_number) +{ + uint32_t result = 0; + int i; + for (i = 0; i < (int)sizeof(result); i++) { + result <<= CHAR_BIT; + result += (((unsigned char *)&net_number)[i] & UCHAR_MAX); + } + return result; +} + +static __inline uint32_t end_host2net32(uint32_t native_number) +{ + uint32_t result = 0; + int i; + for (i = (int)sizeof(result) - 1; i >= 0; i--) { + ((unsigned char *)&result)[i] = native_number & UCHAR_MAX; + native_number >>= CHAR_BIT; + } + return result; +} + +static __inline uint64_t end_net2host64(uint64_t net_number) +{ + uint64_t result = 0; + int i; + for (i = 0; i < (int)sizeof(result); i++) { + result <<= CHAR_BIT; + result += (((unsigned char *)&net_number)[i] & UCHAR_MAX); + } + return result; +} + +static __inline uint64_t end_host2net64(uint64_t native_number) +{ + uint64_t result = 0; + int i; + for (i = (int)sizeof(result) - 1; i >= 0; i--) { + ((unsigned char *)&result)[i] = native_number & UCHAR_MAX; + native_number >>= CHAR_BIT; + } + return result; +} + +#ifdef ENDIANNESS_LE +# define end_htobe16(x) end_bswap16(x) +# define end_be16toh(x) end_bswap16(x) +# define end_htobe32(x) end_bswap32(x) +# define end_be32toh(x) end_bswap32(x) +# define end_htobe64(x) end_bswap64(x) +# define end_be64toh(x) end_bswap64(x) +# define end_htole16(x) (uint16_t)(x) +# define end_le16toh(x) (uint16_t)(x) +# define end_htole32(x) (uint32_t)(x) +# define end_le32toh(x) (uint32_t)(x) +# define end_htole64(x) (uint64_t)(x) +# define end_le64toh(x) (uint64_t)(x) +#elif ENDIANNESS_BE +# define end_htobe16(x) (uint16_t)(x) +# define end_be16toh(x) (uint16_t)(x) +# define end_htobe32(x) (uint32_t)(x) +# define end_be32toh(x) (uint32_t)(x) +# define end_htobe64(x) (uint64_t)(x) +# define end_be64toh(x) (uint64_t)(x) +# define end_htole16(x) end_bswap16(x) +# define end_le16toh(x) end_bswap16(x) +# define end_htole32(x) end_bswap32(x) +# define end_le32toh(x) end_bswap32(x) +# define end_htole64(x) end_bswap64(x) +# define end_le64toh(x) end_bswap64(x) +#else +/* Resort to slower, but neutral code */ +# define end_htobe16(x) end_host2net16(x) +# define end_be16toh(x) end_net2host16(x) +# define end_htobe32(x) end_host2net32(x) +# define end_be32toh(x) end_net2host32(x) +# define end_htobe64(x) end_host2net64(x) +# define end_be64toh(x) end_net2host64(x) +# define end_htole16(x) end_bswap_16(end_host2net16(x)) +# define end_le16toh(x) end_bswap_16(end_host2net16(x)) +# define end_htole32(x) end_bswap_32(end_host2net32(x)) +# define end_le32toh(x) end_bswap_32(end_host2net32(x)) +# define end_htole64(x) end_bswap_64(end_host2net64(x)) +# define end_le64toh(x) end_bswap_64(end_host2net64(x)) +#endif + +#define end_ntoh16(x) end_be16toh(x) +#define end_hton16(x) end_htobe16(x) +#define end_ntoh32(x) end_be32toh(x) +#define end_hton32(x) end_htobe32(x) +#define end_ntoh64(x) end_be64toh(x) +#define end_hton64(x) end_htobe64(x) + +#endif diff --git a/src/pixiewps.c b/src/pixiewps.c index da6bf76..c2fce75 100644 --- a/src/pixiewps.c +++ b/src/pixiewps.c @@ -34,8 +34,8 @@ #include #include -#include "pixiewps.h" #include "config.h" +#include "pixiewps.h" #include "crypto/crypto_internal-modexp.c" #include "crypto/aes-cbc.c" #include "utils.h" @@ -671,7 +671,7 @@ usage_err: printf("\n [*] ES2: "); byte_array_print(vtag->data, WPS_NONCE_LEN); } if ((vtag = find_vtag(decrypted7, wps->m7_encr_len - 16, WPS_TAG_SSID, 0))) { - int tag_size = be16_to_h(vtag->len); + int tag_size = end_ntoh16(vtag->len); memcpy(buffer, vtag->data, tag_size); buffer[tag_size] = '\0'; printf("\n [*] SSID: %s", buffer); @@ -683,7 +683,7 @@ usage_err: printf("\n [+] WPS pin: %s", pin); } if ((vtag = find_vtag(decrypted7, wps->m7_encr_len - 16, WPS_TAG_NET_KEY, 0))) { - int tag_size = be16_to_h(vtag->len); + int tag_size = end_ntoh16(vtag->len); memcpy(buffer, vtag->data, tag_size); buffer[tag_size] = '\0'; printf("\n [+] WPA-PSK: %s", buffer); @@ -1108,7 +1108,7 @@ usage_err: i++; glibc_seed(&glibc_prng, nonce_seed + i); for (uint_fast8_t j = 0; j < 4; j++) { - uint32_t be = h32_to_be(glibc_rand(&glibc_prng)); + uint32_t be = end_htobe32(glibc_rand(&glibc_prng)); memcpy(&(wps->e_s1[4 * j]), &be, sizeof(uint32_t)); } memcpy(wps->e_s2, wps->e_s1, WPS_SECRET_NONCE_LEN); /* E-S1 = E-S2 != E-Nonce */ @@ -1164,7 +1164,7 @@ usage_err: i++; glibc_seed(&glibc_prng, nonce_seed - i); for (uint_fast8_t j = 0; j < 4; j++) { - uint32_t be = h32_to_be(glibc_rand(&glibc_prng)); + uint32_t be = end_htobe32(glibc_rand(&glibc_prng)); memcpy(&(wps->e_s1[4 * j]), &be, sizeof(uint32_t)); } memcpy(wps->e_s2, wps->e_s1, WPS_SECRET_NONCE_LEN); /* E-S1 = E-S2 != E-Nonce */ diff --git a/src/utils.h b/src/utils.h index 15507b3..5dfd61e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -260,41 +260,4 @@ void byte_array_print(const uint8_t *buffer, const unsigned int length) } } -/* Converts a 32 Little Endian bit number to its Big Endian representation */ -uint32_t h32_to_be(const uint32_t num) -{ - uint32_t tmp = num; - uint32_t res; - unsigned int i = 1; - char *p = (char *)&i; - - if (p[0] == 1) { /* LE */ - res = ((tmp & 0x000000ff) << 24) | ((tmp & 0x0000ff00) << 8) | - ((tmp & 0x00ff0000) >> 8) | ((tmp & 0xff000000) >> 24); - } - else { /* BE */ - res = num; - } - - return res; -} - -/* Converts a 16 Big Endian bit number to the host representation */ -uint16_t be16_to_h(const uint16_t num) -{ - uint16_t tmp = num; - uint16_t res; - unsigned int i = 1; - char *p = (char *)&i; - - if (p[0] == 1) { /* LE */ - res = ((tmp & 0x000000ff) << 8) | ((tmp & 0x0000ff00) >> 8); - } - else { /* BE */ - res = num; - } - - return res; -} - #endif /* UTILS_H */ diff --git a/src/wps.h b/src/wps.h index dad4512..7fb0283 100644 --- a/src/wps.h +++ b/src/wps.h @@ -35,8 +35,8 @@ #include #include -#include "pixiewps.h" #include "config.h" +#include "pixiewps.h" #include "utils.h" struct ie_vtag { @@ -65,14 +65,15 @@ vtag_t *find_vtag(void *vtagp, int vtagl, void *vidp, int vlen) uint8_t *vid = vidp; vtag_t *vtag = vtagp; while (0 < vtagl) { + const int len = end_ntoh16(vtag->len); if (vid && memcmp(vid, &vtag->id, 2) != 0) goto next_vtag; - if (!vlen || be16_to_h(vtag->len) == vlen) + if (!vlen || len == vlen) return vtag; next_vtag: - vtagl -= be16_to_h(vtag->len) + VTAG_SIZE; - vtag = (vtag_t *)((uint8_t *)vtag + be16_to_h(vtag->len) + VTAG_SIZE); + vtagl -= len + VTAG_SIZE; + vtag = (vtag_t *)((uint8_t *)vtag + len + VTAG_SIZE); } return NULL; } @@ -110,10 +111,10 @@ void kdf(const void *key, uint8_t *res) uint8_t *buffer = malloc(sizeof(kdf_salt) + sizeof(uint32_t) * 2); for (uint32_t i = 1; i < 4; i++) { - uint32_t be = h32_to_be(i); + uint32_t be = end_htobe32(i); memcpy(buffer, &be, sizeof(uint32_t)); memcpy(buffer + sizeof(uint32_t), kdf_salt, sizeof(kdf_salt)); - be = h32_to_be(kdk_len); + be = end_htobe32(kdk_len); memcpy(buffer + sizeof(uint32_t) + sizeof(kdf_salt), &be, sizeof(uint32_t)); hmac_sha256(key, WPS_HASH_LEN, buffer, sizeof(kdf_salt) + sizeof(uint32_t) * 2, res + j); j += WPS_HASH_LEN;