- add hmac_sha1 and md5 implementations as source code
This commit is contained in:
parent
cedc44e24c
commit
84d11d3b04
|
|
@ -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$<$<CONFIG:Debug>: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$<$<CONFIG:Debug>:Debug>")
|
||||
|
|
|
|||
|
|
@ -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 <string.h>
|
||||
|
||||
/*
|
||||
* 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 <openssl/md5.h>
|
||||
#endif
|
||||
# include <openssl/md5.h>
|
||||
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef MD5_H
|
||||
#define MD5_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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
|
||||
Loading…
Reference in New Issue