diff --git a/src/libs/ice/CMakeLists.txt b/src/libs/ice/CMakeLists.txt index 7697e7c4..5bc4d4e2 100644 --- a/src/libs/ice/CMakeLists.txt +++ b/src/libs/ice/CMakeLists.txt @@ -32,21 +32,18 @@ set (ICE_STACK_SOURCES ICEAddress.cpp ICEStunTransaction.cpp ICESync.cpp ICETime.cpp - ICETransactionList.cpp) - - -#if (ANDROID_ABI) -# set (ICE_STACK_SOURCES ${ICE_STACK_SOURCES} android-ifaddrs/android-ifaddrs.h android-ifaddrs/android-ifaddrs.c) -#endif() + ICETransactionList.cpp + hmac_sha1_impl.h + hmac_sha1_impl.c + md5_impl.h + md5_impl.c +) +set (ICE_DEFINES -D_WINSOCK_DEPRECATED_NO_WARNINGS) if (TARGET_MUSL) - add_definitions(-DTARGET_MUSL) + set(ICE_DEFINES ${ICE_DEFINES} -DTARGET_MUSL) endif() -add_definitions(-DUSE_NATIVE_SMARTPTR -D_WINSOCK_DEPRECATED_NO_WARNINGS -DUSE_OPENSSL) - add_library(ice_stack ${ICE_STACK_SOURCES}) -set_property(TARGET ice_stack PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") -if (TARGET_LINUX) - # target_link_libraries(ice_stack PUBLIC ssl crypto) -endif() +target_compile_definitions(ice_stack PRIVATE ${ICE_DEFINES}) +set_target_properties(ice_stack PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") diff --git a/src/libs/ice/ICEMD5.cpp b/src/libs/ice/ICEMD5.cpp index 8a1f4bc1..837d480f 100644 --- a/src/libs/ice/ICEMD5.cpp +++ b/src/libs/ice/ICEMD5.cpp @@ -8,7 +8,6 @@ using namespace ice; #ifdef USE_CRYPTOPP - #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 #include "../CryptoPP/md5.h" using namespace CryptoPP; @@ -22,284 +21,26 @@ void ice::md5Bin(const void* inputData, size_t inputSize, void* digest) } #elif defined(USE_OPENSSL) - -#ifdef USE_FIPS -typedef unsigned int MD5_u32plus; - -typedef struct { - MD5_u32plus lo, hi; - MD5_u32plus a, b, c, d; - unsigned char buffer[64]; - MD5_u32plus block[16]; -} MD5_CTX; - -#include - -/* - * The basic MD5 functions. - * - * F and G are optimized compared to their RFC 1321 definitions for - * architectures that lack an AND-NOT instruction, just like in Colin Plumb's - * implementation. - */ -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | ~(z))) - -/* - * The MD5 transformation for all four rounds. - */ -#define STEP(f, a, b, c, d, x, t, s) \ -(a) += f((b), (c), (d)) + (x) + (t); \ -(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ -(a) += (b); - -/* - * SET reads 4 input bytes in little-endian byte order and stores them - * in a properly aligned word in host byte order. - * - * The check for little-endian architectures that tolerate unaligned - * memory accesses is just an optimization. Nothing will break if it - * doesn't work. - */ -#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) -#define SET(n) \ -(*(MD5_u32plus *)&ptr[(n) * 4]) -#define GET(n) \ -SET(n) -#else -#define SET(n) \ -(ctx->block[(n)] = \ -(MD5_u32plus)ptr[(n) * 4] | \ -((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ -((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ -((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) -#define GET(n) \ -(ctx->block[(n)]) -#endif - -/* - * This processes one or more 64-byte data blocks, but does NOT update - * the bit counters. There are no alignment requirements. - */ -static void *body(MD5_CTX *ctx, void *data, unsigned long size) -{ - unsigned char *ptr; - MD5_u32plus a, b, c, d; - MD5_u32plus saved_a, saved_b, saved_c, saved_d; - - ptr = (unsigned char*)data; - - a = ctx->a; - b = ctx->b; - c = ctx->c; - d = ctx->d; - - do { - saved_a = a; - saved_b = b; - saved_c = c; - saved_d = d; - - /* Round 1 */ - STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) - STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) - STEP(F, c, d, a, b, SET(2), 0x242070db, 17) - STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) - STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) - STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) - STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) - STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) - STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) - STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) - STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) - STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) - STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) - STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) - STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) - STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) - - /* Round 2 */ - STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) - STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) - STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) - STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) - STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) - STEP(G, d, a, b, c, GET(10), 0x02441453, 9) - STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) - STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) - STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) - STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) - STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) - STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) - STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) - STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) - STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) - STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) - - /* Round 3 */ - STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) - STEP(H, d, a, b, c, GET(8), 0x8771f681, 11) - STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) - STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23) - STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) - STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11) - STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) - STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23) - STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) - STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11) - STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) - STEP(H, b, c, d, a, GET(6), 0x04881d05, 23) - STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) - STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11) - STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) - STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23) - - /* Round 4 */ - STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) - STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) - STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) - STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) - STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) - STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) - STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) - STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) - STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) - STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) - STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) - STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) - STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) - STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) - STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) - STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) - - a += saved_a; - b += saved_b; - c += saved_c; - d += saved_d; - - ptr += 64; - } while (size -= 64); - - ctx->a = a; - ctx->b = b; - ctx->c = c; - ctx->d = d; - - return ptr; -} - -void MD5_Init(MD5_CTX *ctx) -{ - ctx->a = 0x67452301; - ctx->b = 0xefcdab89; - ctx->c = 0x98badcfe; - ctx->d = 0x10325476; - - ctx->lo = 0; - ctx->hi = 0; -} - -void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size) -{ - MD5_u32plus saved_lo; - unsigned long used, free; - - saved_lo = ctx->lo; - if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) - ctx->hi++; - ctx->hi += size >> 29; - - used = saved_lo & 0x3f; - - if (used) { - free = 64 - used; - - if (size < free) { - memcpy(&ctx->buffer[used], data, size); - return; - } - - memcpy(&ctx->buffer[used], data, free); - data = (unsigned char *)data + free; - size -= free; - body(ctx, ctx->buffer, 64); - } - - if (size >= 64) { - data = body(ctx, data, size & ~(unsigned long)0x3f); - size &= 0x3f; - } - - memcpy(ctx->buffer, data, size); -} - -void MD5_Final(unsigned char *result, MD5_CTX *ctx) -{ - unsigned long used, free; - - used = ctx->lo & 0x3f; - - ctx->buffer[used++] = 0x80; - - free = 64 - used; - - if (free < 8) { - memset(&ctx->buffer[used], 0, free); - body(ctx, ctx->buffer, 64); - used = 0; - free = 64; - } - - memset(&ctx->buffer[used], 0, free - 8); - - ctx->lo <<= 3; - ctx->buffer[56] = ctx->lo; - ctx->buffer[57] = ctx->lo >> 8; - ctx->buffer[58] = ctx->lo >> 16; - ctx->buffer[59] = ctx->lo >> 24; - ctx->buffer[60] = ctx->hi; - ctx->buffer[61] = ctx->hi >> 8; - ctx->buffer[62] = ctx->hi >> 16; - ctx->buffer[63] = ctx->hi >> 24; - - body(ctx, ctx->buffer, 64); - - result[0] = ctx->a; - result[1] = ctx->a >> 8; - result[2] = ctx->a >> 16; - result[3] = ctx->a >> 24; - result[4] = ctx->b; - result[5] = ctx->b >> 8; - result[6] = ctx->b >> 16; - result[7] = ctx->b >> 24; - result[8] = ctx->c; - result[9] = ctx->c >> 8; - result[10] = ctx->c >> 16; - result[11] = ctx->c >> 24; - result[12] = ctx->d; - result[13] = ctx->d >> 8; - result[14] = ctx->d >> 16; - result[15] = ctx->d >> 24; - - memset(ctx, 0, sizeof(*ctx)); -} - -#else -#include -#endif +# include void ice::md5Bin(const void* inputData, size_t inputSize, void* digest) { MD5_CTX md5; MD5_Init(&md5); -#ifdef USE_FIPS MD5_Update(&md5, (void*)inputData, inputSize); -#else - MD5_Update(&md5, (const unsigned char*)inputData, inputSize); -#endif MD5_Final((unsigned char*)digest, &md5); } +#else +#include "md5_impl.h" +// Use own MD5 implementation +void ice::md5Bin(const void* inputData, size_t inputSize, void* digest) +{ + MD5Context ctx; + md5Init(&ctx); + md5Update(&ctx, (const uint8_t*)inputData, inputSize); + md5Finalize(&ctx); + memcpy(digest, ctx.digest, sizeof(ctx.digest)); +} #endif + diff --git a/src/libs/ice/ICESHA1.cpp b/src/libs/ice/ICESHA1.cpp index cf625465..b112f434 100644 --- a/src/libs/ice/ICESHA1.cpp +++ b/src/libs/ice/ICESHA1.cpp @@ -28,4 +28,11 @@ void hmacSha1Digest(const void* inputData, size_t inputSize, void* outputData, c HMAC(EVP_sha1(), key, keySize, (const unsigned char*)inputData, inputSize, (unsigned char*)outputData, &outputSize); } -#endif \ No newline at end of file +#else + +#include "hmac_sha1_impl.h" +void hmacSha1Digest(const void* inputData, size_t inputSize, void* outputData, const void* key, size_t keySize) +{ + hmac_sha1((const uint8_t*)key, keySize, (const uint8_t*)inputData, inputSize, (uint8_t*)outputData); +} +#endif diff --git a/src/libs/ice/hmac_sha1_impl.c b/src/libs/ice/hmac_sha1_impl.c new file mode 100644 index 00000000..5fb34bd2 --- /dev/null +++ b/src/libs/ice/hmac_sha1_impl.c @@ -0,0 +1,561 @@ +/* + * sha1.c + * + * Description: + * This file implements the Secure Hashing Algorithm 1 as + * defined in FIPS PUB 180-1 published April 17, 1995. + * + * The SHA-1, produces a 160-bit message digest for a given + * data stream. It should take about 2**n steps to find a + * message with the same digest as a given message and + * 2**(n/2) to find any two messages with the same digest, + * when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated + * for messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is + * a multiple of the size of an 8-bit character. + * + */ + +#include "hmac_sha1_impl.h" + +/* Local Function Prototyptes */ +static void _pad_block(struct sha1*); +static void _process_block(struct sha1*); + +/* SHA1 circular left shift */ +static uint32_t _circular_shift(const uint32_t nbits, const uint32_t word) +{ + return ((word << nbits) | (word >> (32 - nbits))); +} + +/* + * sha1_reset + * + * Description: + * This function will initialize the SHA1-context in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int sha1_reset(struct sha1* context) +{ + if (context == 0) + { + 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->flags = 0; + + return shaSuccess; +} + +/* + * sha1_result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int sha1_result(struct sha1* context, uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if ( (context == 0) + || (Message_Digest == 0)) + { + return shaNull; + } + + if ((context->flags & FLAG_CORRUPTED) != 0) + { + return shaStateError; + } + + if ((context->flags & FLAG_COMPUTED) == 0) + { + _pad_block(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->flags |= FLAG_COMPUTED; + } + + for (i = 0; i < SHA1HashSize; ++i) + { + Message_Digest[i] = (context->Intermediate_Hash[i >> 2] >> (8 * (3 - (i & 0x03)))); + } + + return shaSuccess; +} + +/* + * sha1_input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int sha1_input(struct sha1* context, const uint8_t* message_array, unsigned length) +{ + if (length == 0) + { + return shaSuccess; + } + + if ( (context == 0) + || (message_array == 0)) + { + return shaNull; + } + + if ((context->flags & FLAG_COMPUTED) != 0) + { + context->flags |= FLAG_CORRUPTED; + return shaStateError; + } + + if ((context->flags & FLAG_CORRUPTED) != 0) + { + return shaStateError; + } + + while ( (length != 0) + && (context->flags == 0)) + { + context->Message_Block[context->Message_Block_Index] = (*message_array); + + context->Message_Block_Index += 1; + context->Length_Low += 8; + + if (context->Length_Low == 0) + { + context->Length_High += 1; + + if (context->Length_High == 0) + { + /* Message is too long */ + context->flags |= FLAG_CORRUPTED; + } + } + + if (context->Message_Block_Index == 64) + { + _process_block(context); + } + + message_array += 1; + length -= 1; + } + + return shaSuccess; +} + +/* + * _process_block + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + * + * + */ +#if 0 // original code +static void _process_block(struct sha1 *context) +{ + const uint32_t K[] = /* Constants defined in SHA-1 */ + { + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + uint32_t 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) + 0] << 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] << 0; + } + + for (t = 16; t < 80; ++t) + { + W[t] = _circular_shift(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 = _circular_shift(5, A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (; t < 40; ++t) + { + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (; t < 60; ++t) + { + temp = _circular_shift(5, A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (; t < 80; ++t) + { + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = _circular_shift(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; +} + +#else + +//#define METHOD2 + void _process_block(struct sha1 *context) + { + const uint32_t K[] = /* Constants defined in SHA-1 */ + { + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + uint8_t t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ +#ifdef METHOD2 + uint8_t s; + uint32_t W[16]; +#else + uint32_t W[80]; /* Word sequence */ +#endif + 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] = ((uint32_t)context->Message_Block[t * 4 + 0]) << 24; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]) << 0; + } + +#ifndef METHOD2 + for (t = 16; t < 80; ++t) + { + W[t] = _circular_shift(1, (W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16])); + } +#endif + + 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) + { +#ifdef METHOD2 + s = t & 0x0f; + if (t >= 16) + { + W[s] = _circular_shift(1, (W[(s + 13) & 0x0f] ^ W[(s + 8) & 0x0f] ^ W[(s + 2) & 0x0f] ^ W[s])); + } + temp = _circular_shift(5, A) + ((B & C) | ((~B) & D)) + E + W[s] + K[0]; +#else + temp = _circular_shift(5, A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; +#endif + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (t = 20; t < 40; ++t) + { +#ifdef METHOD2 + s = (t & 0x0f); + W[s] = _circular_shift(1, (W[(s + 13) & 0x0f] ^ W[(s + 8) & 0x0f] ^ W[(s + 2) & 0x0f] ^ W[s])); + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[s] + K[1]; +#else + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; +#endif + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (t = 40; t < 60; ++t) + { +#ifdef METHOD2 + s = (t & 0x0f); + W[s] = _circular_shift(1, (W[(s + 13) & 0x0f] ^ W[(s + 8) & 0x0f] ^ W[(s + 2) & 0x0f] ^ W[s])); + temp = _circular_shift(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[s] + K[2]; +#else + temp = _circular_shift(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; +#endif + E = D; + D = C; + C = _circular_shift(30, B); + B = A; + A = temp; + } + + for (t = 60; t < 80; ++t) + { +#ifdef METHOD2 + s = (t & 0x0f); + W[s] = _circular_shift(1, (W[(s + 13) & 0x0f] ^ W[(s + 8) & 0x0f] ^ W[(s + 2) & 0x0f] ^ W[s])); + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[s] + K[3]; +#else + temp = _circular_shift(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; +#endif + E = D; + D = C; + C = _circular_shift(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; + } + +#endif + + +/* + * _pad_block + * + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * ProcessMessageBlock: [in] + * The appropriate SHA*ProcessMessageBlock function + * Returns: + * Nothing. + * + */ +static void _pad_block(struct sha1* 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; + context->Message_Block_Index += 1; + + while (context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index] = 0; + context->Message_Block_Index += 1; + } + + _process_block(context); + + while (context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index] = 0; + context->Message_Block_Index += 1; + } + } + else + { + context->Message_Block[context->Message_Block_Index] = 0x80; + context->Message_Block_Index += 1; + + while (context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index] = 0; + context->Message_Block_Index += 1; + } + } + + /* + * Store the message length as the last 8 bytes + */ + 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 >> 0; + 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 >> 0; + + _process_block(context); +} + +/* function doing the HMAC-SHA-1 calculation */ +void hmac_sha1(const uint8_t* key, const uint32_t keysize, const uint8_t* msg, const uint32_t msgsize, uint8_t* output) +{ + struct sha1 outer, inner; + uint8_t tmp; + + if (keysize > HMAC_SHA1_BLOCK_SIZE) // if len(key) > blocksize(sha1) => key = sha1(key) + { + uint8_t new_key[HMAC_SHA1_DIGEST_SIZE]; + sha1_reset(&outer); + sha1_input(&outer, key, keysize); + sha1_result(&outer, new_key); + return hmac_sha1(new_key, HMAC_SHA1_DIGEST_SIZE, msg, msgsize, output); + } + sha1_reset(&outer); + sha1_reset(&inner); + + uint32_t i; + for (i = 0; i < keysize; ++i) + { + tmp = key[i] ^ 0x5C; + sha1_input(&outer, &tmp, 1); + tmp = key[i] ^ 0x36; + sha1_input(&inner, &tmp, 1); + } + for (; i < HMAC_SHA1_BLOCK_SIZE; ++i) + { + tmp = 0x5C; + sha1_input(&outer, &tmp, 1); + tmp = 0x36; + sha1_input(&inner, &tmp, 1); + } + + sha1_input(&inner, msg, msgsize); + sha1_result(&inner, output); + + sha1_input(&outer, output, HMAC_SHA1_DIGEST_SIZE); + sha1_result(&outer, output); +} + + + + + + + + diff --git a/src/libs/ice/hmac_sha1_impl.h b/src/libs/ice/hmac_sha1_impl.h new file mode 100644 index 00000000..3ed565ac --- /dev/null +++ b/src/libs/ice/hmac_sha1_impl.h @@ -0,0 +1,73 @@ +/* + * sha1.h + * + * Description: + * This is the header file for code which implements the Secure + * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published + * April 17, 1995. + * + * Many of the variable names in this code, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _HMAC_SHA1_H_ +#define _HMAC_SHA1_H_ + +#include + +#define SHA1HashSize 20 + +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; + +#define FLAG_COMPUTED 1 +#define FLAG_CORRUPTED 2 + +/* + * Data structure holding contextual information about the SHA-1 hash + */ +struct sha1 +{ + uint8_t Message_Block[64]; /* 512-bit message blocks */ + uint32_t Intermediate_Hash[5]; /* Message Digest */ + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + uint16_t Message_Block_Index; /* Index into message block array */ + uint8_t flags; +}; + + + +/* + * Public API + */ +int sha1_reset (struct sha1* context); +int sha1_input (struct sha1* context, const uint8_t* message_array, unsigned length); +int sha1_result(struct sha1* context, uint8_t Message_Digest[SHA1HashSize]); + + + +#define HMAC_SHA1_DIGEST_SIZE 20 +#define HMAC_SHA1_BLOCK_SIZE 64 + +/***********************************************************************' + * HMAC(K,m) : HMAC SHA1 + * @param key : secret key + * @param keysize : key-length ín bytes + * @param msg : msg to calculate HMAC over + * @param msgsize : msg-length in bytes + * @param output : writeable buffer with at least 20 bytes available + */ +void hmac_sha1(const uint8_t* key, const uint32_t keysize, const uint8_t* msg, const uint32_t msgsize, uint8_t* output); + +#endif + diff --git a/src/libs/ice/md5_impl.c b/src/libs/ice/md5_impl.c new file mode 100644 index 00000000..8e4af0a9 --- /dev/null +++ b/src/libs/ice/md5_impl.c @@ -0,0 +1,223 @@ +/* + * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm + * and modified slightly to be functionally identical but condensed into control structures. + */ + +#include "md5_impl.h" + +/* + * Constants defined by the MD5 algorithm + */ +#define A 0x67452301 +#define B 0xefcdab89 +#define C 0x98badcfe +#define D 0x10325476 + +static uint32_t S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; + +static uint32_t K[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; + +/* + * Padding used to make the size (in bits) of the input congruent to 448 mod 512 + */ +static uint8_t PADDING[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* + * Bit-manipulation functions defined by the MD5 algorithm + */ +#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)) + +/* + * Rotates a 32-bit word left by n bits + */ +uint32_t rotateLeft(uint32_t x, uint32_t n){ + return (x << n) | (x >> (32 - n)); +} + + +/* + * Initialize a context + */ +void md5Init(MD5Context *ctx){ + ctx->size = (uint64_t)0; + + ctx->buffer[0] = (uint32_t)A; + ctx->buffer[1] = (uint32_t)B; + ctx->buffer[2] = (uint32_t)C; + ctx->buffer[3] = (uint32_t)D; +} + +/* + * Add some amount of input to the context + * + * If the input fills out a block of 512 bits, apply the algorithm (md5Step) + * and save the result in the buffer. Also updates the overall size. + */ +void md5Update(MD5Context *ctx, const uint8_t *input_buffer, size_t input_len){ + uint32_t input[16]; + unsigned int offset = ctx->size % 64; + ctx->size += (uint64_t)input_len; + + // Copy each byte in input_buffer into the next space in our context input + for(unsigned int i = 0; i < input_len; ++i){ + ctx->input[offset++] = (uint8_t)*(input_buffer + i); + + // If we've filled our context input, copy it into our local array input + // then reset the offset to 0 and fill in a new buffer. + // Every time we fill out a chunk, we run it through the algorithm + // to enable some back and forth between cpu and i/o + if(offset % 64 == 0){ + for(unsigned int j = 0; j < 16; ++j){ + // Convert to little-endian + // The local variable `input` our 512-bit chunk separated into 32-bit words + // we can use in calculations + input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 | + (uint32_t)(ctx->input[(j * 4) + 2]) << 16 | + (uint32_t)(ctx->input[(j * 4) + 1]) << 8 | + (uint32_t)(ctx->input[(j * 4)]); + } + md5Step(ctx->buffer, input); + offset = 0; + } + } +} + +/* + * Pad the current input to get to 448 bytes, append the size in bits to the very end, + * and save the result of the final iteration into digest. + */ +void md5Finalize(MD5Context *ctx){ + uint32_t input[16]; + unsigned int offset = ctx->size % 64; + unsigned int padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset; + + // Fill in the padding and undo the changes to size that resulted from the update + md5Update(ctx, PADDING, padding_length); + ctx->size -= (uint64_t)padding_length; + + // Do a final update (internal to this function) + // Last two 32-bit words are the two halves of the size (converted from bytes to bits) + for(unsigned int j = 0; j < 14; ++j){ + input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 | + (uint32_t)(ctx->input[(j * 4) + 2]) << 16 | + (uint32_t)(ctx->input[(j * 4) + 1]) << 8 | + (uint32_t)(ctx->input[(j * 4)]); + } + input[14] = (uint32_t)(ctx->size * 8); + input[15] = (uint32_t)((ctx->size * 8) >> 32); + + md5Step(ctx->buffer, input); + + // Move the result into digest (convert from little-endian) + for(unsigned int i = 0; i < 4; ++i){ + ctx->digest[(i * 4) + 0] = (uint8_t)((ctx->buffer[i] & 0x000000FF)); + ctx->digest[(i * 4) + 1] = (uint8_t)((ctx->buffer[i] & 0x0000FF00) >> 8); + ctx->digest[(i * 4) + 2] = (uint8_t)((ctx->buffer[i] & 0x00FF0000) >> 16); + ctx->digest[(i * 4) + 3] = (uint8_t)((ctx->buffer[i] & 0xFF000000) >> 24); + } +} + +/* + * Step on 512 bits of input with the main MD5 algorithm. + */ +void md5Step(uint32_t *buffer, uint32_t *input){ + uint32_t AA = buffer[0]; + uint32_t BB = buffer[1]; + uint32_t CC = buffer[2]; + uint32_t DD = buffer[3]; + + uint32_t E; + + unsigned int j; + + for(unsigned int i = 0; i < 64; ++i){ + switch(i / 16){ + case 0: + E = F(BB, CC, DD); + j = i; + break; + case 1: + E = G(BB, CC, DD); + j = ((i * 5) + 1) % 16; + break; + case 2: + E = H(BB, CC, DD); + j = ((i * 3) + 5) % 16; + break; + default: + E = I(BB, CC, DD); + j = (i * 7) % 16; + break; + } + + uint32_t temp = DD; + DD = CC; + CC = BB; + BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]); + AA = temp; + } + + buffer[0] += AA; + buffer[1] += BB; + buffer[2] += CC; + buffer[3] += DD; +} + +/* + * Functions that run the algorithm on the provided input and put the digest into result. + * result should be able to store 16 bytes. + */ +void md5String(char *input, uint8_t *result){ + MD5Context ctx; + md5Init(&ctx); + md5Update(&ctx, (uint8_t *)input, strlen(input)); + md5Finalize(&ctx); + + memcpy(result, ctx.digest, 16); +} + +void md5File(FILE *file, uint8_t *result){ + char *input_buffer = malloc(1024); + size_t input_size = 0; + + MD5Context ctx; + md5Init(&ctx); + + while((input_size = fread(input_buffer, 1, 1024, file)) > 0){ + md5Update(&ctx, (uint8_t *)input_buffer, input_size); + } + + md5Finalize(&ctx); + + free(input_buffer); + + memcpy(result, ctx.digest, 16); +} diff --git a/src/libs/ice/md5_impl.h b/src/libs/ice/md5_impl.h new file mode 100644 index 00000000..63076f6b --- /dev/null +++ b/src/libs/ice/md5_impl.h @@ -0,0 +1,24 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include + +typedef struct{ + uint64_t size; // Size of input in bytes + uint32_t buffer[4]; // Current accumulation of hash + uint8_t input[64]; // Input to be used in the next step + uint8_t digest[16]; // Result of algorithm +}MD5Context; + +void md5Init(MD5Context *ctx); +void md5Update(MD5Context *ctx, const uint8_t *input, size_t input_len); +void md5Finalize(MD5Context *ctx); +void md5Step(uint32_t *buffer, uint32_t *input); + +void md5String(char *input, uint8_t *result); +void md5File(FILE *file, uint8_t *result); + +#endif