diff --git a/src/checksum.c b/src/checksum.c index 22d1a7a6..6180d312 100644 --- a/src/checksum.c +++ b/src/checksum.c @@ -1,7 +1,8 @@ /* * Rufus: The Reliable USB Formatting Utility - * Message-Digest algorithms (md5sum, sha1sum, sha256sum) + * Message-Digest algorithms (md5sum, sha1sum, sha256sum, sha512sum) * Copyright © 1998-2001 Free Software Foundation, Inc. + * Copyright © 2004-2019 Tom St Denis * Copyright © 2004 g10 Code GmbH * Copyright © 2002-2015 Wei Dai & Igor Pavlov * Copyright © 2015-2020 Pete Batard @@ -25,6 +26,8 @@ * * SHA-256 taken from 7-zip's Sha256.c, itself based on Crypto++ - Public Domain * + * SHA-512 modified from LibTomCrypt - Public Domain + * * MD5 code from various public domain sources sharing the following * copyright declaration: * @@ -44,6 +47,12 @@ * will fill a supplied 16-byte array with the digest. */ + /* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */ +#ifdef _CRTDBG_MAP_ALLOC +#include +#include +#endif + #include #include #include @@ -67,25 +76,35 @@ #define MD5_BLOCKSIZE 64 #define SHA1_BLOCKSIZE 64 #define SHA256_BLOCKSIZE 64 +#define SHA512_BLOCKSIZE 128 +#define MAX_BLOCKSIZE SHA512_BLOCKSIZE + +/* Hashsize for each algorithm */ +#define MD5_HASHSIZE 16 +#define SHA1_HASHSIZE 20 +#define SHA256_HASHSIZE 32 +#define SHA512_HASHSIZE 64 +#define MAX_HASHSIZE SHA512_HASHSIZE /* Globals */ -char sum_str[CHECKSUM_MAX][65]; -uint32_t bufnum, sum_count[CHECKSUM_MAX] = { 16, 20, 32 }; +char sum_str[CHECKSUM_MAX][150]; +uint32_t bufnum, sum_count[CHECKSUM_MAX] = { MD5_HASHSIZE, SHA1_HASHSIZE, SHA256_HASHSIZE, SHA512_HASHSIZE }; HANDLE data_ready[CHECKSUM_MAX] = { 0 }, thread_ready[CHECKSUM_MAX] = { 0 }; DWORD read_size[2]; uint8_t ALIGNED(64) buffer[2][BUFFER_SIZE]; /* - * Rotate 32 bit integers by n bytes. + * Rotate 32 or 64 bit integers by n bytes. * Don't bother trying to hand-optimize those, as the * compiler usually does a pretty good job at that. */ #define ROL32(a,b) (((a) << (b)) | ((a) >> (32-(b)))) #define ROR32(a,b) (((a) >> (b)) | ((a) << (32-(b)))) - +#define ROL64(a,b) (((a) << (b)) | ((a) >> (64-(b)))) +#define ROR64(a,b) (((a) >> (b)) | ((a) << (64-(b)))) /* - * SHA-256 macros (use Wikipedia SHA-2 names for clarity) + * SHA-256, SHA-512 common macros (use Wikipedia SHA-2 names for clarity) */ #define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) #define Ma(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) @@ -102,13 +121,37 @@ static const uint32_t K256[64] = { 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; +/* SHA-512 constants */ +static const uint64_t K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + /* * For convenience, we use a common context for all the checksum algorithms, * which means some elements may be unused... */ typedef struct ALIGNED(64) { - uint8_t buf[64]; - uint32_t state[8]; + uint8_t buf[MAX_BLOCKSIZE]; + uint64_t state[8]; uint64_t bytecount; } SUM_CONTEXT; @@ -144,17 +187,30 @@ static void sha256_init(SUM_CONTEXT *ctx) ctx->state[7] = 0x5be0cd19; } +static void sha512_init(SUM_CONTEXT* ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->state[0] = 0x6a09e667f3bcc908ULL; + ctx->state[1] = 0xbb67ae8584caa73bULL; + ctx->state[2] = 0x3c6ef372fe94f82bULL; + ctx->state[3] = 0xa54ff53a5f1d36f1ULL; + ctx->state[4] = 0x510e527fade682d1ULL; + ctx->state[5] = 0x9b05688c2b3e6c1fULL; + ctx->state[6] = 0x1f83d9abfb41bd6bULL; + ctx->state[7] = 0x5be0cd19137e2179ULL; +} + /* Transform the message X which consists of 16 32-bit-words (SHA-1) */ static void sha1_transform(SUM_CONTEXT *ctx, const uint8_t *data) { uint32_t a, b, c, d, e, tm, x[16]; /* get values from the chaining vars */ - a = ctx->state[0]; - b = ctx->state[1]; - c = ctx->state[2]; - d = ctx->state[3]; - e = ctx->state[4]; + a = (uint32_t)ctx->state[0]; + b = (uint32_t)ctx->state[1]; + c = (uint32_t)ctx->state[2]; + d = (uint32_t)ctx->state[3]; + e = (uint32_t)ctx->state[4]; #ifdef BIG_ENDIAN_HOST memcpy(x, data, sizeof(x)); @@ -283,22 +339,22 @@ static __inline void sha256_transform(SUM_CONTEXT *ctx, const uint8_t *data) { uint32_t a, b, c, d, e, f, g, h, j, x[16]; - a = ctx->state[0]; - b = ctx->state[1]; - c = ctx->state[2]; - d = ctx->state[3]; - e = ctx->state[4]; - f = ctx->state[5]; - g = ctx->state[6]; - h = ctx->state[7]; + a = (uint32_t)ctx->state[0]; + b = (uint32_t)ctx->state[1]; + c = (uint32_t)ctx->state[2]; + d = (uint32_t)ctx->state[3]; + e = (uint32_t)ctx->state[4]; + f = (uint32_t)ctx->state[5]; + g = (uint32_t)ctx->state[6]; + h = (uint32_t)ctx->state[7]; // Nesting the ROR allows for single register compiler optimizations #define S0(x) (ROR32(ROR32(ROR32(x,9)^(x),11)^(x),2)) // Σ0 (Sigma 0) #define S1(x) (ROR32(ROR32(ROR32(x,14)^(x),5)^(x),6)) // Σ1 (Sigma 1) -#define g0(x) (ROR32(ROR32(x,11)^(x),7)^((x)>>3)) // γ0 (gamma 0) -#define g1(x) (ROR32(ROR32(x,2)^(x),17)^((x)>>10)) // γ1 (gamma 1) +#define s0(x) (ROR32(ROR32(x,11)^(x),7)^((x)>>3)) // σ0 (sigma 0) +#define s1(x) (ROR32(ROR32(x,2)^(x),17)^((x)>>10)) // σ1 (sigma 1) #define BLK0(i) (x[i]) -#define BLK2(i) (x[i] += g1(x[((i)-2)&15]) + x[((i)-7)&15] + g0(x[((i)-15)&15])) +#define BLK2(i) (x[i] += s1(x[((i)-2)&15]) + x[((i)-7)&15] + s0(x[((i)-15)&15])) #define R(a, b, c, d, e, f, g, h, i) \ h += S1(e) + Ch(e,f,g) + K256[(i)+(j)] + (j ? BLK2(i) : BLK0(i)); \ d += h; \ @@ -335,8 +391,8 @@ static __inline void sha256_transform(SUM_CONTEXT *ctx, const uint8_t *data) #undef S0 #undef S1 -#undef g0 -#undef g1 +#undef s0 +#undef s1 #undef BLK0 #undef BLK2 #undef R @@ -352,15 +408,74 @@ static __inline void sha256_transform(SUM_CONTEXT *ctx, const uint8_t *data) ctx->state[7] += h; } +/* Transform the message X which consists of 16 64-bit-words (SHA-512) */ +static __inline void sha512_transform(SUM_CONTEXT* ctx, const uint8_t* data) +{ + uint64_t a, b, c, d, e, f, g, h, W[80]; + uint32_t i; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + +// Nesting the ROR allows for single register compiler optimizations +#define S0(x) (ROR64(ROR64(ROR64(x,5)^(x),6)^(x),28)) // Σ0 (Sigma 0) +#define S1(x) (ROR64(ROR64(ROR64(x,23)^(x),4)^(x),14)) // Σ1 (Sigma 1) +#define s0(x) (ROR64(ROR64(x,7)^(x),1)^((x)>>7)) // σ0 (sigma 0) +#define s1(x) (ROR64(ROR64(x,42)^(x),19)^((x)>>6)) // σ1 (sigma 1) +#define R(a, b, c, d, e, f, g, h, i) \ + h += S1(e) + Ch(e, f, g) + K512[i] + W[i]; \ + d += h; \ + h += S0(a) + Ma(a, b, c) + + for (i = 0; i < 80; i++) { + if (i < 16) + W[i] = read_swap64(&data[8 * i]); + else + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + } + + for (i = 0; i < 80; i += 8) { + R(a, b, c, d, e, f, g, h, i); + R(h, a, b, c, d, e, f, g, i+1); + R(g, h, a, b, c, d, e, f, i+2); + R(f, g, h, a, b, c, d, e, i+3); + R(e, f, g, h, a, b, c, d, i+4); + R(d, e, f, g, h, a, b, c, i+5); + R(c, d, e, f, g, h, a, b, i+6); + R(b, c, d, e, f, g, h, a, i+7); + } + +#undef S0 +#undef S1 +#undef s0 +#undef s1 +#undef R + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + /* Transform the message X which consists of 16 32-bit-words (MD5) */ static void md5_transform(SUM_CONTEXT *ctx, const uint8_t *data) { uint32_t a, b, c, d, x[16]; - a = ctx->state[0]; - b = ctx->state[1]; - c = ctx->state[2]; - d = ctx->state[3]; + a = (uint32_t)ctx->state[0]; + b = (uint32_t)ctx->state[1]; + c = (uint32_t)ctx->state[2]; + d = (uint32_t)ctx->state[3]; #ifdef BIG_ENDIAN_HOST { @@ -535,6 +650,41 @@ static void sha256_write(SUM_CONTEXT *ctx, const uint8_t *buf, size_t len) memcpy(ctx->buf, buf, len); } +/* Update the message digest with the contents of the buffer (SHA-512) */ +static void sha512_write(SUM_CONTEXT* ctx, const uint8_t* buf, size_t len) +{ + size_t num = ctx->bytecount & (SHA512_BLOCKSIZE - 1); + + /* Update bytecount */ + ctx->bytecount += len; + + /* Handle any leading odd-sized chunks */ + if (num) { + uint8_t* p = ctx->buf + num; + + num = SHA512_BLOCKSIZE - num; + if (len < num) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, num); + sha512_transform(ctx, ctx->buf); + buf += num; + len -= num; + } + + /* Process data in blocksize chunks */ + while (len >= SHA512_BLOCKSIZE) { + PREFETCH64(buf + SHA512_BLOCKSIZE); + sha512_transform(ctx, buf); + buf += SHA512_BLOCKSIZE; + len -= SHA512_BLOCKSIZE; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->buf, buf, len); +} + /* Update the message digest with the contents of the buffer (MD5) */ static void md5_write(SUM_CONTEXT *ctx, const uint8_t *buf, size_t len) { @@ -580,7 +730,7 @@ static void sha1_final(SUM_CONTEXT *ctx) ctx->buf[pos++] = 0x80; /* Pad whatever data is left in the buffer */ - while (pos != (SHA1_BLOCKSIZE - 8)) { + while (pos != (SHA1_BLOCKSIZE - sizeof(uint64_t))) { pos &= (SHA1_BLOCKSIZE - 1); if (pos == 0) sha1_transform(ctx, ctx->buf); @@ -601,9 +751,9 @@ static void sha1_final(SUM_CONTEXT *ctx) p = ctx->buf; #ifdef BIG_ENDIAN_HOST -#define X(a) do { *(uint32_t*)p = ctx->state[a]; p += 4; } while(0) +#define X(a) do { *(uint32_t*)p = (uint32_t)ctx->state[a]; p += 4; } while(0) #else -#define X(a) do { write_swap32(p, ctx->state[a]); p += 4; } while(0); +#define X(a) do { write_swap32(p, (uint32_t)ctx->state[a]); p += 4; } while(0); #endif X(0); X(1); @@ -623,7 +773,7 @@ static void sha256_final(SUM_CONTEXT *ctx) ctx->buf[pos++] = 0x80; /* Pad whatever data is left in the buffer */ - while (pos != (SHA256_BLOCKSIZE - 8)) { + while (pos != (SHA256_BLOCKSIZE - sizeof(uint64_t))) { pos &= (SHA256_BLOCKSIZE - 1); if (pos == 0) sha256_transform(ctx, ctx->buf); @@ -644,9 +794,66 @@ static void sha256_final(SUM_CONTEXT *ctx) p = ctx->buf; #ifdef BIG_ENDIAN_HOST -#define X(a) do { *(uint32_t*)p = ctx->state[a]; p += 4; } while(0) +#define X(a) do { *(uint32_t*)p = (uint32_t)ctx->state[a]; p += 4; } while(0) #else -#define X(a) do { write_swap32(p, ctx->state[a]); p += 4; } while(0); +#define X(a) do { write_swap32(p, (uint32_t)ctx->state[a]); p += 4; } while(0); +#endif + X(0); + X(1); + X(2); + X(3); + X(4); + X(5); + X(6); + X(7); +#undef X +} + +/* Finalize the computation and write the digest in ctx->state[] (SHA-256) */ +static void sha512_final(SUM_CONTEXT* ctx) +{ + size_t pos = ((size_t)ctx->bytecount) & (SHA512_BLOCKSIZE - 1); + /* 16 EB ought to be enough for everybody... */ + uint64_t bitcount_lo = ctx->bytecount << 3; + uint64_t bitcount_hi = ctx->bytecount >> (64 - 3); + uint8_t* p; + + ctx->buf[pos++] = 0x80; + + /* Pad whatever data is left in the buffer */ + while (pos != (SHA512_BLOCKSIZE - (2 * sizeof(uint64_t)))) { + pos &= (SHA512_BLOCKSIZE - 1); + if (pos == 0) + sha512_transform(ctx, ctx->buf); + ctx->buf[pos++] = 0; + } + + /* Append to the padding the total message's length in bits and transform */ + ctx->buf[SHA512_BLOCKSIZE - 1] = (uint8_t)bitcount_lo; + ctx->buf[SHA512_BLOCKSIZE - 2] = (uint8_t)(bitcount_lo >> 8); + ctx->buf[SHA512_BLOCKSIZE - 3] = (uint8_t)(bitcount_lo >> 16); + ctx->buf[SHA512_BLOCKSIZE - 4] = (uint8_t)(bitcount_lo >> 24); + ctx->buf[SHA512_BLOCKSIZE - 5] = (uint8_t)(bitcount_lo >> 32); + ctx->buf[SHA512_BLOCKSIZE - 6] = (uint8_t)(bitcount_lo >> 40); + ctx->buf[SHA512_BLOCKSIZE - 7] = (uint8_t)(bitcount_lo >> 48); + ctx->buf[SHA512_BLOCKSIZE - 8] = (uint8_t)(bitcount_lo >> 56); + ctx->buf[SHA512_BLOCKSIZE - 9] = (uint8_t)bitcount_hi; + /* For clarity since, with a 64-bit bytecount, the following are always 0 */ + ctx->buf[SHA512_BLOCKSIZE - 10] = (uint8_t)(bitcount_hi >> 8); + ctx->buf[SHA512_BLOCKSIZE - 11] = (uint8_t)(bitcount_hi >> 16); + ctx->buf[SHA512_BLOCKSIZE - 12] = (uint8_t)(bitcount_hi >> 24); + ctx->buf[SHA512_BLOCKSIZE - 13] = (uint8_t)(bitcount_hi >> 32); + ctx->buf[SHA512_BLOCKSIZE - 14] = (uint8_t)(bitcount_hi >> 40); + ctx->buf[SHA512_BLOCKSIZE - 15] = (uint8_t)(bitcount_hi >> 48); + ctx->buf[SHA512_BLOCKSIZE - 16] = (uint8_t)(bitcount_hi >> 56); + + sha512_transform(ctx, ctx->buf); + + p = ctx->buf; +#ifdef BIG_ENDIAN_HOST +#define X(a) do { *p = ctx->state[a]; p += 8; } while(0) +#else +#define X(a) do { write_swap64(p, ctx->state[a]); p += 8; } while(0); #endif X(0); X(1); @@ -702,9 +909,9 @@ static void md5_final(SUM_CONTEXT *ctx) p = ctx->buf; #ifdef BIG_ENDIAN_HOST -#define X(a) do { write_swap32(p, ctx->state[a]); p += 4; } while(0); +#define X(a) do { write_swap32(p, (uint32_t)ctx->state[a]); p += 4; } while(0); #else -#define X(a) do { *(uint32_t*)p = ctx->state[a]; p += 4; } while(0) +#define X(a) do { *(uint32_t*)p = (uint32_t)ctx->state[a]; p += 4; } while(0) #endif X(0); X(1); @@ -724,9 +931,9 @@ static void null_final(SUM_CONTEXT *ctx) { } typedef void sum_init_t(SUM_CONTEXT *ctx); typedef void sum_write_t(SUM_CONTEXT *ctx, const uint8_t *buf, size_t len); typedef void sum_final_t(SUM_CONTEXT *ctx); -sum_init_t *sum_init[CHECKSUM_MAX] = { md5_init, sha1_init , sha256_init }; -sum_write_t *sum_write[CHECKSUM_MAX] = { md5_write, sha1_write , sha256_write }; -sum_final_t *sum_final[CHECKSUM_MAX] = { md5_final, sha1_final , sha256_final }; +sum_init_t *sum_init[CHECKSUM_MAX] = { md5_init, sha1_init , sha256_init, sha512_init }; +sum_write_t *sum_write[CHECKSUM_MAX] = { md5_write, sha1_write , sha256_write, sha512_write }; +sum_final_t *sum_final[CHECKSUM_MAX] = { md5_final, sha1_final , sha256_final, sha512_final }; // Compute an individual checksum without threading or buffering, for a single file BOOL HashFile(const unsigned type, const char* path, uint8_t* sum) @@ -855,11 +1062,12 @@ INT_PTR CALLBACK ChecksumCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM return (INT_PTR)FALSE; } -// Individual thread that computes one of MD5, SHA1 or SHA256 in parallel +// Individual thread that computes one of MD5, SHA1, SHA256 or SHA512 in parallel DWORD WINAPI IndividualSumThread(void* param) { SUM_CONTEXT sum_ctx = { {0} }; // There's a memset in sum_init, but static analyzers still bug us uint32_t i = (uint32_t)(uintptr_t)param, j; + char val[3] = { 0 }; sum_init[i](&sum_ctx); // Signal that we're ready to service requests @@ -879,8 +1087,13 @@ DWORD WINAPI IndividualSumThread(void* param) } else { sum_final[i](&sum_ctx); memset(&sum_str[i], 0, ARRAYSIZE(sum_str[i])); - for (j = 0; j < sum_count[i]; j++) - safe_sprintf(&sum_str[i][2 * j], ARRAYSIZE(sum_str[i]) - 2 * j, "%02x", sum_ctx.buf[j]); + for (j = 0; j < sum_count[i]; j++) { + val[0] = ((sum_ctx.buf[j] >> 4) < 10) ? ((sum_ctx.buf[j] >> 4) + '0') : ((sum_ctx.buf[j] >> 4) - 0xa + 'a'); + val[1] = ((sum_ctx.buf[j] & 15) < 10) ? ((sum_ctx.buf[j] & 15) + '0') : ((sum_ctx.buf[j] & 15) - 0xa + 'a'); + static_strcat(sum_str[i], val); + if (j == 31) + static_strcat(sum_str[i], "\r\n "); + } return 0; } } @@ -983,9 +1196,10 @@ DWORD WINAPI SumThread(void* param) goto out; } - uprintf(" MD5:\t %s", sum_str[0]); - uprintf(" SHA1:\t %s", sum_str[1]); + uprintf(" MD5: %s", sum_str[0]); + uprintf(" SHA1: %s", sum_str[1]); uprintf(" SHA256: %s", sum_str[2]); + uprintf(" SHA512: %s", sum_str[3]); r = 0; out: @@ -1028,3 +1242,110 @@ BOOL IsFileInDB(const char* path) return TRUE; return FALSE; } + +#if defined(_DEBUG) +/* Convert a lowercase hex string to binary. Returned value must be freed */ +uint8_t* to_bin(const char* str) +{ + size_t i, len = safe_strlen(str); + uint8_t val = 0, *ret = NULL; + + if ((len < 2) || (len % 2)) + return NULL; + ret = malloc(len / 2); + if (ret == NULL) + return NULL; + + for (i = 0; i < len; i++) { + val <<= 4; + val |= ((str[i] - '0') < 0xa) ? (str[i] - '0') : (str[i] - 'a' + 0xa); + if (i % 2) + ret[i / 2] = val; + } + + return ret; +} + +const char* test_msg = "Did you ever hear the tragedy of Darth Plagueis The Wise? " + "I thought not. It's not a story the Jedi would tell you. It's a Sith legend. " + "Darth Plagueis was a Dark Lord of the Sith, so powerful and so wise he could " + "use the Force to influence the midichlorians to create life... He had such a " + "knowledge of the dark side that he could even keep the ones he cared about " + "from dying. The dark side of the Force is a pathway to many abilities some " + "consider to be unnatural. He became so powerful... the only thing he was afraid " + "of was losing his power, which eventually, of course, he did. Unfortunately, " + "he taught his apprentice everything he knew, then his apprentice killed him " + "in his sleep. Ironic. He could save others from death, but not himself."; + +/* + * Yeah, I'm not gonna bother with binary arrays of hash values since + * they have different sizes and MSVC is an ass with initializing unions. + * Much rather copy paste from md5sum/sha#sum output from Linux and just + * convert the string. + */ +const char* test_hash[CHECKSUM_MAX][4] = { + { + "d41d8cd98f00b204e9800998ecf8427e", + "74cac558072300385f7ab4dff7465e3c", + "88c7cb90ea8c60be51e8e20875b4d912", + "e0ea372ac14a3574167543b851d4babb" + }, + { + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "a5bac908bf3e51ff0036a94d43b4f3bd2d01a75d", + "8af850c7238f320cba940299e0f4f2da66bd75f9", + "09463ec0b5917706c9cb1d6b164b2582c04018e0" + }, + { + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "62c1a97974dfe6848942794be4f2f027b5f4815e1eb76db63a30f0e290b5c1c4", + "662a80c59d2a44023d3b111b5242bb7fc0bc7e50ab3ae986df005a630dd7ddb5", + "c9b43c1058bc7f7661619e9d983fc9d31356e97f9195a2405ab972d0737b11bf" + }, + { + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", + "4913ace12f1169e5a5f524ef87ab8fc39dff0418851fbbbb1f609d3261b2b4072bd1746e6accb91bf38f3b1b3d59b0a60af5de67aab87b76c2456fde523efc1c", + "33df8a16dd624cbc4613b5ae902b722411c7e90f37dd3947c9a86e01c51ada68fcf5a0cd4ca928d7cc1ed469bb34c2ed008af069d8b28cc4512e6c8b2e7a5592", + "999b4eae14de584cce5fa5962b768beda076b06df00d384bb502c6389df8159c006a5b94d1324f47e8d7bd2efe9d8d3dc1fa1429798e49826987ab5ae7ed5c21" + }, +}; + +/* Tests the message digest aglorithms */ +int TestChecksum(void) +{ + const char* hash_name[4] = { "MD5 ", "SHA1 ", "SHA256", "SHA512" }; + int i, j, errors = 0; + uint8_t sum[MAX_HASHSIZE], *sum_expected; + size_t full_msg_len = strlen(test_msg); + char* msg = malloc(full_msg_len); + if (msg == NULL) + return -1; + + for (j = 0; j < CHECKSUM_MAX; j++) { + size_t copy_msg_len[4]; + copy_msg_len[0] = 0; + copy_msg_len[1] = 3; + // Designed to test the case where we pad into the total message length area + // For SHA-512 this is 128 - 16 = 112 bytes, for others 64 - 8 = 56 bytes + copy_msg_len[2] = SHA512_BLOCKSIZE - (SHA512_BLOCKSIZE >> 3); + copy_msg_len[3] = full_msg_len; + for (i = 0; i < 4; i++) { + memset(msg, 0, full_msg_len); + if (i != 0) + memcpy(msg, test_msg, copy_msg_len[i]); + HashBuffer(j, msg, copy_msg_len[i], sum); + sum_expected = to_bin(test_hash[j][i]); + if (memcmp(sum, sum_expected, sum_count[j]) != 0) { + uprintf("Test %s %d: FAIL", hash_name[j], i); + errors++; + } else { + uprintf("Test %s %d: PASS", hash_name[j], i); + } + free(sum_expected); + } + } + + free(msg); + return errors; +} +#endif diff --git a/src/rufus.c b/src/rufus.c index 57e4a77a..9489ad45 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -3369,7 +3369,8 @@ relaunch: // Ctrl-T => Alternate Test mode that doesn't require a full rebuild if ((ctrl_without_focus || ((GetKeyState(VK_CONTROL) & 0x8000) && (msg.message == WM_KEYDOWN))) && (msg.wParam == 'T')) { - uprintf("TEST"); + extern int TestChecksum(void); + TestChecksum(); continue; } #endif diff --git a/src/rufus.h b/src/rufus.h index c3ed725d..40ac183e 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -284,6 +284,7 @@ enum checksum_type { CHECKSUM_MD5 = 0, CHECKSUM_SHA1, CHECKSUM_SHA256, + CHECKSUM_SHA512, CHECKSUM_MAX }; diff --git a/src/rufus.rc b/src/rufus.rc index 3fecc598..d3de0b44 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.11.1683" +CAPTION "Rufus 3.11.1684" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -395,8 +395,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,11,1683,0 - PRODUCTVERSION 3,11,1683,0 + FILEVERSION 3,11,1684,0 + PRODUCTVERSION 3,11,1684,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -414,13 +414,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.11.1683" + VALUE "FileVersion", "3.11.1684" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2020 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-3.11.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.11.1683" + VALUE "ProductVersion", "3.11.1684" END END BLOCK "VarFileInfo"