From 42ebdf66aa2effa2d0db5fd6216f58508ea40dd5 Mon Sep 17 00:00:00 2001 From: vlvo0615 Date: Wed, 11 Jul 2018 16:43:50 +0300 Subject: [PATCH] OpenSSL, Zlib and libbsd dependecies was removed --- AUTHORS | 2 +- CMakeLists.txt | 24 ++-- include/stun_crypto.h | 4 +- src/CMakeLists.txt | 26 +--- src/stun_crc32.c | 48 +++++++ src/stun_crypto.c | 60 -------- src/stun_md5.c | 254 +++++++++++++++++++++++++++++++++ src/stun_random.c | 66 +++++++++ src/stun_sha1.c | 318 ++++++++++++++++++++++++++++++++++++++++++ src/stunlib.c | 3 - test/CMakeLists.txt | 2 +- test/crypto_test.c | 37 +++++ 12 files changed, 743 insertions(+), 101 deletions(-) create mode 100644 src/stun_crc32.c delete mode 100644 src/stun_crypto.c create mode 100644 src/stun_md5.c create mode 100644 src/stun_random.c create mode 100644 src/stun_sha1.c create mode 100644 test/crypto_test.c diff --git a/AUTHORS b/AUTHORS index 49fbb8e..6b809b8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,4 +2,4 @@ # List alphabetically by surname Pål-Erik Martinsen - +Vladislav Volkov diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a14da9..ecb5baf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ include ( Uncrustify ) include ( GetGitRevisionDescription ) git_describe(VERSION --tags --dirty=-d) -string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" STUNLIBL_VERSION_MAJOR "${VERSION}") +string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" STUNLIB_VERSION_MAJOR "${VERSION}") string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" STUNLIB_VERSION_MINOR "${VERSION}") string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" STUNLIB_VERSION_PATCH "${VERSION}") string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+(.*)" "\\1" STUNLIB_VERSION_SHA1 "${VERSION}") @@ -128,20 +128,20 @@ UncrustifyTop(${uncrustify}) if (build_docs) if(NOT DOXYGEN_FOUND) message(FATAL_ERROR "Doxygen is needed to build the documentation.") - endif() - - set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) - set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + else() + set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) + set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - configure_file(${doxyfile_in} ${doxyfile} @ONLY) + configure_file(${doxyfile_in} ${doxyfile} @ONLY) - add_custom_target(doc - COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating API documentation wit1h Doxygen" - VERBATIM) + add_custom_target(doc + COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation wit1h Doxygen" + VERBATIM) - install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc) + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc) + endif() endif() diff --git a/include/stun_crypto.h b/include/stun_crypto.h index 2c7085f..594bf50 100644 --- a/include/stun_crypto.h +++ b/include/stun_crypto.h @@ -3,7 +3,7 @@ */ #include -#include +#include #ifdef __cplusplus extern "C" { @@ -13,7 +13,7 @@ unsigned char* stunlib_util_md5(const void* data, size_t len, unsigned char* md) void stunlib_util_sha1_hmac(const void* key, size_t keyLength, const void* data, size_t dataLength, void* macOut, unsigned int* macLength); -void stunlib_util_random(void* buffer, size_t size); +void stunlib_util_random(void* buffer, size_t size); // not threadsafe uint32_t stunlib_util_crc32(long crc, const uint8_t* buf, size_t len); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a5e8726..ea065f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,7 +8,10 @@ set ( stunlib_srcs stunlib.c turnclient.c stuntrace.c - stun_crypto.c + stun_random.c + stun_crc32.c + stun_md5.c + stun_sha1.c ) set (ADDITIONAL_LIBS "") @@ -25,27 +28,6 @@ install ( TARGETS stunlib set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) -find_package( ZLIB ) -if ( ZLIB_FOUND ) - include_directories( ${ZLIB_INCLUDE_DIRS} ) - list(APPEND ADDITIONAL_LIBS ${ZLIB_LIBRARIES}) - add_definitions(-DSTUNLIB_USE_ZLIB) -endif( ZLIB_FOUND ) - - -find_package( OpenSSL ) -if( OPENSSL_FOUND ) - include_directories( ${OPENSSL_INCLUDE_DIR} ) - list(APPEND ADDITIONAL_LIBS ${OPENSSL_LIBRARIES}) - add_definitions(-DSTUNLIB_USE_OPENSSL) -endif( OPENSSL_FOUND ) - -# Todo fix propper library discovery. -if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - list(APPEND ADDITIONAL_LIBS "bsd") - add_definitions(-DSTUNLIB_USE_BSD) -endif() - target_link_libraries ( stunlib PRIVATE sockaddrutil ${ADDITIONAL_LIBS}) diff --git a/src/stun_crc32.c b/src/stun_crc32.c new file mode 100644 index 0000000..7cc3faf --- /dev/null +++ b/src/stun_crc32.c @@ -0,0 +1,48 @@ +/* + * See license file + */ + +#include + +static void +make_crc_table(uint32_t crc_table[256]) +{ + uint32_t c, n, k; + + for (n = 0; n < 256u; n++) + { + c = n; + for (k = 0; k < 8; k++) + { + c = c & 1 ? 0xedb88320ul ^ (c >> 1) : c >> 1; + } + crc_table[n] = c; + } +} + +static unsigned long +update_crc(uint32_t crc, + const uint8_t* buf, + size_t len, + uint32_t crc_table[256]) +{ + uint32_t c = crc ^ 0xfffffffful; + size_t n; + + for (n = 0; n < len; n++) + { + c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + + return c ^ 0xfffffffful; +} + +uint32_t +stunlib_util_crc32(long crc, + const uint8_t* buf, + size_t len) +{ + uint32_t crc_table[256]; + make_crc_table(crc_table); + return update_crc(crc, buf, len, crc_table); +} diff --git a/src/stun_crypto.c b/src/stun_crypto.c deleted file mode 100644 index 8b01239..0000000 --- a/src/stun_crypto.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * See license file - */ - -#include "stun_crypto.h" - -#if defined(STUNLIB_USE_OPENSSL) -# include -# include -# include - -unsigned char* stunlib_util_md5(const void *data, size_t len, unsigned char *md) { - return MD5( (uint8_t*)data, len, md ); -} - -void stunlib_util_sha1_hmac(const void *key, size_t keyLength, const void *data, size_t dataLength, void *macOut, unsigned int* macLength) { - HMAC(EVP_sha1(), - key, - keyLength, - data, - dataLength, - macOut, macLength); -} - -#elif defined(__APPLE__) -# define COMMON_DIGEST_FOR_OPENSSL -# include -# include - -unsigned char* stunlib_util_md5(const void *data, size_t len, unsigned char *md) { - return CC_MD5((uint8_t*)data, (CC_LONG) len, md); -} - -void stunlib_util_sha1_hmac(const void *key, - size_t keyLength, - const void *data, - size_t dataLength, - void *macOut, - __attribute__((unused)) unsigned int* macLength) { - CCHmac(kCCHmacAlgSHA1, key, keyLength, data, dataLength, macOut); -} - -#endif // defined(__APPLE__) - -#if defined(STUNLIB_USE_BSD) -# include -#endif - -#if defined(STUNLIB_USE_BSD) || defined(__APPLE__) -void stunlib_util_random(void* buffer, size_t size) { - arc4random_buf(buffer, size); -} -#endif - -#if defined(STUNLIB_USE_ZLIB) -#include -uint32_t stunlib_util_crc32(long crc, const uint8_t* buf, size_t len) { - return crc32(crc, buf, len); -} -#endif diff --git a/src/stun_md5.c b/src/stun_md5.c new file mode 100644 index 0000000..0f4b20e --- /dev/null +++ b/src/stun_md5.c @@ -0,0 +1,254 @@ +/* + * See license file + */ + +#include +#include + +typedef struct +{ + uint32_t state[4]; + uint32_t count[2]; + uint8_t buffer[64]; +} MD5Ctx; + +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + +static void +MD5Encode(unsigned char * output, + uint32_t const* input, + uint32_t len) +{ + uint32_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +static void +MD5Decode(uint32_t* output, + unsigned char const* input, + uint32_t len) +{ + uint32_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[i] = ((uint32_t)input[j]) + | (((uint32_t)input[j + 1]) << 8) + | (((uint32_t)input[j + 2]) << 16) + | (((uint32_t)input[j + 3]) << 24); + } +} + +static void +MD5Transform(uint32_t state[4], + unsigned char const block[64]) +{ + uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + MD5Decode(x, block, 64); + + static const uint8_t S11 = 7; + static const uint8_t S12 = 12; + static const uint8_t S13 = 17; + static const uint8_t S14 = 22; + static const uint8_t S21 = 5; + static const uint8_t S22 = 9; + static const uint8_t S23 = 14; + static const uint8_t S24 = 20; + static const uint8_t S31 = 4; + static const uint8_t S32 = 11; + static const uint8_t S33 = 16; + static const uint8_t S34 = 23; + static const uint8_t S41 = 6; + static const uint8_t S42 = 10; + static const uint8_t S43 = 15; + static const uint8_t S44 = 21; + + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x02441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x04881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + memset (x, 0, sizeof x); +} + +static void +MD5Init(MD5Ctx *context) +{ + context->count[0] = context->count[1] = 0; + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +void +MD5Update (MD5Ctx * context, + unsigned char const * input, + unsigned int inputLen) +{ + unsigned int i, index, partLen; + + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + if ((context->count[0] += ((uint32_t)inputLen << 3)) < ((uint32_t)inputLen << 3)) + context->count[1]++; + + context->count[1] += ((uint32_t)inputLen >> 29); + + partLen = 64 - index; + + if (inputLen >= partLen) { + memcpy(&context->buffer[index], input, partLen); + + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + memcpy(&context->buffer[index], &input[i], inputLen - i); +} + +void +MD5Final(unsigned char digest[16], + MD5Ctx * context) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + MD5Encode(bits, context->count, 8); + + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update(context, PADDING, padLen); + + MD5Update(context, bits, 8); + + MD5Encode(digest, context->state, 16); + + memset(context, 0, sizeof(*context)); +} + +unsigned char* +stunlib_util_md5(const void* data, + size_t len, + unsigned char* md) +{ + MD5Ctx context; + MD5Init(&context); + MD5Update(&context, (unsigned char const *)data, (unsigned int)len); + MD5Final(md, &context); + return md; +} diff --git a/src/stun_random.c b/src/stun_random.c new file mode 100644 index 0000000..d8b34a5 --- /dev/null +++ b/src/stun_random.c @@ -0,0 +1,66 @@ +/* + * See license file + */ + +#include "stun_crypto.h" +#include +#include + +/* + * Permuted congruential generator implementation: PCG-XSH-RR + */ + +static uint64_t state = 0; +static uint64_t const multiplier = 6364136223846793005u; +static uint64_t const increment = 1442695040888963407u; +static int init = 0; + +static uint32_t +rotate32(uint32_t x, + unsigned r) +{ + return x >> r | x << (-r & 31); +} + +static uint32_t +pcg32() +{ + uint64_t x = state; + unsigned count = (unsigned)(x >> 59); // 59 = 64 - 5 + state = x * multiplier + increment; + x ^= x >> 18; // 18 = (64 - 27)/2 + return rotate32((uint32_t)(x >> 27), count); // 27 = 32 - 5 +} + +static void +pcg32_init(uint64_t seed) +{ + state = seed + increment; + (void)pcg32(); + init = 1; +} + +void +stunlib_util_random(void* buffer, + size_t size) +{ + if (!init) + pcg32_init(time(0)); + + size_t i; + + for(i = 0; i < size / sizeof(uint32_t); ++i) + { + uint32_t *p = ((uint32_t *)buffer) + i; + *p = pcg32(); + } + + uint32_t const n = size % sizeof(uint32_t); + + if (n) + { + uint32_t *p = ((uint32_t *)buffer) + i; + uint32_t const k = pcg32(); + memcpy(p, &k, n); + } +} diff --git a/src/stun_sha1.c b/src/stun_sha1.c new file mode 100644 index 0000000..8deaf83 --- /dev/null +++ b/src/stun_sha1.c @@ -0,0 +1,318 @@ +/* + * See license file + */ + +#include +#include + +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; + +#define SHA1HashSize 20 + +typedef struct +{ + uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + int_least16_t Message_Block_Index; /* Index into message block array */ + uint8_t Message_Block[64]; /* 512-bit message blocks */ + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corrupted? */ +} SHA1Context; + +#define SHA1CircularShift(bits,word) (((word) << (bits)) | ((word) >> (32-(bits)))) + +static void +SHA1ProcessMessageBlock(SHA1Context *context) +{ + /* Constants defined in SHA-1 */ + static const uint32_t K[] = { 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = context->Message_Block[t * 4] << 24; + W[t] |= context->Message_Block[t * 4 + 1] << 16; + W[t] |= context->Message_Block[t * 4 + 2] << 8; + W[t] |= context->Message_Block[t * 4 + 3]; + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5, A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} + +static void +SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = context->Length_High >> 24; + context->Message_Block[57] = context->Length_High >> 16; + context->Message_Block[58] = context->Length_High >> 8; + context->Message_Block[59] = context->Length_High; + context->Message_Block[60] = context->Length_Low >> 24; + context->Message_Block[61] = context->Length_Low >> 16; + context->Message_Block[62] = context->Length_Low >> 8; + context->Message_Block[63] = context->Length_Low; + + SHA1ProcessMessageBlock(context); +} + +static int +SHA1Reset(SHA1Context *context) +{ + if (!context) + return shaNull; + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +static int +SHA1Result(SHA1Context* context, + uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if (!context || !Message_Digest) + return shaNull; + + if (context->Corrupted) + return context->Corrupted; + + if (!context->Computed) + { + SHA1PadMessage(context); + for(i=0; i<64; ++i) + { + /* message may be sensitive, clear it out */ + context->Message_Block[i] = 0; + } + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; + } + + for(i = 0; i < SHA1HashSize; ++i) + { + Message_Digest[i] = context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ); + } + + return shaSuccess; +} + +static int +SHA1Input(SHA1Context* context, + const uint8_t* message_array, + unsigned length) +{ + if (!length) + return shaSuccess; + + if (!context || !message_array) + return shaNull; + + if (context->Computed) + { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF); + + context->Length_Low += 8; + if (context->Length_Low == 0) + { + context->Length_High++; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } + + return shaSuccess; +} + +void +stunlib_util_sha1_hmac(const void* key, + size_t keyLength, + const void* data, + size_t dataLength, + void* macOut, + unsigned int* macLength) { + + SHA1Context context; + + uint8_t k_ipad[65] = { 0 }; /* inner padding-key XORd with ipad */ + uint8_t k_opad[65] = { 0 }; /* outer padding-key XORd with opad */ + + uint8_t tk[SHA1HashSize]; + + int i; + + if (keyLength > 64) + { + SHA1Context tctx; + + SHA1Reset(&tctx); + SHA1Input(&tctx, (const uint8_t *)key, (unsigned)keyLength); + SHA1Result(&tctx, tk); + + key = tk; + keyLength = SHA1HashSize; + } + + memcpy(k_ipad, key, keyLength); + memcpy(k_opad, key, keyLength); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + SHA1Reset(&context); /* init context for 1st pass */ + SHA1Input(&context, k_ipad, 64); /* start with inner pad */ + SHA1Input(&context, data, dataLength); /* then text of datagram */ + SHA1Result(&context, macOut); + + SHA1Reset(&context); /* init context for 2nd pass */ + SHA1Input(&context, k_opad, 64); /* start with outer pad */ + SHA1Input(&context, macOut, SHA1HashSize); /* then results of 1st hash */ + SHA1Result(&context, macOut); + + *macLength = SHA1HashSize; +} diff --git a/src/stunlib.c b/src/stunlib.c index b9684c8..cb37997 100644 --- a/src/stunlib.c +++ b/src/stunlib.c @@ -3,9 +3,6 @@ */ #include "stunlib.h" #include "stun_crypto.h" - -#include - #include #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8fbf807..991616f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,7 +20,7 @@ sa_test ( turnmessage ) sa_test ( stunserver ) sa_test ( turnclient ) sa_test ( stuntrace ) - +sa_test ( crypto ) include ( CTest ) diff --git a/test/crypto_test.c b/test/crypto_test.c new file mode 100644 index 0000000..84600eb --- /dev/null +++ b/test/crypto_test.c @@ -0,0 +1,37 @@ +#include +#include +#include + +#include "test_utils.h" +#include "stun_crypto.h" + +static const char lazyDogString[] = "The quick brown fox jumps over the lazy dog"; + +CTEST(crypto, Sha1_Hmac) +{ + unsigned char macOut[20] = { 0 }; + unsigned int macLength = 0; + const unsigned char macResult0[] = { 0xfb, 0xdb, 0x1d, 0x1b, 0x18, 0xaa, 0x6c, 0x08, 0x32, 0x4b, 0x7d, 0x64, 0xb7, 0x1f, 0xb7, 0x63, 0x70, 0x69, 0x0e, 0x1d }; + const unsigned char macResult1[] = { 0xde, 0x7c, 0x9b, 0x85, 0xb8, 0xb7, 0x8a, 0xa6, 0xbc, 0x8a, 0x7a, 0x36, 0xf7, 0x0a, 0x90, 0x70, 0x1c, 0x9d, 0xb4, 0xd9 }; + + stunlib_util_sha1_hmac("", 0, "", 0, macOut, &macLength); + ASSERT_TRUE(memcmp(macResult0, macOut, sizeof macOut) == 0); + + stunlib_util_sha1_hmac("key", 3, lazyDogString, sizeof lazyDogString - 1, macOut, &macLength); + ASSERT_TRUE(memcmp(macResult1, macOut, sizeof macOut) == 0); +} + +CTEST(crypto, MD5) +{ + unsigned char md5[16]; + const unsigned char md5Result0[] = { 0x9e, 0x10, 0x7d, 0x9d, 0x37, 0x2b, 0xb6, 0x82, 0x6b, 0xd8, 0x1d, 0x35, 0x42, 0xa4, 0x19, 0xd6 }; + + stunlib_util_md5(lazyDogString, sizeof lazyDogString - 1, md5); + ASSERT_TRUE(memcmp(md5Result0, md5, sizeof md5) == 0); +} + +CTEST(crypto, CRC32) +{ + uint32_t const crc32 = stunlib_util_crc32(0, (const uint8_t*)lazyDogString, sizeof lazyDogString - 1); + ASSERT_TRUE(0x414fa339 == crc32); +}