mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
df9e333f3a
* Not all md5sum.txt (e.g. Ubuntu 24.04) will reference the UEFI bootloader, so we can't rely on using that data for the bootloader extraction. * Instead, formally test for the presence of the bootloader on disk.
2371 lines
75 KiB
C
2371 lines
75 KiB
C
/*
|
||
* 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-2024 Pete Batard <pete@akeo.ie>
|
||
* Copyright © 2022 Jeffrey Walton <noloader@gmail.com>
|
||
* Copyright © 2016 Alexander Graf
|
||
*
|
||
* 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
|
||
*
|
||
* PE256 modified from u-boot's efi_image_loader.c - GPLv2.0+
|
||
*
|
||
* CPU accelerated SHA code taken from SHA-Intrinsics - 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 <assert.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <inttypes.h>
|
||
#include <errno.h>
|
||
#include <windows.h>
|
||
#include <windowsx.h>
|
||
|
||
#include "db.h"
|
||
#include "cpu.h"
|
||
#include "rufus.h"
|
||
#include "winio.h"
|
||
#include "missing.h"
|
||
#include "resource.h"
|
||
#include "msapi_utf8.h"
|
||
#include "localization.h"
|
||
|
||
/* Includes for SHA-1 and SHA-256 intrinsics */
|
||
#if defined(CPU_X86_SHA1_ACCELERATION) || defined(CPU_X86_SHA256_ACCELERATION)
|
||
#if defined(_MSC_VER)
|
||
#include <immintrin.h>
|
||
#elif defined(__GNUC__)
|
||
#include <stdint.h>
|
||
#include <x86intrin.h>
|
||
#endif
|
||
#endif
|
||
|
||
#if defined(_MSC_VER)
|
||
#define RUFUS_ENABLE_GCC_ARCH(arch)
|
||
#else
|
||
#define RUFUS_ENABLE_GCC_ARCH(arch) __attribute__ ((target (arch)))
|
||
#endif
|
||
|
||
#undef BIG_ENDIAN_HOST
|
||
|
||
#define BUFFER_SIZE (64*KB)
|
||
#define WAIT_TIME 5000
|
||
|
||
/* Number of buffers we work with */
|
||
#define NUM_BUFFERS 3 // 2 + 1 as a mere double buffered async I/O
|
||
// would modify the buffer being processed.
|
||
|
||
/* Globals */
|
||
char hash_str[HASH_MAX][150];
|
||
HANDLE data_ready[HASH_MAX] = { 0 }, thread_ready[HASH_MAX] = { 0 };
|
||
DWORD read_size[NUM_BUFFERS];
|
||
BOOL enable_extra_hashes = FALSE, validate_md5sum = FALSE;
|
||
uint8_t ALIGNED(64) buffer[NUM_BUFFERS][BUFFER_SIZE];
|
||
uint8_t* pe256ssp = NULL;
|
||
uint32_t proc_bufnum, hash_count[HASH_MAX] = { MD5_HASHSIZE, SHA1_HASHSIZE, SHA256_HASHSIZE, SHA512_HASHSIZE };
|
||
uint32_t pe256ssp_size = 0;
|
||
uint64_t md5sum_totalbytes;
|
||
StrArray modified_files = { 0 };
|
||
|
||
extern int default_thread_priority;
|
||
extern const char* efi_bootname[ARCH_MAX];
|
||
|
||
/*
|
||
* 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))))
|
||
|
||
/* 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
|
||
};
|
||
|
||
static void md5_init(HASH_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(HASH_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(HASH_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(HASH_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_cc(HASH_CONTEXT *ctx, const uint8_t *data)
|
||
{
|
||
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;
|
||
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;
|
||
}
|
||
|
||
#ifdef CPU_X86_SHA1_ACCELERATION
|
||
/*
|
||
* Transform the message X which consists of 16 32-bit-words (SHA-1)
|
||
* The code is public domain taken from https://github.com/noloader/SHA-Intrinsics.
|
||
*/
|
||
RUFUS_ENABLE_GCC_ARCH("ssse3,sse4.1,sha")
|
||
static void sha1_transform_x86(uint64_t state64[5], const uint8_t *data, size_t length)
|
||
{
|
||
__m128i ABCD, E0, E1;
|
||
__m128i MSG0, MSG1, MSG2, MSG3;
|
||
const __m128i MASK = _mm_set_epi64x(0x0001020304050607ULL, 0x08090a0b0c0d0e0fULL);
|
||
|
||
/* Rufus uses uint64_t for the state array. Pack it into uint32_t. */
|
||
uint32_t state[5] = {
|
||
(uint32_t)state64[0],
|
||
(uint32_t)state64[1],
|
||
(uint32_t)state64[2],
|
||
(uint32_t)state64[3],
|
||
(uint32_t)state64[4]
|
||
};
|
||
|
||
/* Load initial values */
|
||
ABCD = _mm_loadu_si128((const __m128i*) state);
|
||
E0 = _mm_set_epi32(state[4], 0, 0, 0);
|
||
ABCD = _mm_shuffle_epi32(ABCD, 0x1B);
|
||
|
||
while (length >= SHA1_BLOCKSIZE)
|
||
{
|
||
/* Save current state */
|
||
const __m128i ABCD_SAVE = ABCD;
|
||
const __m128i E0_SAVE = E0;
|
||
|
||
/* Rounds 0-3 */
|
||
MSG0 = _mm_loadu_si128((const __m128i*)(data + 0));
|
||
MSG0 = _mm_shuffle_epi8(MSG0, MASK);
|
||
E0 = _mm_add_epi32(E0, MSG0);
|
||
E1 = ABCD;
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0);
|
||
|
||
/* Rounds 4-7 */
|
||
MSG1 = _mm_loadu_si128((const __m128i*)(data + 16));
|
||
MSG1 = _mm_shuffle_epi8(MSG1, MASK);
|
||
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
||
E0 = ABCD;
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0);
|
||
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
||
|
||
/* Rounds 8-11 */
|
||
MSG2 = _mm_loadu_si128((const __m128i*)(data + 32));
|
||
MSG2 = _mm_shuffle_epi8(MSG2, MASK);
|
||
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
||
E1 = ABCD;
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0);
|
||
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
||
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
||
|
||
/* Rounds 12-15 */
|
||
MSG3 = _mm_loadu_si128((const __m128i*)(data + 48));
|
||
MSG3 = _mm_shuffle_epi8(MSG3, MASK);
|
||
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
||
E0 = ABCD;
|
||
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0);
|
||
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
||
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
||
|
||
/* Rounds 16-19 */
|
||
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
||
E1 = ABCD;
|
||
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0);
|
||
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
||
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
||
|
||
/* Rounds 20-23 */
|
||
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
||
E0 = ABCD;
|
||
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1);
|
||
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
||
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
||
|
||
/* Rounds 24-27 */
|
||
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
||
E1 = ABCD;
|
||
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1);
|
||
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
||
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
||
|
||
/* Rounds 28-31 */
|
||
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
||
E0 = ABCD;
|
||
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1);
|
||
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
||
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
||
|
||
/* Rounds 32-35 */
|
||
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
||
E1 = ABCD;
|
||
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1);
|
||
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
||
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
||
|
||
/* Rounds 36-39 */
|
||
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
||
E0 = ABCD;
|
||
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1);
|
||
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
||
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
||
|
||
/* Rounds 40-43 */
|
||
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
||
E1 = ABCD;
|
||
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2);
|
||
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
||
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
||
|
||
/* Rounds 44-47 */
|
||
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
||
E0 = ABCD;
|
||
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2);
|
||
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
||
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
||
|
||
/* Rounds 48-51 */
|
||
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
||
E1 = ABCD;
|
||
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2);
|
||
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
||
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
||
|
||
/* Rounds 52-55 */
|
||
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
||
E0 = ABCD;
|
||
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2);
|
||
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
||
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
||
|
||
/* Rounds 56-59 */
|
||
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
||
E1 = ABCD;
|
||
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2);
|
||
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
||
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
||
|
||
/* Rounds 60-63 */
|
||
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
||
E0 = ABCD;
|
||
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3);
|
||
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
||
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
||
|
||
/* Rounds 64-67 */
|
||
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
||
E1 = ABCD;
|
||
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3);
|
||
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
||
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
||
|
||
/* Rounds 68-71 */
|
||
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
||
E0 = ABCD;
|
||
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3);
|
||
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
||
|
||
/* Rounds 72-75 */
|
||
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
||
E1 = ABCD;
|
||
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3);
|
||
|
||
/* Rounds 76-79 */
|
||
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
||
E0 = ABCD;
|
||
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3);
|
||
|
||
/* Combine state */
|
||
E0 = _mm_sha1nexte_epu32(E0, E0_SAVE);
|
||
ABCD = _mm_add_epi32(ABCD, ABCD_SAVE);
|
||
|
||
data += 64;
|
||
length -= 64;
|
||
}
|
||
|
||
/* Save state */
|
||
ABCD = _mm_shuffle_epi32(ABCD, 0x1B);
|
||
_mm_storeu_si128((__m128i*) state, ABCD);
|
||
state[4] = _mm_extract_epi32(E0, 3);
|
||
|
||
/* Repack into uint64_t. */
|
||
state64[0] = state[0];
|
||
state64[1] = state[1];
|
||
state64[2] = state[2];
|
||
state64[3] = state[3];
|
||
state64[4] = state[4];
|
||
}
|
||
#endif /* CPU_X86_SHA1_ACCELERATION */
|
||
|
||
/* Transform the message X which consists of 16 32-bit-words (SHA-1) */
|
||
static void sha1_transform(HASH_CONTEXT *ctx, const uint8_t *data)
|
||
{
|
||
#ifdef CPU_X86_SHA1_ACCELERATION
|
||
if (cpu_has_sha1_accel)
|
||
{
|
||
/* SHA-1 acceleration using intrinsics */
|
||
sha1_transform_x86(ctx->state, data, SHA1_BLOCKSIZE);
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
/* Portable C/C++ implementation */
|
||
sha1_transform_cc(ctx, data);
|
||
}
|
||
}
|
||
|
||
/* Transform the message X which consists of 16 32-bit-words (SHA-256) */
|
||
static __inline void sha256_transform_cc(HASH_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;
|
||
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;
|
||
}
|
||
|
||
#ifdef CPU_X86_SHA256_ACCELERATION
|
||
/*
|
||
* Transform the message X which consists of 16 32-bit-words (SHA-256)
|
||
* The code is public domain taken from https://github.com/noloader/SHA-Intrinsics.
|
||
*/
|
||
RUFUS_ENABLE_GCC_ARCH("ssse3,sse4.1,sha")
|
||
static __inline void sha256_transform_x86(uint64_t state64[8], const uint8_t *data, size_t length)
|
||
{
|
||
__m128i STATE0, STATE1;
|
||
__m128i MSG, TMP;
|
||
__m128i MSG0, MSG1, MSG2, MSG3;
|
||
const __m128i MASK = _mm_set_epi64x(0x0c0d0e0f08090a0bULL, 0x0405060700010203ULL);
|
||
|
||
/* Rufus uses uint64_t for the state array. Pack it into uint32_t. */
|
||
uint32_t state[8] = {
|
||
(uint32_t)state64[0],
|
||
(uint32_t)state64[1],
|
||
(uint32_t)state64[2],
|
||
(uint32_t)state64[3],
|
||
(uint32_t)state64[4],
|
||
(uint32_t)state64[5],
|
||
(uint32_t)state64[6],
|
||
(uint32_t)state64[7]
|
||
};
|
||
|
||
/* Load initial values */
|
||
TMP = _mm_loadu_si128((const __m128i*) (state+0));
|
||
STATE1 = _mm_loadu_si128((const __m128i*) (state+4));
|
||
|
||
TMP = _mm_shuffle_epi32(TMP, 0xB1); /* CDAB */
|
||
STATE1 = _mm_shuffle_epi32(STATE1, 0x1B); /* EFGH */
|
||
STATE0 = _mm_alignr_epi8(TMP, STATE1, 8); /* ABEF */
|
||
STATE1 = _mm_blend_epi16(STATE1, TMP, 0xF0); /* CDGH */
|
||
|
||
while (length >= SHA256_BLOCKSIZE)
|
||
{
|
||
/* Save current state */
|
||
const __m128i ABEF_SAVE = STATE0;
|
||
const __m128i CDGH_SAVE = STATE1;
|
||
|
||
/* Rounds 0-3 */
|
||
MSG = _mm_loadu_si128((const __m128i*) (data+0));
|
||
MSG0 = _mm_shuffle_epi8(MSG, MASK);
|
||
MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0xE9B5DBA5B5C0FBCFULL, 0x71374491428A2F98ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
|
||
/* Rounds 4-7 */
|
||
MSG1 = _mm_loadu_si128((const __m128i*) (data+16));
|
||
MSG1 = _mm_shuffle_epi8(MSG1, MASK);
|
||
MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0xAB1C5ED5923F82A4ULL, 0x59F111F13956C25BULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG0 = _mm_sha256msg1_epu32(MSG0, MSG1);
|
||
|
||
/* Rounds 8-11 */
|
||
MSG2 = _mm_loadu_si128((const __m128i*) (data+32));
|
||
MSG2 = _mm_shuffle_epi8(MSG2, MASK);
|
||
MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0x550C7DC3243185BEULL, 0x12835B01D807AA98ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG1 = _mm_sha256msg1_epu32(MSG1, MSG2);
|
||
|
||
/* Rounds 12-15 */
|
||
MSG3 = _mm_loadu_si128((const __m128i*) (data+48));
|
||
MSG3 = _mm_shuffle_epi8(MSG3, MASK);
|
||
MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0xC19BF1749BDC06A7ULL, 0x80DEB1FE72BE5D74ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG3, MSG2, 4);
|
||
MSG0 = _mm_add_epi32(MSG0, TMP);
|
||
MSG0 = _mm_sha256msg2_epu32(MSG0, MSG3);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG2 = _mm_sha256msg1_epu32(MSG2, MSG3);
|
||
|
||
/* Rounds 16-19 */
|
||
MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0x240CA1CC0FC19DC6ULL, 0xEFBE4786E49B69C1ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG0, MSG3, 4);
|
||
MSG1 = _mm_add_epi32(MSG1, TMP);
|
||
MSG1 = _mm_sha256msg2_epu32(MSG1, MSG0);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG3 = _mm_sha256msg1_epu32(MSG3, MSG0);
|
||
|
||
/* Rounds 20-23 */
|
||
MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0x76F988DA5CB0A9DCULL, 0x4A7484AA2DE92C6FULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG1, MSG0, 4);
|
||
MSG2 = _mm_add_epi32(MSG2, TMP);
|
||
MSG2 = _mm_sha256msg2_epu32(MSG2, MSG1);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG0 = _mm_sha256msg1_epu32(MSG0, MSG1);
|
||
|
||
/* Rounds 24-27 */
|
||
MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0xBF597FC7B00327C8ULL, 0xA831C66D983E5152ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG2, MSG1, 4);
|
||
MSG3 = _mm_add_epi32(MSG3, TMP);
|
||
MSG3 = _mm_sha256msg2_epu32(MSG3, MSG2);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG1 = _mm_sha256msg1_epu32(MSG1, MSG2);
|
||
|
||
/* Rounds 28-31 */
|
||
MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0x1429296706CA6351ULL, 0xD5A79147C6E00BF3ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG3, MSG2, 4);
|
||
MSG0 = _mm_add_epi32(MSG0, TMP);
|
||
MSG0 = _mm_sha256msg2_epu32(MSG0, MSG3);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG2 = _mm_sha256msg1_epu32(MSG2, MSG3);
|
||
|
||
/* Rounds 32-35 */
|
||
MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0x53380D134D2C6DFCULL, 0x2E1B213827B70A85ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG0, MSG3, 4);
|
||
MSG1 = _mm_add_epi32(MSG1, TMP);
|
||
MSG1 = _mm_sha256msg2_epu32(MSG1, MSG0);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG3 = _mm_sha256msg1_epu32(MSG3, MSG0);
|
||
|
||
/* Rounds 36-39 */
|
||
MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0x92722C8581C2C92EULL, 0x766A0ABB650A7354ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG1, MSG0, 4);
|
||
MSG2 = _mm_add_epi32(MSG2, TMP);
|
||
MSG2 = _mm_sha256msg2_epu32(MSG2, MSG1);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG0 = _mm_sha256msg1_epu32(MSG0, MSG1);
|
||
|
||
/* Rounds 40-43 */
|
||
MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0xC76C51A3C24B8B70ULL, 0xA81A664BA2BFE8A1ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG2, MSG1, 4);
|
||
MSG3 = _mm_add_epi32(MSG3, TMP);
|
||
MSG3 = _mm_sha256msg2_epu32(MSG3, MSG2);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG1 = _mm_sha256msg1_epu32(MSG1, MSG2);
|
||
|
||
/* Rounds 44-47 */
|
||
MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0x106AA070F40E3585ULL, 0xD6990624D192E819ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG3, MSG2, 4);
|
||
MSG0 = _mm_add_epi32(MSG0, TMP);
|
||
MSG0 = _mm_sha256msg2_epu32(MSG0, MSG3);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG2 = _mm_sha256msg1_epu32(MSG2, MSG3);
|
||
|
||
/* Rounds 48-51 */
|
||
MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0x34B0BCB52748774CULL, 0x1E376C0819A4C116ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG0, MSG3, 4);
|
||
MSG1 = _mm_add_epi32(MSG1, TMP);
|
||
MSG1 = _mm_sha256msg2_epu32(MSG1, MSG0);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
MSG3 = _mm_sha256msg1_epu32(MSG3, MSG0);
|
||
|
||
/* Rounds 52-55 */
|
||
MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0x682E6FF35B9CCA4FULL, 0x4ED8AA4A391C0CB3ULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG1, MSG0, 4);
|
||
MSG2 = _mm_add_epi32(MSG2, TMP);
|
||
MSG2 = _mm_sha256msg2_epu32(MSG2, MSG1);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
|
||
/* Rounds 56-59 */
|
||
MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0x8CC7020884C87814ULL, 0x78A5636F748F82EEULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
TMP = _mm_alignr_epi8(MSG2, MSG1, 4);
|
||
MSG3 = _mm_add_epi32(MSG3, TMP);
|
||
MSG3 = _mm_sha256msg2_epu32(MSG3, MSG2);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
|
||
/* Rounds 60-63 */
|
||
MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0xC67178F2BEF9A3F7ULL, 0xA4506CEB90BEFFFAULL));
|
||
STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG);
|
||
MSG = _mm_shuffle_epi32(MSG, 0x0E);
|
||
STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG);
|
||
|
||
/* Combine state */
|
||
STATE0 = _mm_add_epi32(STATE0, ABEF_SAVE);
|
||
STATE1 = _mm_add_epi32(STATE1, CDGH_SAVE);
|
||
|
||
data += 64;
|
||
length -= 64;
|
||
}
|
||
|
||
TMP = _mm_shuffle_epi32(STATE0, 0x1B); /* FEBA */
|
||
STATE1 = _mm_shuffle_epi32(STATE1, 0xB1); /* DCHG */
|
||
STATE0 = _mm_blend_epi16(TMP, STATE1, 0xF0); /* DCBA */
|
||
STATE1 = _mm_alignr_epi8(STATE1, TMP, 8); /* ABEF */
|
||
|
||
/* Save state */
|
||
_mm_storeu_si128((__m128i*) (state+0), STATE0);
|
||
_mm_storeu_si128((__m128i*) (state+4), STATE1);
|
||
|
||
/* Repack into uint64_t. */
|
||
state64[0] = state[0];
|
||
state64[1] = state[1];
|
||
state64[2] = state[2];
|
||
state64[3] = state[3];
|
||
state64[4] = state[4];
|
||
state64[5] = state[5];
|
||
state64[6] = state[6];
|
||
state64[7] = state[7];
|
||
}
|
||
#endif /* CPU_X86_SHA256_ACCELERATION */
|
||
|
||
static __inline void sha256_transform(HASH_CONTEXT *ctx, const uint8_t *data)
|
||
{
|
||
#ifdef CPU_X86_SHA256_ACCELERATION
|
||
if (cpu_has_sha256_accel)
|
||
{
|
||
/* SHA-256 acceleration using intrinsics */
|
||
sha256_transform_x86(ctx->state, data, SHA256_BLOCKSIZE);
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
/* Portable C/C++ implementation */
|
||
sha256_transform_cc(ctx, data);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Transform the message X which consists of 16 64-bit-words (SHA-512)
|
||
* This is an algorithm that *REALLY* benefits from being executed as 64-bit
|
||
* code rather than 32-bit, as it's more than twice as fast then...
|
||
*/
|
||
static __inline void sha512_transform(HASH_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)
|
||
#ifdef BIG_ENDIAN_HOST
|
||
W[i] = *((uint64_t*)&data[8 * i]));
|
||
#else
|
||
W[i] = read_swap64(&data[8 * i]);
|
||
#endif
|
||
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(HASH_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];
|
||
|
||
#ifdef BIG_ENDIAN_HOST
|
||
{
|
||
uint32_t k;
|
||
for (k = 0; k < 16; k += 4) {
|
||
const uint8_t *p2 = data + k * 4;
|
||
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);
|
||
}
|
||
}
|
||
#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(HASH_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;
|
||
}
|
||
|
||
#ifdef CPU_X86_SHA1_ACCELERATION
|
||
if (cpu_has_sha1_accel)
|
||
{
|
||
/* Process all full blocks at once */
|
||
if (len >= SHA1_BLOCKSIZE) {
|
||
/* Calculate full blocks, in bytes */
|
||
num = (len / SHA1_BLOCKSIZE) * SHA1_BLOCKSIZE;
|
||
/* SHA-1 acceleration using intrinsics */
|
||
sha1_transform_x86(ctx->state, buf, num);
|
||
buf += num;
|
||
len -= num;
|
||
}
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
/* 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);
|
||
}
|
||
|
||
/* Update the message digest with the contents of the buffer (SHA-256) */
|
||
static void sha256_write(HASH_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;
|
||
}
|
||
|
||
#ifdef CPU_X86_SHA256_ACCELERATION
|
||
if (cpu_has_sha256_accel)
|
||
{
|
||
/* Process all full blocks at once */
|
||
if (len >= SHA256_BLOCKSIZE) {
|
||
/* Calculate full blocks, in bytes */
|
||
num = (len / SHA256_BLOCKSIZE) * SHA256_BLOCKSIZE;
|
||
/* SHA-256 acceleration using intrinsics */
|
||
sha256_transform_x86(ctx->state, buf, num);
|
||
buf += num;
|
||
len -= num;
|
||
}
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
/* 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(HASH_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(HASH_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);
|
||
}
|
||
|
||
/* Finalize the computation and write the digest in ctx->state[] (SHA-1) */
|
||
static void sha1_final(HASH_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)
|
||
#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
|
||
}
|
||
|
||
/* Finalize the computation and write the digest in ctx->state[] (SHA-256) */
|
||
static void sha256_final(HASH_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;
|
||
|
||
/* 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;
|
||
}
|
||
|
||
/* 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)
|
||
#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(HASH_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
|
||
}
|
||
|
||
/* Finalize the computation and write the digest in ctx->state[] (MD5) */
|
||
static void md5_final(HASH_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);
|
||
#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(HASH_CONTEXT *ctx) { memset(ctx, 0, sizeof(*ctx)); }
|
||
static void null_write(HASH_CONTEXT *ctx, const uint8_t *buf, size_t len) { }
|
||
static void null_final(HASH_CONTEXT *ctx) { }
|
||
#endif
|
||
|
||
hash_init_t *hash_init[HASH_MAX] = { md5_init, sha1_init , sha256_init, sha512_init };
|
||
hash_write_t *hash_write[HASH_MAX] = { md5_write, sha1_write , sha256_write, sha512_write };
|
||
hash_final_t *hash_final[HASH_MAX] = { md5_final, sha1_final , sha256_final, sha512_final };
|
||
|
||
/* Compute an individual hash without threading or buffering, for a single file */
|
||
BOOL HashFile(const unsigned type, const char* path, uint8_t* hash)
|
||
{
|
||
BOOL r = FALSE;
|
||
HASH_CONTEXT hash_ctx = { {0} };
|
||
HANDLE h = INVALID_HANDLE_VALUE;
|
||
DWORD rs = 0;
|
||
uint64_t rb;
|
||
uint8_t buf[4096];
|
||
|
||
if ((type >= HASH_MAX) || (path == NULL) || (hash == 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());
|
||
ErrorStatus = RUFUS_ERROR(ERROR_OPEN_FAILED);
|
||
goto out;
|
||
}
|
||
|
||
hash_init[type](&hash_ctx);
|
||
for (rb = 0; ; rb += rs) {
|
||
CHECK_FOR_USER_CANCEL;
|
||
if (!ReadFile(h, buf, sizeof(buf), &rs, NULL)) {
|
||
ErrorStatus = RUFUS_ERROR(ERROR_READ_FAULT);
|
||
uprintf(" Read error: %s", WindowsErrorString());
|
||
goto out;
|
||
}
|
||
if (rs == 0)
|
||
break;
|
||
hash_write[type](&hash_ctx, buf, (size_t)rs);
|
||
}
|
||
hash_final[type](&hash_ctx);
|
||
|
||
memcpy(hash, hash_ctx.buf, hash_count[type]);
|
||
r = TRUE;
|
||
|
||
out:
|
||
safe_closehandle(h);
|
||
return r;
|
||
}
|
||
|
||
/* A part of an image, used for hashing */
|
||
struct image_region {
|
||
const uint8_t* data;
|
||
uint32_t size;
|
||
};
|
||
|
||
/**
|
||
* struct efi_image_regions - A list of memory regions
|
||
*
|
||
* @max: Maximum number of regions
|
||
* @num: Number of regions
|
||
* @reg: Array of regions
|
||
*/
|
||
struct efi_image_regions {
|
||
int max;
|
||
int num;
|
||
struct image_region reg[];
|
||
};
|
||
|
||
/**
|
||
* efi_image_region_add() - add an entry of region
|
||
* @regs: Pointer to array of regions
|
||
* @start: Start address of region (included)
|
||
* @end: End address of region (excluded)
|
||
* @nocheck: Flag against overlapped regions
|
||
*
|
||
* Take one entry of region \[@start, @end\[ and insert it into the list.
|
||
*
|
||
* * If @nocheck is false, the list will be sorted ascending by address.
|
||
* Overlapping entries will not be allowed.
|
||
*
|
||
* * If @nocheck is true, the list will be sorted ascending by sequence
|
||
* of adding the entries. Overlapping is allowed.
|
||
*
|
||
* Return: TRUE on success, FALSE on error
|
||
*/
|
||
BOOL efi_image_region_add(struct efi_image_regions* regs,
|
||
const void* start, const void* end, int nocheck)
|
||
{
|
||
struct image_region* reg;
|
||
int i, j;
|
||
|
||
if (regs->num >= regs->max) {
|
||
uprintf("%s: no more room for regions", __func__);
|
||
return FALSE;
|
||
}
|
||
|
||
if (end < start)
|
||
return FALSE;
|
||
|
||
for (i = 0; i < regs->num; i++) {
|
||
reg = ®s->reg[i];
|
||
if (nocheck)
|
||
continue;
|
||
|
||
/* new data after registered region */
|
||
if ((uint8_t*)start >= reg->data + reg->size)
|
||
continue;
|
||
|
||
/* new data preceding registered region */
|
||
if ((uint8_t*)end <= reg->data) {
|
||
for (j = regs->num - 1; j >= i; j--)
|
||
memcpy(®s->reg[j + 1], ®s->reg[j],
|
||
sizeof(*reg));
|
||
break;
|
||
}
|
||
|
||
/* new data overlapping registered region */
|
||
uprintf("%s: new region already part of another", __func__);
|
||
return FALSE;
|
||
}
|
||
|
||
reg = ®s->reg[i];
|
||
reg->data = start;
|
||
reg->size = (uint32_t)((uintptr_t)end - (uintptr_t)start);
|
||
regs->num++;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/**
|
||
* cmp_pe_section() - compare virtual addresses of two PE image sections
|
||
* @arg1: Pointer to pointer to first section header
|
||
* @arg2: Pointer to pointer to second section header
|
||
*
|
||
* Compare the virtual addresses of two sections of an portable executable.
|
||
* The arguments are defined as const void * to allow usage with qsort().
|
||
*
|
||
* Return: -1 if the virtual address of arg1 is less than that of arg2,
|
||
* 0 if the virtual addresses are equal, 1 if the virtual address
|
||
* of arg1 is greater than that of arg2.
|
||
*/
|
||
static int cmp_pe_section(const void* arg1, const void* arg2)
|
||
{
|
||
const IMAGE_SECTION_HEADER* section1, * section2;
|
||
|
||
section1 = *((const IMAGE_SECTION_HEADER**)arg1);
|
||
section2 = *((const IMAGE_SECTION_HEADER**)arg2);
|
||
|
||
if (section1->VirtualAddress < section2->VirtualAddress)
|
||
return -1;
|
||
else if (section1->VirtualAddress == section2->VirtualAddress)
|
||
return 0;
|
||
else
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* efi_image_parse() - parse a PE image
|
||
* @efi: Pointer to image
|
||
* @len: Size of @efi
|
||
* @regp: Pointer to a list of regions
|
||
*
|
||
* Parse image binary in PE32(+) format, assuming that sanity of PE image
|
||
* has been checked by a caller.
|
||
*
|
||
* Return: TRUE on success, FALSE on error
|
||
*/
|
||
BOOL efi_image_parse(uint8_t* efi, size_t len, struct efi_image_regions** regp)
|
||
{
|
||
struct efi_image_regions* regs;
|
||
IMAGE_DOS_HEADER* dos;
|
||
IMAGE_NT_HEADERS32* nt;
|
||
IMAGE_SECTION_HEADER *sections, **sorted;
|
||
int num_regions, num_sections, i;
|
||
DWORD ctidx = IMAGE_DIRECTORY_ENTRY_SECURITY;
|
||
uint32_t align, size, authsz;
|
||
size_t bytes_hashed;
|
||
|
||
dos = (void*)efi;
|
||
nt = (void*)(efi + dos->e_lfanew);
|
||
authsz = 0;
|
||
|
||
/*
|
||
* Count maximum number of regions to be digested.
|
||
* We don't have to have an exact number here.
|
||
* See efi_image_region_add()'s in parsing below.
|
||
*/
|
||
num_regions = 3; /* for header */
|
||
num_regions += nt->FileHeader.NumberOfSections;
|
||
num_regions++; /* for extra */
|
||
|
||
regs = calloc(sizeof(*regs) + sizeof(struct image_region) * num_regions, 1);
|
||
if (!regs)
|
||
goto err;
|
||
regs->max = num_regions;
|
||
|
||
/*
|
||
* Collect data regions for hash calculation
|
||
* 1. File headers
|
||
*/
|
||
if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||
IMAGE_NT_HEADERS64* nt64 = (void*)nt;
|
||
IMAGE_OPTIONAL_HEADER64* opt = &nt64->OptionalHeader;
|
||
|
||
/* Skip CheckSum */
|
||
efi_image_region_add(regs, efi, &opt->CheckSum, 0);
|
||
if (nt64->OptionalHeader.NumberOfRvaAndSizes <= ctidx) {
|
||
efi_image_region_add(regs,
|
||
&opt->Subsystem,
|
||
efi + opt->SizeOfHeaders, 0);
|
||
} else {
|
||
/* Skip Certificates Table */
|
||
efi_image_region_add(regs,
|
||
&opt->Subsystem,
|
||
&opt->DataDirectory[ctidx], 0);
|
||
efi_image_region_add(regs,
|
||
&opt->DataDirectory[ctidx] + 1,
|
||
efi + opt->SizeOfHeaders, 0);
|
||
|
||
authsz = opt->DataDirectory[ctidx].Size;
|
||
}
|
||
|
||
bytes_hashed = opt->SizeOfHeaders;
|
||
align = opt->FileAlignment;
|
||
} else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||
IMAGE_OPTIONAL_HEADER32* opt = &nt->OptionalHeader;
|
||
|
||
/* Skip CheckSum */
|
||
efi_image_region_add(regs, efi, &opt->CheckSum, 0);
|
||
if (nt->OptionalHeader.NumberOfRvaAndSizes <= ctidx) {
|
||
efi_image_region_add(regs,
|
||
&opt->Subsystem,
|
||
efi + opt->SizeOfHeaders, 0);
|
||
} else {
|
||
/* Skip Certificates Table */
|
||
efi_image_region_add(regs, &opt->Subsystem,
|
||
&opt->DataDirectory[ctidx], 0);
|
||
efi_image_region_add(regs,
|
||
&opt->DataDirectory[ctidx] + 1,
|
||
efi + opt->SizeOfHeaders, 0);
|
||
|
||
authsz = opt->DataDirectory[ctidx].Size;
|
||
}
|
||
|
||
bytes_hashed = opt->SizeOfHeaders;
|
||
align = opt->FileAlignment;
|
||
} else {
|
||
uprintf("%s: Invalid optional header magic %x", __func__,
|
||
nt->OptionalHeader.Magic);
|
||
goto err;
|
||
}
|
||
|
||
/* 2. Sections */
|
||
num_sections = nt->FileHeader.NumberOfSections;
|
||
sections = (void*)((uint8_t*)&nt->OptionalHeader +
|
||
nt->FileHeader.SizeOfOptionalHeader);
|
||
sorted = calloc(sizeof(IMAGE_SECTION_HEADER*), num_sections);
|
||
if (!sorted) {
|
||
uprintf("%s: Out of memory", __func__);
|
||
goto err;
|
||
}
|
||
|
||
/*
|
||
* Make sure the section list is in ascending order.
|
||
*/
|
||
for (i = 0; i < num_sections; i++)
|
||
sorted[i] = §ions[i];
|
||
qsort(sorted, num_sections, sizeof(sorted[0]), cmp_pe_section);
|
||
|
||
for (i = 0; i < num_sections; i++) {
|
||
if (!sorted[i]->SizeOfRawData)
|
||
continue;
|
||
|
||
size = (sorted[i]->SizeOfRawData + align - 1) & ~(align - 1);
|
||
efi_image_region_add(regs, efi + sorted[i]->PointerToRawData,
|
||
efi + sorted[i]->PointerToRawData + size, 0);
|
||
//uprintf("section[%d](%s): raw: 0x%x-0x%x, virt: %x-%x",
|
||
// i, sorted[i]->Name,
|
||
// sorted[i]->PointerToRawData,
|
||
// sorted[i]->PointerToRawData + size,
|
||
// sorted[i]->VirtualAddress,
|
||
// sorted[i]->VirtualAddress
|
||
// + sorted[i]->Misc.VirtualSize);
|
||
|
||
bytes_hashed += size;
|
||
}
|
||
free(sorted);
|
||
|
||
/* 3. Extra data excluding Certificates Table */
|
||
if (bytes_hashed + authsz < len) {
|
||
//uprintf("extra data for hash: %zu",
|
||
// len - (bytes_hashed + authsz));
|
||
efi_image_region_add(regs, efi + bytes_hashed,
|
||
efi + len - authsz, 0);
|
||
}
|
||
|
||
*regp = regs;
|
||
return TRUE;
|
||
|
||
err:
|
||
free(regs);
|
||
return FALSE;
|
||
}
|
||
|
||
/*
|
||
* Compute the PE256 (a.k.a. Applocker SHA256) hash of a single EFI executable.
|
||
* This is a SHA-256 hash applied to only specific parts of a PE binary.
|
||
* See https://security.stackexchange.com/a/199627/270178.
|
||
* Oh, and you'd think that Windows's ImageGetDigestStream() API could be used
|
||
* for some part of this but you'd be very, very wrong since the PE sections it
|
||
* feeds to the hash function does include the PE header checksum field...
|
||
*/
|
||
BOOL PE256File(const char* path, uint8_t* hash)
|
||
{
|
||
BOOL r = FALSE;
|
||
HASH_CONTEXT hash_ctx = { {0} };
|
||
int i;
|
||
uint32_t rb;
|
||
uint8_t* buf = NULL;
|
||
struct __stat64 stat64 = { 0 };
|
||
struct efi_image_regions* regs = NULL;
|
||
|
||
if ((path == NULL) || (hash == NULL))
|
||
goto out;
|
||
|
||
/* Filter anything that would be out of place as a EFI bootloader */
|
||
if (_stat64U(path, &stat64) != 0) {
|
||
uprintf("Could not open '%s", path);
|
||
goto out;
|
||
}
|
||
if ((stat64.st_size < 1 * KB) || (stat64.st_size > 64 * MB)) {
|
||
uprintf("'%s' is either too small or too large for PE-256", path);
|
||
goto out;
|
||
}
|
||
|
||
/* Read the executable into a memory buffer */
|
||
rb = read_file(path, &buf);
|
||
if (rb < 1 * KB)
|
||
goto out;
|
||
|
||
/* Isolate the PE sections to hash */
|
||
if (!efi_image_parse(buf, rb, ®s))
|
||
goto out;
|
||
|
||
/* Hash the relevant PE data */
|
||
sha256_init(&hash_ctx);
|
||
for (i = 0; i < regs->num; i++)
|
||
sha256_write(&hash_ctx, regs->reg[i].data, regs->reg[i].size);
|
||
sha256_final(&hash_ctx);
|
||
|
||
memcpy(hash, hash_ctx.buf, SHA256_HASHSIZE);
|
||
r = TRUE;
|
||
|
||
out:
|
||
free(regs);
|
||
free(buf);
|
||
return r;
|
||
}
|
||
|
||
/*
|
||
* Compute the hash of a single buffer.
|
||
*/
|
||
BOOL HashBuffer(const unsigned type, const uint8_t* buf, const size_t len, uint8_t* hash)
|
||
{
|
||
BOOL r = FALSE;
|
||
HASH_CONTEXT hash_ctx = { {0} };
|
||
|
||
if ((type >= HASH_MAX) || (hash == NULL))
|
||
goto out;
|
||
|
||
hash_init[type](&hash_ctx);
|
||
hash_write[type](&hash_ctx, buf, len);
|
||
hash_final[type](&hash_ctx);
|
||
|
||
memcpy(hash, hash_ctx.buf, hash_count[type]);
|
||
r = TRUE;
|
||
|
||
out:
|
||
return r;
|
||
}
|
||
|
||
/*
|
||
* Hash dialog callback
|
||
*/
|
||
INT_PTR CALLBACK HashCallback(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_HASH, 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);
|
||
SendDlgItemMessageA(hDlg, IDC_SHA512, WM_SETFONT, (WPARAM)hFont, TRUE);
|
||
SetWindowTextA(GetDlgItem(hDlg, IDC_MD5), hash_str[0]);
|
||
SetWindowTextA(GetDlgItem(hDlg, IDC_SHA1), hash_str[1]);
|
||
SetWindowTextA(GetDlgItem(hDlg, IDC_SHA256), hash_str[2]);
|
||
if (enable_extra_hashes)
|
||
SetWindowTextA(GetDlgItem(hDlg, IDC_SHA512), hash_str[3]);
|
||
else
|
||
SetWindowTextU(GetDlgItem(hDlg, IDC_SHA512), lmprintf(MSG_311, "<Alt>-<H>"));
|
||
|
||
// 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, hash_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);
|
||
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SHA512), 0, 0, dw, dh, 1.0f);
|
||
|
||
GetWindowRect(GetDlgItem(hDlg, IDC_SHA1), &rc);
|
||
dw = rc.right - rc.left;
|
||
DrawTextU(hDC, hash_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);
|
||
|
||
if (image_path != NULL) {
|
||
for (i = (int)strlen(image_path); (i > 0) && (image_path[i] != '\\'); i--);
|
||
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_HASH);
|
||
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 IndividualHashThread(void* param)
|
||
{
|
||
HASH_CONTEXT hash_ctx = { {0} }; // There's a memset in hash_init, but static analyzers still bug us
|
||
uint32_t i = (uint32_t)(uintptr_t)param, j;
|
||
|
||
hash_init[i](&hash_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 hash thread #%d: %s", i, WindowsErrorString());
|
||
return 1;
|
||
}
|
||
if (read_size[proc_bufnum] != 0) {
|
||
hash_write[i](&hash_ctx, buffer[proc_bufnum], (size_t)read_size[proc_bufnum]);
|
||
if (!SetEvent(thread_ready[i]))
|
||
goto error;
|
||
} else {
|
||
hash_final[i](&hash_ctx);
|
||
memset(&hash_str[i], 0, ARRAYSIZE(hash_str[i]));
|
||
for (j = 0; j < hash_count[i]; j++) {
|
||
hash_str[i][2 * j] = ((hash_ctx.buf[j] >> 4) < 10) ?
|
||
((hash_ctx.buf[j] >> 4) + '0') : ((hash_ctx.buf[j] >> 4) - 0xa + 'a');
|
||
hash_str[i][2 * j + 1] = ((hash_ctx.buf[j] & 15) < 10) ?
|
||
((hash_ctx.buf[j] & 15) + '0') : ((hash_ctx.buf[j] & 15) - 0xa + 'a');
|
||
}
|
||
hash_str[i][2 * j] = 0;
|
||
return 0;
|
||
}
|
||
}
|
||
error:
|
||
uprintf("Failed to set event for hash thread #%d: %s", i, WindowsErrorString());
|
||
return 1;
|
||
}
|
||
|
||
DWORD WINAPI HashThread(void* param)
|
||
{
|
||
DWORD_PTR* thread_affinity = (DWORD_PTR*)param;
|
||
HANDLE hash_thread[HASH_MAX] = { NULL, NULL, NULL, NULL };
|
||
DWORD wr;
|
||
VOID* fd = NULL;
|
||
uint64_t processed_bytes;
|
||
int i, read_bufnum, r = -1;
|
||
int num_hashes = HASH_MAX - (enable_extra_hashes ? 0 : 1);
|
||
|
||
if ((image_path == NULL) || (thread_affinity == NULL))
|
||
ExitThread(r);
|
||
|
||
uprintf("\r\nComputing hash 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 < num_hashes; 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 hash thread event: %s", WindowsErrorString());
|
||
goto out;
|
||
}
|
||
hash_thread[i] = CreateThread(NULL, 0, IndividualHashThread, (LPVOID)(uintptr_t)i, 0, NULL);
|
||
if (hash_thread[i] == NULL) {
|
||
uprintf("Unable to start hash thread #%d", i);
|
||
goto out;
|
||
}
|
||
SetThreadPriority(hash_thread[i], default_thread_priority);
|
||
if (thread_affinity[i+1] != 0)
|
||
SetThreadAffinityMask(hash_thread[i], thread_affinity[i+1]);
|
||
}
|
||
|
||
fd = CreateFileAsync(image_path, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN);
|
||
if (fd == NULL) {
|
||
uprintf("Could not open file: %s", WindowsErrorString());
|
||
ErrorStatus = RUFUS_ERROR(ERROR_OPEN_FAILED);
|
||
goto out;
|
||
}
|
||
|
||
read_bufnum = 0;
|
||
proc_bufnum = 1;
|
||
read_size[proc_bufnum] = 1; // To avoid early loop exit
|
||
UpdateProgressWithInfoInit(hMainDialog, FALSE);
|
||
|
||
// Start the initial read
|
||
ReadFileAsync(fd, buffer[read_bufnum], BUFFER_SIZE);
|
||
|
||
for (processed_bytes = 0; read_size[proc_bufnum] != 0; processed_bytes += read_size[proc_bufnum]) {
|
||
// 0. Update the progress and check for cancel
|
||
UpdateProgressWithInfo(OP_NOOP_WITH_TASKBAR, MSG_271, processed_bytes, img_report.image_size);
|
||
CHECK_FOR_USER_CANCEL;
|
||
|
||
// 1. Wait for the current read operation to complete (and update the read size)
|
||
if ((!WaitFileAsync(fd, DRIVE_ACCESS_TIMEOUT)) ||
|
||
(!GetSizeAsync(fd, &read_size[read_bufnum]))) {
|
||
uprintf("Read error: %s", WindowsErrorString());
|
||
ErrorStatus = RUFUS_ERROR(ERROR_READ_FAULT);
|
||
goto out;
|
||
}
|
||
|
||
// 2. Switch to the next reading buffer
|
||
read_bufnum = (read_bufnum + 1) % NUM_BUFFERS;
|
||
|
||
// 3. Launch the next asynchronous read operation
|
||
ReadFileAsync(fd, buffer[read_bufnum], BUFFER_SIZE);
|
||
|
||
// 4. Wait for all the hash threads to indicate that they are ready to process data
|
||
wr = WaitForMultipleObjects(num_hashes, thread_ready, TRUE, WAIT_TIME);
|
||
if (wr != WAIT_OBJECT_0) {
|
||
if (wr == STATUS_TIMEOUT)
|
||
SetLastError(ERROR_TIMEOUT);
|
||
uprintf("Hash threads failed to signal: %s", WindowsErrorString());
|
||
goto out;
|
||
}
|
||
|
||
// 5. Set the target buffer we want to process to the buffer we just read data into
|
||
// Note that this variable should only be updated AFTER all the threads have signalled.
|
||
proc_bufnum = (read_bufnum + NUM_BUFFERS - 1) % NUM_BUFFERS;
|
||
|
||
// 6. Signal the waiting threads that there is data available
|
||
for (i = 0; i < num_hashes; i++) {
|
||
if (!SetEvent(data_ready[i])) {
|
||
uprintf("Could not signal hash thread %d: %s", i, WindowsErrorString());
|
||
goto out;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Our last event with read_size=0 signaled the threads to exit - wait for that to happen
|
||
if (WaitForMultipleObjects(num_hashes, hash_thread, TRUE, WAIT_TIME) != WAIT_OBJECT_0) {
|
||
uprintf("Hash threads did not finalize: %s", WindowsErrorString());
|
||
goto out;
|
||
}
|
||
|
||
uprintf(" MD5: %s", hash_str[0]);
|
||
uprintf(" SHA1: %s", hash_str[1]);
|
||
uprintf(" SHA256: %s", hash_str[2]);
|
||
if (enable_extra_hashes) {
|
||
char c = hash_str[3][SHA512_HASHSIZE];
|
||
hash_str[3][SHA512_HASHSIZE] = 0;
|
||
uprintf(" SHA512: %s", hash_str[3]);
|
||
hash_str[3][SHA512_HASHSIZE] = c;
|
||
uprintf(" %s", &hash_str[3][SHA512_HASHSIZE]);
|
||
}
|
||
r = 0;
|
||
|
||
out:
|
||
for (i = 0; i < num_hashes; i++) {
|
||
if (hash_thread[i] != NULL)
|
||
TerminateThread(hash_thread[i], 1);
|
||
safe_closehandle(data_ready[i]);
|
||
safe_closehandle(thread_ready[i]);
|
||
}
|
||
CloseFileAsync(fd);
|
||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
|
||
if (r == 0)
|
||
MyDialogBox(hMainInstance, IDD_HASH, hMainDialog, HashCallback);
|
||
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 hash[SHA256_HASHSIZE];
|
||
if (!HashBuffer(HASH_SHA256, buf, len, hash))
|
||
return FALSE;
|
||
for (i = 0; i < ARRAYSIZE(sha256db); i += SHA256_HASHSIZE)
|
||
if (memcmp(hash, &sha256db[i], SHA256_HASHSIZE) == 0)
|
||
return TRUE;
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL IsFileInDB(const char* path)
|
||
{
|
||
int i;
|
||
uint8_t hash[SHA256_HASHSIZE];
|
||
if (!HashFile(HASH_SHA256, path, hash))
|
||
return FALSE;
|
||
for (i = 0; i < ARRAYSIZE(sha256db); i += SHA256_HASHSIZE)
|
||
if (memcmp(hash, &sha256db[i], SHA256_HASHSIZE) == 0)
|
||
return TRUE;
|
||
return FALSE;
|
||
}
|
||
|
||
int IsBootloaderRevoked(const char* path)
|
||
{
|
||
version_t* ver;
|
||
uint32_t i;
|
||
uint8_t hash[SHA256_HASHSIZE];
|
||
|
||
if (!PE256File(path, hash))
|
||
return -1;
|
||
for (i = 0; i < ARRAYSIZE(pe256dbx); i += SHA256_HASHSIZE)
|
||
if (memcmp(hash, &pe256dbx[i], SHA256_HASHSIZE) == 0)
|
||
return 1;
|
||
for (i = 0; i < pe256ssp_size * SHA256_HASHSIZE; i += SHA256_HASHSIZE)
|
||
if (memcmp(hash, &pe256ssp[i], SHA256_HASHSIZE) == 0)
|
||
return 2;
|
||
ver = GetExecutableVersion(path);
|
||
// Blanket filter for Windows 10 1607 (excluded) to Windows 10 20H1 (excluded)
|
||
// TODO: Revoke all bootloaders prior to 2023.05 once Microsoft does
|
||
// uprintf("Found UEFI bootloader version: %d.%d.%d.%d", ver->Major, ver->Minor, ver->Micro, ver->Nano);
|
||
if (ver != NULL && ver->Major == 10 && ver->Minor == 0 && ver->Micro > 14393 && ver->Micro < 19041)
|
||
return 3;
|
||
return 0;
|
||
}
|
||
|
||
void PrintRevokedBootloaderInfo(void)
|
||
{
|
||
uprintf("Found %d officially revoked UEFI bootloaders from embedded list", sizeof(pe256dbx) / SHA256_HASHSIZE);
|
||
if (ParseSKUSiPolicy())
|
||
uprintf("Found %d additional revoked UEFI bootloaders from this system's SKUSiPolicy.p7b", pe256ssp_size);
|
||
else
|
||
uprintf("WARNING: Could not parse this system's SkuSiPolicy.p7b for additional revoked UEFI bootloaders");
|
||
}
|
||
|
||
/*
|
||
* Updates the MD5SUMS/md5sum.txt file that some distros (Ubuntu, Mint...)
|
||
* use to validate the media. Because we may alter some of the validated files
|
||
* to add persistence and whatnot, we need to alter the MD5 list as a result.
|
||
* The format of the file is expected to always be "<MD5SUM> <FILE_PATH>" on
|
||
* individual lines.
|
||
* This function is also used to finalize the md5sum.txt we create for use with
|
||
* our uefi-md5sum bootloaders.
|
||
*/
|
||
void UpdateMD5Sum(const char* dest_dir, const char* md5sum_name)
|
||
{
|
||
BOOL display_header = TRUE;
|
||
BYTE* res_data;
|
||
DWORD res_size;
|
||
HANDLE hFile;
|
||
intptr_t pos;
|
||
uint32_t i, j, size, md5_size, new_size;
|
||
uint8_t sum[MD5_HASHSIZE];
|
||
char md5_path[64], path1[64], path2[64], *md5_data = NULL, *new_data = NULL, *str_pos;
|
||
char *d, *s, *p;
|
||
|
||
if (!img_report.has_md5sum && !validate_md5sum)
|
||
goto out;
|
||
|
||
static_sprintf(md5_path, "%s\\%s", dest_dir, md5sum_name);
|
||
md5_size = read_file(md5_path, (uint8_t**)&md5_data);
|
||
if (md5_size == 0)
|
||
goto out;
|
||
|
||
for (i = 0; i < modified_files.Index; i++) {
|
||
for (j = 0; j < (uint32_t)strlen(modified_files.String[i]); j++)
|
||
if (modified_files.String[i][j] == '\\')
|
||
modified_files.String[i][j] = '/';
|
||
str_pos = strstr(md5_data, &modified_files.String[i][2]);
|
||
if (str_pos == NULL)
|
||
// File is not listed in md5 sums
|
||
continue;
|
||
if (display_header) {
|
||
uprintf("Updating %s:", md5_path);
|
||
display_header = FALSE;
|
||
}
|
||
uprintf("● %s", &modified_files.String[i][2]);
|
||
pos = str_pos - md5_data;
|
||
HashFile(HASH_MD5, modified_files.String[i], sum);
|
||
while ((pos > 0) && (md5_data[pos - 1] != '\n'))
|
||
pos--;
|
||
assert(IS_HEXASCII(md5_data[pos]));
|
||
for (j = 0; j < 16; j++) {
|
||
md5_data[pos + 2 * j] = ((sum[j] >> 4) < 10) ? ('0' + (sum[j] >> 4)) : ('a' - 0xa + (sum[j] >> 4));
|
||
md5_data[pos + 2 * j + 1] = ((sum[j] & 15) < 10) ? ('0' + (sum[j] & 15)) : ('a' - 0xa + (sum[j] & 15));
|
||
}
|
||
}
|
||
|
||
// If we validate md5sum we need to update the original bootloader names and add md5sum_totalbytes
|
||
if (validate_md5sum) {
|
||
new_size = md5_size;
|
||
new_data = malloc(md5_size + 1024);
|
||
assert(new_data != NULL);
|
||
if (new_data == NULL)
|
||
goto out;
|
||
// Will be nonzero if we created the file, otherwise zero
|
||
if (md5sum_totalbytes != 0) {
|
||
snprintf(new_data, md5_size + 1024, "# md5sum_totalbytes = 0x%llx\n", md5sum_totalbytes);
|
||
new_size += (uint32_t)strlen(new_data);
|
||
d = &new_data[strlen(new_data)];
|
||
} else {
|
||
d = new_data;
|
||
}
|
||
s = md5_data;
|
||
// Extract the MD5Sum bootloader(s)
|
||
for (i = 1; i < ARRAYSIZE(efi_bootname); i++) {
|
||
static_sprintf(path1, "%s\\efi\\boot\\%s", dest_dir, efi_bootname[i]);
|
||
if (!PathFileExistsA(path1))
|
||
continue;
|
||
res_data = (BYTE*)GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_MD5_BOOT + i),
|
||
_RT_RCDATA, efi_bootname[i], &res_size, FALSE);
|
||
static_strcpy(path2, path1);
|
||
path2[strlen(path2) - 4] = 0;
|
||
static_strcat(path2, "_original.efi");
|
||
if (res_data == NULL || !MoveFileU(path1, path2)) {
|
||
uprintf("Could not rename: %s → %s", path1, path2);
|
||
continue;
|
||
}
|
||
uprintf("Renamed: %s → %s", path1, path2);
|
||
hFile = CreateFileA(path1, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) {
|
||
uprintf("Could not create '%s': %s.", path1, WindowsErrorString());
|
||
MoveFileU(path2, path1);
|
||
continue;
|
||
}
|
||
if (!WriteFileWithRetry(hFile, res_data, res_size, NULL, WRITE_RETRIES)) {
|
||
uprintf("Could not write '%s': %s.", path1, WindowsErrorString());
|
||
safe_closehandle(hFile);
|
||
MoveFileU(path2, path1);
|
||
continue;
|
||
}
|
||
safe_closehandle(hFile);
|
||
uprintf("Created: %s (%s)", path1, SizeToHumanReadable(res_size, FALSE, FALSE));
|
||
}
|
||
// Rename the original bootloaders if present in md5sum.txt
|
||
for (p = md5_data; (p = StrStrIA(p, " ./efi/boot/boot")) != NULL; ) {
|
||
for (i = 1; i < ARRAYSIZE(efi_bootname); i++) {
|
||
if (p[12 + strlen(efi_bootname[i])] != 0x0a)
|
||
continue;
|
||
p[12 + strlen(efi_bootname[i])] = 0;
|
||
if (lstrcmpiA(&p[12], efi_bootname[i]) == 0) {
|
||
size = (uint32_t)(p - s) + 12 + (uint32_t)strlen(efi_bootname[i]) - 4;
|
||
memcpy(d, s, size);
|
||
d = &d[size];
|
||
strcpy(d, "_original.efi\n");
|
||
new_size += 9;
|
||
d = &d[14];
|
||
s = &p[12 + strlen(efi_bootname[i]) + 1];
|
||
}
|
||
p[12 + strlen(efi_bootname[i])] = 0x0a;
|
||
}
|
||
p = &p[12];
|
||
}
|
||
p = &md5_data[md5_size];
|
||
memcpy(d, s, p - s);
|
||
free(md5_data);
|
||
md5_data = new_data;
|
||
md5_size = new_size;
|
||
}
|
||
|
||
write_file(md5_path, md5_data, md5_size);
|
||
free(md5_data);
|
||
|
||
out:
|
||
// We no longer need the string array at this stage
|
||
StrArrayDestroy(&modified_files);
|
||
}
|
||
|
||
#if defined(_DEBUG) || defined(TEST) || defined(ALPHA)
|
||
/* 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[HASH_MAX][4] = {
|
||
{
|
||
"d41d8cd98f00b204e9800998ecf8427e",
|
||
"74cac558072300385f7ab4dff7465e3c",
|
||
"f99d37d3bee20f9c0ca3204991be2698",
|
||
"e0ea372ac14a3574167543b851d4babb"
|
||
}, {
|
||
"da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
||
"a5bac908bf3e51ff0036a94d43b4f3bd2d01a75d",
|
||
"8aa6c0064b013b8a6f4e88a0421d39bbf07e2e1b",
|
||
"09463ec0b5917706c9cb1d6b164b2582c04018e0"
|
||
}, {
|
||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||
"62c1a97974dfe6848942794be4f2f027b5f4815e1eb76db63a30f0e290b5c1c4",
|
||
"dbca61af192edba49ea215c49a23feee302c98cc4d2c018347fe78db572f07a5",
|
||
"c9b43c1058bc7f7661619e9d983fc9d31356e97f9195a2405ab972d0737b11bf"
|
||
}, {
|
||
"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
|
||
"4913ace12f1169e5a5f524ef87ab8fc39dff0418851fbbbb1f609d3261b2b4072bd1746e6accb91bf38f3b1b3d59b0a60af5de67aab87b76c2456fde523efc1c",
|
||
"33df8a16dd624cbc4613b5ae902b722411c7e90f37dd3947c9a86e01c51ada68fcf5a0cd4ca928d7cc1ed469bb34c2ed008af069d8b28cc4512e6c8b2e7a5592",
|
||
"999b4eae14de584cce5fa5962b768beda076b06df00d384bb502c6389df8159c006a5b94d1324f47e8d7bd2efe9d8d3dc1fa1429798e49826987ab5ae7ed5c21"
|
||
},
|
||
};
|
||
|
||
/* Tests the message digest algorithms */
|
||
int TestHashes(void)
|
||
{
|
||
const uint32_t blocksize[HASH_MAX] = { MD5_BLOCKSIZE, SHA1_BLOCKSIZE, SHA256_BLOCKSIZE, SHA512_BLOCKSIZE };
|
||
const char* hash_name[4] = { "MD5 ", "SHA1 ", "SHA256", "SHA512" };
|
||
int i, j, errors = 0;
|
||
uint8_t hash[MAX_HASHSIZE], *hash_expected;
|
||
size_t full_msg_len = strlen(test_msg);
|
||
char* msg = malloc(full_msg_len + 1);
|
||
if (msg == NULL)
|
||
return -1;
|
||
|
||
/* Display accelerations available */
|
||
uprintf("SHA1 acceleration: %s", (cpu_has_sha1_accel ? "TRUE" : "FALSE"));
|
||
uprintf("SHA256 acceleration: %s", (cpu_has_sha256_accel ? "TRUE" : "FALSE"));
|
||
|
||
for (j = 0; j < HASH_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] = blocksize[j] - (blocksize[j] >> 3);
|
||
copy_msg_len[3] = full_msg_len;
|
||
for (i = 0; i < 4; i++) {
|
||
memset(msg, 0, full_msg_len + 1);
|
||
if (i != 0)
|
||
memcpy(msg, test_msg, copy_msg_len[i]);
|
||
HashBuffer(j, msg, copy_msg_len[i], hash);
|
||
hash_expected = to_bin(test_hash[j][i]);
|
||
if (memcmp(hash, hash_expected, hash_count[j]) != 0) {
|
||
uprintf("Test %s %d: FAIL", hash_name[j], i);
|
||
errors++;
|
||
} else {
|
||
uprintf("Test %s %d: PASS", hash_name[j], i);
|
||
}
|
||
free(hash_expected);
|
||
}
|
||
}
|
||
|
||
free(msg);
|
||
return errors;
|
||
}
|
||
#endif
|