rufus/src/checksum.c

1352 lines
43 KiB
C
Raw Normal View History

/*
* Rufus: The Reliable USB Formatting Utility
* 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 <pete@akeo.ie>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* SHA-1 code taken from GnuPG, as per copyrights above.
*
* 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:
*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* 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 <stdlib.h>
#include <crtdbg.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <errno.h>
#include <windowsx.h>
#include "db.h"
#include "rufus.h"
#include "missing.h"
#include "resource.h"
#include "msapi_utf8.h"
#include "localization.h"
#undef BIG_ENDIAN_HOST
#define BUFFER_SIZE (64*KB)
#define WAIT_TIME 5000
/* Blocksize for each algorithm - Must be a power of 2 */
#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][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 };
2016-03-03 14:58:49 +00:00
DWORD read_size[2];
uint8_t ALIGNED(64) buffer[2][BUFFER_SIZE];
/*
* 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, 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))))
2016-03-03 14:58:49 +00:00
/* SHA-256 constants */
static const uint32_t K256[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
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[MAX_BLOCKSIZE];
uint64_t state[8];
uint64_t bytecount;
} SUM_CONTEXT;
static void md5_init(SUM_CONTEXT *ctx)
{
memset(ctx, 0, sizeof(*ctx));
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xefcdab89;
ctx->state[2] = 0x98badcfe;
ctx->state[3] = 0x10325476;
}
static void sha1_init(SUM_CONTEXT *ctx)
{
memset(ctx, 0, sizeof(*ctx));
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xefcdab89;
ctx->state[2] = 0x98badcfe;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xc3d2e1f0;
}
static void sha256_init(SUM_CONTEXT *ctx)
{
memset(ctx, 0, sizeof(*ctx));
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
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)
{
2016-03-03 14:58:49 +00:00
uint32_t a, b, c, d, e, tm, x[16];
/* get values from the chaining vars */
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));
#else
{
unsigned k;
for (k = 0; k < 16; k += 4) {
const uint8_t *p2 = data + k * 4;
2016-03-03 14:58:49 +00:00
x[k] = read_swap32(p2);
x[k + 1] = read_swap32(p2 + 4);
x[k + 2] = read_swap32(p2 + 8);
x[k + 3] = read_swap32(p2 + 12);
}
}
#endif
#define K1 0x5a827999L
#define K2 0x6ed9eba1L
#define K3 0x8f1bbcdcL
#define K4 0xca62c1d6L
#define F1(x,y,z) ( z ^ ( x & ( y ^ z ) ) )
#define F2(x,y,z) ( x ^ y ^ z )
#define F3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) )
#define F4(x,y,z) ( x ^ y ^ z )
#define M(i) ( tm = x[i&0x0f] ^ x[(i-14)&0x0f] ^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f], (x[i&0x0f] = ROL32(tm,1)) )
#define SHA1STEP(a, b, c, d, e, f, k, m) do { e += ROL32(a, 5) + f(b, c, d) + k + m; \
b = ROL32(b, 30); } while(0)
SHA1STEP(a, b, c, d, e, F1, K1, x[0]);
SHA1STEP(e, a, b, c, d, F1, K1, x[1]);
SHA1STEP(d, e, a, b, c, F1, K1, x[2]);
SHA1STEP(c, d, e, a, b, F1, K1, x[3]);
SHA1STEP(b, c, d, e, a, F1, K1, x[4]);
SHA1STEP(a, b, c, d, e, F1, K1, x[5]);
SHA1STEP(e, a, b, c, d, F1, K1, x[6]);
SHA1STEP(d, e, a, b, c, F1, K1, x[7]);
SHA1STEP(c, d, e, a, b, F1, K1, x[8]);
SHA1STEP(b, c, d, e, a, F1, K1, x[9]);
SHA1STEP(a, b, c, d, e, F1, K1, x[10]);
SHA1STEP(e, a, b, c, d, F1, K1, x[11]);
SHA1STEP(d, e, a, b, c, F1, K1, x[12]);
SHA1STEP(c, d, e, a, b, F1, K1, x[13]);
SHA1STEP(b, c, d, e, a, F1, K1, x[14]);
SHA1STEP(a, b, c, d, e, F1, K1, x[15]);
SHA1STEP(e, a, b, c, d, F1, K1, M(16));
SHA1STEP(d, e, a, b, c, F1, K1, M(17));
SHA1STEP(c, d, e, a, b, F1, K1, M(18));
SHA1STEP(b, c, d, e, a, F1, K1, M(19));
SHA1STEP(a, b, c, d, e, F2, K2, M(20));
SHA1STEP(e, a, b, c, d, F2, K2, M(21));
SHA1STEP(d, e, a, b, c, F2, K2, M(22));
SHA1STEP(c, d, e, a, b, F2, K2, M(23));
SHA1STEP(b, c, d, e, a, F2, K2, M(24));
SHA1STEP(a, b, c, d, e, F2, K2, M(25));
SHA1STEP(e, a, b, c, d, F2, K2, M(26));
SHA1STEP(d, e, a, b, c, F2, K2, M(27));
SHA1STEP(c, d, e, a, b, F2, K2, M(28));
SHA1STEP(b, c, d, e, a, F2, K2, M(29));
SHA1STEP(a, b, c, d, e, F2, K2, M(30));
SHA1STEP(e, a, b, c, d, F2, K2, M(31));
SHA1STEP(d, e, a, b, c, F2, K2, M(32));
SHA1STEP(c, d, e, a, b, F2, K2, M(33));
SHA1STEP(b, c, d, e, a, F2, K2, M(34));
SHA1STEP(a, b, c, d, e, F2, K2, M(35));
SHA1STEP(e, a, b, c, d, F2, K2, M(36));
SHA1STEP(d, e, a, b, c, F2, K2, M(37));
SHA1STEP(c, d, e, a, b, F2, K2, M(38));
SHA1STEP(b, c, d, e, a, F2, K2, M(39));
SHA1STEP(a, b, c, d, e, F3, K3, M(40));
SHA1STEP(e, a, b, c, d, F3, K3, M(41));
SHA1STEP(d, e, a, b, c, F3, K3, M(42));
SHA1STEP(c, d, e, a, b, F3, K3, M(43));
SHA1STEP(b, c, d, e, a, F3, K3, M(44));
SHA1STEP(a, b, c, d, e, F3, K3, M(45));
SHA1STEP(e, a, b, c, d, F3, K3, M(46));
SHA1STEP(d, e, a, b, c, F3, K3, M(47));
SHA1STEP(c, d, e, a, b, F3, K3, M(48));
SHA1STEP(b, c, d, e, a, F3, K3, M(49));
SHA1STEP(a, b, c, d, e, F3, K3, M(50));
SHA1STEP(e, a, b, c, d, F3, K3, M(51));
SHA1STEP(d, e, a, b, c, F3, K3, M(52));
SHA1STEP(c, d, e, a, b, F3, K3, M(53));
SHA1STEP(b, c, d, e, a, F3, K3, M(54));
SHA1STEP(a, b, c, d, e, F3, K3, M(55));
SHA1STEP(e, a, b, c, d, F3, K3, M(56));
SHA1STEP(d, e, a, b, c, F3, K3, M(57));
SHA1STEP(c, d, e, a, b, F3, K3, M(58));
SHA1STEP(b, c, d, e, a, F3, K3, M(59));
SHA1STEP(a, b, c, d, e, F4, K4, M(60));
SHA1STEP(e, a, b, c, d, F4, K4, M(61));
SHA1STEP(d, e, a, b, c, F4, K4, M(62));
SHA1STEP(c, d, e, a, b, F4, K4, M(63));
SHA1STEP(b, c, d, e, a, F4, K4, M(64));
SHA1STEP(a, b, c, d, e, F4, K4, M(65));
SHA1STEP(e, a, b, c, d, F4, K4, M(66));
SHA1STEP(d, e, a, b, c, F4, K4, M(67));
SHA1STEP(c, d, e, a, b, F4, K4, M(68));
SHA1STEP(b, c, d, e, a, F4, K4, M(69));
SHA1STEP(a, b, c, d, e, F4, K4, M(70));
SHA1STEP(e, a, b, c, d, F4, K4, M(71));
SHA1STEP(d, e, a, b, c, F4, K4, M(72));
SHA1STEP(c, d, e, a, b, F4, K4, M(73));
SHA1STEP(b, c, d, e, a, F4, K4, M(74));
SHA1STEP(a, b, c, d, e, F4, K4, M(75));
SHA1STEP(e, a, b, c, d, F4, K4, M(76));
SHA1STEP(d, e, a, b, c, F4, K4, M(77));
SHA1STEP(c, d, e, a, b, F4, K4, M(78));
SHA1STEP(b, c, d, e, a, F4, K4, M(79));
#undef F1
#undef F2
#undef F3
#undef F4
/* Update chaining vars */
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
}
2016-03-03 14:58:49 +00:00
/* Transform the message X which consists of 16 32-bit-words (SHA-256) */
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 = (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 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] += 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; \
h += S0(a) + Ma(a, b, c)
#define RX_8(i) \
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)
#ifdef BIG_ENDIAN_HOST
memcpy(x, data, sizeof(x));
#else
{
uint32_t k;
for (k = 0; k < 16; k += 4) {
const uint8_t* p2 = data + k * 4;
2016-03-03 14:58:49 +00:00
x[k] = read_swap32(p2);
x[k + 1] = read_swap32(p2 + 4);
x[k + 2] = read_swap32(p2 + 8);
x[k + 3] = read_swap32(p2 + 12);
}
}
#endif
for (j = 0; j < 64; j += 16) {
RX_8(0);
RX_8(8);
}
#undef S0
#undef S1
#undef s0
#undef s1
#undef BLK0
#undef BLK2
#undef R
#undef RX_8
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 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 = (uint32_t)ctx->state[0];
b = (uint32_t)ctx->state[1];
c = (uint32_t)ctx->state[2];
d = (uint32_t)ctx->state[3];
2016-03-03 14:58:49 +00:00
#ifdef BIG_ENDIAN_HOST
{
uint32_t k;
for (k = 0; k < 16; k += 4) {
const uint8_t *p2 = data + k * 4;
2016-03-03 14:58:49 +00:00
x[k] = read_swap32(p2);
x[k + 1] = read_swap32(p2 + 4);
x[k + 2] = read_swap32(p2 + 8);
x[k + 3] = read_swap32(p2 + 12);
}
}
2016-03-03 14:58:49 +00:00
#else
memcpy(x, data, sizeof(x));
#endif
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
#define MD5STEP(f, w, x, y, z, data, s) do { \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ); } while(0)
MD5STEP(F1, a, b, c, d, x[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, x[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, x[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, x[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, x[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, x[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, x[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, x[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, x[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, x[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, x[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, x[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, x[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, x[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, x[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, x[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, x[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, x[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, x[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, x[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, x[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, x[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, x[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, x[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, x[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, x[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, x[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, x[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, x[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, x[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, x[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, x[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, x[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, x[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, x[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, x[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, x[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, x[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, x[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, x[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, x[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, x[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, x[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, x[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, x[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, x[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, x[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, x[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, x[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, x[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, x[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, x[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, x[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, x[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, x[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, x[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, x[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, x[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, x[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, x[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, x[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, x[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, x[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, x[9] + 0xeb86d391, 21);
#undef F1
#undef F2
#undef F3
#undef F4
/* Update chaining vars */
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
}
/* Update the message digest with the contents of the buffer (SHA-1) */
static void sha1_write(SUM_CONTEXT *ctx, const uint8_t *buf, size_t len)
{
size_t num = ctx->bytecount & (SHA1_BLOCKSIZE - 1);
/* Update bytecount */
ctx->bytecount += len;
/* Handle any leading odd-sized chunks */
if (num) {
uint8_t *p = ctx->buf + num;
num = SHA1_BLOCKSIZE - num;
if (len < num) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, num);
sha1_transform(ctx, ctx->buf);
buf += num;
len -= num;
}
/* Process data in blocksize chunks */
while (len >= SHA1_BLOCKSIZE) {
PREFETCH64(buf + SHA1_BLOCKSIZE);
sha1_transform(ctx, buf);
buf += SHA1_BLOCKSIZE;
len -= SHA1_BLOCKSIZE;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->buf, buf, len);
}
2016-03-03 14:58:49 +00:00
/* Update the message digest with the contents of the buffer (SHA-256) */
static void sha256_write(SUM_CONTEXT *ctx, const uint8_t *buf, size_t len)
{
size_t num = ctx->bytecount & (SHA256_BLOCKSIZE - 1);
/* Update bytecount */
ctx->bytecount += len;
/* Handle any leading odd-sized chunks */
if (num) {
uint8_t *p = ctx->buf + num;
num = SHA256_BLOCKSIZE - num;
if (len < num) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, num);
sha256_transform(ctx, ctx->buf);
buf += num;
len -= num;
}
/* Process data in blocksize chunks */
while (len >= SHA256_BLOCKSIZE) {
PREFETCH64(buf + SHA256_BLOCKSIZE);
sha256_transform(ctx, buf);
buf += SHA256_BLOCKSIZE;
len -= SHA256_BLOCKSIZE;
}
/* Handle any remaining bytes of data. */
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)
{
size_t num = ctx->bytecount & (MD5_BLOCKSIZE - 1);
/* Update bytecount */
ctx->bytecount += len;
/* Handle any leading odd-sized chunks */
if (num) {
uint8_t *p = ctx->buf + num;
num = MD5_BLOCKSIZE - num;
if (len < num) {
memcpy(p, buf, num);
return;
}
memcpy(p, buf, num);
md5_transform(ctx, ctx->buf);
buf += num;
len -= num;
}
/* Process data in blocksize chunks */
while (len >= MD5_BLOCKSIZE) {
PREFETCH64(buf + MD5_BLOCKSIZE);
md5_transform(ctx, buf);
buf += MD5_BLOCKSIZE;
len -= MD5_BLOCKSIZE;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->buf, buf, len);
}
2016-03-03 14:58:49 +00:00
/* Finalize the computation and write the digest in ctx->state[] (SHA-1) */
static void sha1_final(SUM_CONTEXT *ctx)
{
size_t pos = ((size_t)ctx->bytecount) & (SHA1_BLOCKSIZE - 1);
uint64_t bitcount = ctx->bytecount << 3;
uint8_t *p;
ctx->buf[pos++] = 0x80;
/* Pad whatever data is left in the buffer */
while (pos != (SHA1_BLOCKSIZE - sizeof(uint64_t))) {
pos &= (SHA1_BLOCKSIZE - 1);
if (pos == 0)
sha1_transform(ctx, ctx->buf);
ctx->buf[pos++] = 0;
}
/* Append to the padding the total message's length in bits and transform */
ctx->buf[SHA1_BLOCKSIZE - 1] = (uint8_t) bitcount;
ctx->buf[SHA1_BLOCKSIZE - 2] = (uint8_t) (bitcount >> 8);
ctx->buf[SHA1_BLOCKSIZE - 3] = (uint8_t) (bitcount >> 16);
ctx->buf[SHA1_BLOCKSIZE - 4] = (uint8_t) (bitcount >> 24);
ctx->buf[SHA1_BLOCKSIZE - 5] = (uint8_t) (bitcount >> 32);
ctx->buf[SHA1_BLOCKSIZE - 6] = (uint8_t) (bitcount >> 40);
ctx->buf[SHA1_BLOCKSIZE - 7] = (uint8_t) (bitcount >> 48);
ctx->buf[SHA1_BLOCKSIZE - 8] = (uint8_t) (bitcount >> 56);
sha1_transform(ctx, ctx->buf);
p = ctx->buf;
#ifdef BIG_ENDIAN_HOST
#define X(a) do { *(uint32_t*)p = (uint32_t)ctx->state[a]; p += 4; } while(0)
2016-03-03 14:58:49 +00:00
#else
#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);
#undef X
}
2016-03-03 14:58:49 +00:00
/* Finalize the computation and write the digest in ctx->state[] (SHA-256) */
static void sha256_final(SUM_CONTEXT *ctx)
{
size_t pos = ((size_t)ctx->bytecount) & (SHA256_BLOCKSIZE - 1);
uint64_t bitcount = ctx->bytecount << 3;
uint8_t *p;
ctx->buf[pos++] = 0x80;
2016-03-03 14:58:49 +00:00
/* Pad whatever data is left in the buffer */
while (pos != (SHA256_BLOCKSIZE - sizeof(uint64_t))) {
pos &= (SHA256_BLOCKSIZE - 1);
if (pos == 0)
sha256_transform(ctx, ctx->buf);
ctx->buf[pos++] = 0;
}
2016-03-03 14:58:49 +00:00
/* Append to the padding the total message's length in bits and transform */
ctx->buf[SHA256_BLOCKSIZE - 1] = (uint8_t) bitcount;
ctx->buf[SHA256_BLOCKSIZE - 2] = (uint8_t) (bitcount >> 8);
ctx->buf[SHA256_BLOCKSIZE - 3] = (uint8_t) (bitcount >> 16);
ctx->buf[SHA256_BLOCKSIZE - 4] = (uint8_t) (bitcount >> 24);
ctx->buf[SHA256_BLOCKSIZE - 5] = (uint8_t) (bitcount >> 32);
ctx->buf[SHA256_BLOCKSIZE - 6] = (uint8_t) (bitcount >> 40);
ctx->buf[SHA256_BLOCKSIZE - 7] = (uint8_t) (bitcount >> 48);
ctx->buf[SHA256_BLOCKSIZE - 8] = (uint8_t) (bitcount >> 56);
sha256_transform(ctx, ctx->buf);
p = ctx->buf;
#ifdef BIG_ENDIAN_HOST
#define X(a) do { *(uint32_t*)p = (uint32_t)ctx->state[a]; p += 4; } while(0)
2016-03-03 14:58:49 +00:00
#else
#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);
X(2);
X(3);
X(4);
X(5);
X(6);
X(7);
#undef X
}
2016-03-03 14:58:49 +00:00
/* Finalize the computation and write the digest in ctx->state[] (MD5) */
static void md5_final(SUM_CONTEXT *ctx)
{
size_t count = ((size_t)ctx->bytecount) & (MD5_BLOCKSIZE - 1);
uint64_t bitcount = ctx->bytecount << 3;
uint8_t *p;
/* Set the first char of padding to 0x80.
* This is safe since there is always at least one byte free
*/
p = ctx->buf + count;
*p++ = 0x80;
/* Bytes of padding needed to make blocksize */
count = (MD5_BLOCKSIZE - 1) - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to blocksize */
memset(p, 0, count);
md5_transform(ctx, ctx->buf);
/* Now fill the next block */
memset(ctx->buf, 0, MD5_BLOCKSIZE - 8);
} else {
/* Pad block to blocksize */
memset(p, 0, count - 8);
}
/* append the 64 bit count (little endian) */
ctx->buf[MD5_BLOCKSIZE - 8] = (uint8_t) bitcount;
ctx->buf[MD5_BLOCKSIZE - 7] = (uint8_t) (bitcount >> 8);
ctx->buf[MD5_BLOCKSIZE - 6] = (uint8_t) (bitcount >> 16);
ctx->buf[MD5_BLOCKSIZE - 5] = (uint8_t) (bitcount >> 24);
ctx->buf[MD5_BLOCKSIZE - 4] = (uint8_t) (bitcount >> 32);
ctx->buf[MD5_BLOCKSIZE - 3] = (uint8_t) (bitcount >> 40);
ctx->buf[MD5_BLOCKSIZE - 2] = (uint8_t) (bitcount >> 48);
ctx->buf[MD5_BLOCKSIZE - 1] = (uint8_t) (bitcount >> 56);
md5_transform(ctx, ctx->buf);
p = ctx->buf;
#ifdef BIG_ENDIAN_HOST
#define X(a) do { write_swap32(p, (uint32_t)ctx->state[a]); p += 4; } while(0);
2016-03-03 14:58:49 +00:00
#else
#define X(a) do { *(uint32_t*)p = (uint32_t)ctx->state[a]; p += 4; } while(0)
#endif
X(0);
X(1);
X(2);
X(3);
#undef X
}
//#define NULL_TEST
#ifdef NULL_TEST
// These 'null' calls are useful for testing load balancing and individual algorithm speed
static void null_init(SUM_CONTEXT *ctx) { memset(ctx, 0, sizeof(*ctx)); }
static void null_write(SUM_CONTEXT *ctx, const uint8_t *buf, size_t len) { }
static void null_final(SUM_CONTEXT *ctx) { }
#endif
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, 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)
{
BOOL r = FALSE;
SUM_CONTEXT sum_ctx = { {0} };
HANDLE h = INVALID_HANDLE_VALUE;
DWORD rs = 0;
uint64_t rb;
uint8_t buf[4096];
if ((type >= CHECKSUM_MAX) || (path == NULL) || (sum == NULL))
goto out;
h = CreateFileU(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (h == INVALID_HANDLE_VALUE) {
uprintf("Could not open file: %s", WindowsErrorString());
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_OPEN_FAILED;
goto out;
}
sum_init[type](&sum_ctx);
for (rb = 0; ; rb += rs) {
CHECK_FOR_USER_CANCEL;
if (!ReadFile(h, buf, sizeof(buf), &rs, NULL)) {
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_READ_FAULT;
uprintf(" Read error: %s", WindowsErrorString());
goto out;
}
if (rs == 0)
break;
sum_write[type](&sum_ctx, buf, (size_t)rs);
}
sum_final[type](&sum_ctx);
memcpy(sum, sum_ctx.buf, sum_count[type]);
r = TRUE;
out:
safe_closehandle(h);
return r;
}
BOOL HashBuffer(const unsigned type, const uint8_t* buf, const size_t len, uint8_t* sum)
{
BOOL r = FALSE;
SUM_CONTEXT sum_ctx = { {0} };
if ((type >= CHECKSUM_MAX) || (sum == NULL))
goto out;
sum_init[type](&sum_ctx);
sum_write[type](&sum_ctx, buf, len);
sum_final[type](&sum_ctx);
memcpy(sum, sum_ctx.buf, sum_count[type]);
r = TRUE;
out:
return r;
}
/*
* Checksum dialog callback
*/
INT_PTR CALLBACK ChecksumCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
int i, dw, dh;
RECT rc;
HFONT hFont;
HDC hDC;
switch (message) {
case WM_INITDIALOG:
apply_localization(IDD_CHECKSUM, hDlg);
hDC = GetDC(hDlg);
hFont = CreateFontA(-MulDiv(9, GetDeviceCaps(hDC, LOGPIXELSY), 72),
0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
0, 0, PROOF_QUALITY, 0, "Courier New");
safe_release_dc(hDlg, hDC);
SendDlgItemMessageA(hDlg, IDC_MD5, WM_SETFONT, (WPARAM)hFont, TRUE);
SendDlgItemMessageA(hDlg, IDC_SHA1, WM_SETFONT, (WPARAM)hFont, TRUE);
SendDlgItemMessageA(hDlg, IDC_SHA256, WM_SETFONT, (WPARAM)hFont, TRUE);
SetWindowTextA(GetDlgItem(hDlg, IDC_MD5), sum_str[0]);
SetWindowTextA(GetDlgItem(hDlg, IDC_SHA1), sum_str[1]);
SetWindowTextA(GetDlgItem(hDlg, IDC_SHA256), sum_str[2]);
// Move/Resize the controls as needed to fit our text
hDC = GetDC(GetDlgItem(hDlg, IDC_MD5));
SelectFont(hDC, hFont); // Yes, you *MUST* reapply the font to the DC, even after SetWindowText!
GetWindowRect(GetDlgItem(hDlg, IDC_MD5), &rc);
dw = rc.right - rc.left;
dh = rc.bottom - rc.top;
DrawTextU(hDC, sum_str[0], -1, &rc, DT_CALCRECT);
dw = rc.right - rc.left - dw + 12; // Ideally we'd compute the field borders from the system, but hey...
dh = rc.bottom - rc.top - dh + 6;
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SHA256), 0, 0, dw, dh, 1.0f);
GetWindowRect(GetDlgItem(hDlg, IDC_SHA1), &rc);
dw = rc.right - rc.left;
DrawTextU(hDC, sum_str[1], -1, &rc, DT_CALCRECT);
dw = rc.right - rc.left - dw + 12;
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_MD5), 0, 0, dw, 0, 1.0f);
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SHA1), 0, 0, dw, 0, 1.0f);
ResizeButtonHeight(hDlg, IDOK);
safe_release_dc(GetDlgItem(hDlg, IDC_MD5), hDC);
for (i=(int)safe_strlen(image_path); (i>0)&&(image_path[i]!='\\'); i--);
if (image_path != NULL) // VS code analysis has a false positive on this one
SetWindowTextU(hDlg, &image_path[i+1]);
// Set focus on the OK button
SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDOK), TRUE);
CenterDialog(hDlg, NULL);
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
case IDCANCEL:
reset_localization(IDD_CHECKSUM);
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
}
return (INT_PTR)FALSE;
}
// 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
2016-03-03 14:58:49 +00:00
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
if (!SetEvent(thread_ready[i]))
goto error;
// Wait for requests
while (1) {
if (WaitForSingleObject(data_ready[i], WAIT_TIME) != WAIT_OBJECT_0) {
uprintf("Failed to wait for event for checksum thread #%d: %s", i, WindowsErrorString());
return 1;
}
2016-03-03 14:58:49 +00:00
if (read_size[bufnum] != 0) {
sum_write[i](&sum_ctx, buffer[bufnum], (size_t)read_size[bufnum]);
if (!SetEvent(thread_ready[i]))
goto error;
} else {
sum_final[i](&sum_ctx);
memset(&sum_str[i], 0, ARRAYSIZE(sum_str[i]));
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;
}
}
error:
uprintf("Failed to set event for checksum thread #%d: %s", i, WindowsErrorString());
return 1;
}
DWORD WINAPI SumThread(void* param)
{
DWORD_PTR* thread_affinity = (DWORD_PTR*)param;
HANDLE sum_thread[CHECKSUM_MAX] = { NULL, NULL, NULL };
HANDLE h = INVALID_HANDLE_VALUE;
uint64_t rb;
int i, _bufnum, r = -1;
if ((image_path == NULL) || (thread_affinity == NULL))
ExitThread(r);
uprintf("\r\nComputing checksum for '%s'...", image_path);
if (thread_affinity[0] != 0)
// Use the first affinity mask, as our read thread is the least
// CPU intensive (mostly waits on disk I/O or on the other threads)
// whereas the OS is likely to requisition the first Core, which
// is usually in this first mask, for other tasks.
SetThreadAffinityMask(GetCurrentThread(), thread_affinity[0]);
for (i = 0; i < CHECKSUM_MAX; i++) {
// NB: Can't use a single manual-reset event for data_ready as we
// wouldn't be able to ensure the event is reset before the thread
// gets into its next wait loop
data_ready[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
thread_ready[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
if ((data_ready[i] == NULL) || (thread_ready[i] == NULL)) {
uprintf("Unable to create checksum thread event: %s", WindowsErrorString());
goto out;
}
sum_thread[i] = CreateThread(NULL, 0, IndividualSumThread, (LPVOID)(uintptr_t)i, 0, NULL);
if (sum_thread[i] == NULL) {
uprintf("Unable to start checksum thread #%d", i);
goto out;
}
if (thread_affinity[i+1] != 0)
SetThreadAffinityMask(sum_thread[i], thread_affinity[i+1]);
}
h = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (h == INVALID_HANDLE_VALUE) {
uprintf("Could not open file: %s", WindowsErrorString());
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_OPEN_FAILED;
goto out;
}
bufnum = 0;
_bufnum = 0;
2016-03-03 14:58:49 +00:00
read_size[0] = 1; // Don't trigger the first loop break
UpdateProgressWithInfoInit(hMainDialog, FALSE);
2016-03-03 14:58:49 +00:00
for (rb = 0; ;rb += read_size[_bufnum]) {
// Update the progress and check for cancel
UpdateProgressWithInfo(OP_NOOP_WITH_TASKBAR, MSG_271, rb, img_report.image_size);
CHECK_FOR_USER_CANCEL;
// Signal the threads that we have data to process
if (rb != 0) {
bufnum = _bufnum;
// Toggle the read buffer
_bufnum = (bufnum + 1) % 2;
// Signal the waiting threads
for (i = 0; i < CHECKSUM_MAX; i++) {
if (!SetEvent(data_ready[i])) {
uprintf("Could not signal checksum thread %d: %s", i, WindowsErrorString());
goto out;
}
}
}
// Break the loop when data has been exhausted
2016-03-03 14:58:49 +00:00
if (read_size[bufnum] == 0)
break;
// Read data (double buffered)
2016-03-03 14:58:49 +00:00
if (!ReadFile(h, buffer[_bufnum], BUFFER_SIZE, &read_size[_bufnum], NULL)) {
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_READ_FAULT;
uprintf("Read error: %s", WindowsErrorString());
goto out;
}
// Wait for the thread to signal they are ready to process data
if (WaitForMultipleObjects(CHECKSUM_MAX, thread_ready, TRUE, WAIT_TIME) != WAIT_OBJECT_0) {
uprintf("Checksum threads failed to signal: %s", WindowsErrorString());
goto out;
}
}
2016-03-03 14:58:49 +00:00
// Our last event with read_size=0 signaled the threads to exit - wait for that to happen
if (WaitForMultipleObjects(CHECKSUM_MAX, sum_thread, TRUE, WAIT_TIME) != WAIT_OBJECT_0) {
uprintf("Checksum threads did not finalize: %s", WindowsErrorString());
goto out;
}
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:
for (i = 0; i < CHECKSUM_MAX; i++) {
if (sum_thread[i] != NULL)
TerminateThread(sum_thread[i], 1);
safe_closehandle(data_ready[i]);
safe_closehandle(thread_ready[i]);
}
safe_closehandle(h);
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
if (r == 0)
MyDialogBox(hMainInstance, IDD_CHECKSUM, hMainDialog, ChecksumCallback);
ExitThread(r);
}
/*
* The following 2 calls are used to check whether a buffer/file is in our hash DB
*/
BOOL IsBufferInDB(const unsigned char* buf, const size_t len)
{
int i;
uint8_t sum[32];
if (!HashBuffer(CHECKSUM_SHA256, buf, len, sum))
return FALSE;
for (i = 0; i < ARRAYSIZE(sha256db); i += 32)
if (memcmp(sum, &sha256db[i], 32) == 0)
return TRUE;
return FALSE;
}
BOOL IsFileInDB(const char* path)
{
int i;
uint8_t sum[32];
if (!HashFile(CHECKSUM_SHA256, path, sum))
return FALSE;
for (i = 0; i < ARRAYSIZE(sha256db); i += 32)
if (memcmp(sum, &sha256db[i], 32) == 0)
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