commit
a9d9f5c0da
|
@ -31,6 +31,8 @@ add_library(common
|
||||||
Crypto/bn.h
|
Crypto/bn.h
|
||||||
Crypto/ec.cpp
|
Crypto/ec.cpp
|
||||||
Crypto/ec.h
|
Crypto/ec.h
|
||||||
|
Crypto/SHA1.cpp
|
||||||
|
Crypto/SHA1.h
|
||||||
Debug/MemoryPatches.cpp
|
Debug/MemoryPatches.cpp
|
||||||
Debug/MemoryPatches.h
|
Debug/MemoryPatches.h
|
||||||
Debug/Threads.h
|
Debug/Threads.h
|
||||||
|
|
|
@ -0,0 +1,400 @@
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "SHA1.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <mbedtls/sha1.h>
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
|
#include "Common/CPUDetect.h"
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Swap.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <intrin.h>
|
||||||
|
#else
|
||||||
|
#ifdef _M_X86_64
|
||||||
|
#include <immintrin.h>
|
||||||
|
#elif defined(_M_ARM_64)
|
||||||
|
#if defined(__clang__)
|
||||||
|
// This is a bit of a hack to get clang to accept the sha1 intrinsics without modifying cmdline
|
||||||
|
// flags. Note __ARM_FEATURE_CRYPTO is deprecated and "SHA2" flag is the lowest one which includes
|
||||||
|
// SHA1.
|
||||||
|
#define __ARM_FEATURE_SHA2
|
||||||
|
// ...needed for older clang before they made the switchover to more granular flags.
|
||||||
|
#define __ARM_FEATURE_CRYPTO
|
||||||
|
#endif
|
||||||
|
#include <arm_acle.h>
|
||||||
|
#include <arm_neon.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define ATTRIBUTE_TARGET(x)
|
||||||
|
#else
|
||||||
|
#define ATTRIBUTE_TARGET(x) [[gnu::target(x)]]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Common::SHA1
|
||||||
|
{
|
||||||
|
class ContextMbed final : public Context
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ContextMbed()
|
||||||
|
{
|
||||||
|
mbedtls_sha1_init(&ctx);
|
||||||
|
ASSERT(!mbedtls_sha1_starts_ret(&ctx));
|
||||||
|
}
|
||||||
|
~ContextMbed() { mbedtls_sha1_free(&ctx); }
|
||||||
|
virtual void Update(const u8* msg, size_t len) override
|
||||||
|
{
|
||||||
|
ASSERT(!mbedtls_sha1_update_ret(&ctx, msg, len));
|
||||||
|
}
|
||||||
|
virtual Digest Finish() override
|
||||||
|
{
|
||||||
|
Digest digest;
|
||||||
|
ASSERT(!mbedtls_sha1_finish_ret(&ctx, digest.data()));
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mbedtls_sha1_context ctx{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class BlockContext : public Context
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
static constexpr size_t BLOCK_LEN = 64;
|
||||||
|
static constexpr u32 K[4]{0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6};
|
||||||
|
static constexpr u32 H[5]{0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0};
|
||||||
|
|
||||||
|
virtual void ProcessBlock(const u8* msg) = 0;
|
||||||
|
virtual Digest GetDigest() = 0;
|
||||||
|
|
||||||
|
virtual void Update(const u8* msg, size_t len) override
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
msg_len += len;
|
||||||
|
|
||||||
|
if (block_used)
|
||||||
|
{
|
||||||
|
if (block_used + len >= block.size())
|
||||||
|
{
|
||||||
|
size_t rem = block.size() - block_used;
|
||||||
|
std::memcpy(&block[block_used], msg, rem);
|
||||||
|
ProcessBlock(&block[0]);
|
||||||
|
block_used = 0;
|
||||||
|
msg += rem;
|
||||||
|
len -= rem;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::memcpy(&block[block_used], msg, len);
|
||||||
|
block_used += len;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (len >= BLOCK_LEN)
|
||||||
|
{
|
||||||
|
ProcessBlock(msg);
|
||||||
|
msg += BLOCK_LEN;
|
||||||
|
len -= BLOCK_LEN;
|
||||||
|
}
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
std::memcpy(&block[0], msg, len);
|
||||||
|
block_used = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Digest Finish() override
|
||||||
|
{
|
||||||
|
// block_used is guaranteed < BLOCK_LEN
|
||||||
|
block[block_used++] = 0x80;
|
||||||
|
|
||||||
|
constexpr size_t MSG_LEN_POS = BLOCK_LEN - sizeof(u64);
|
||||||
|
if (block_used > MSG_LEN_POS)
|
||||||
|
{
|
||||||
|
// Pad current block and process it
|
||||||
|
std::memset(&block[block_used], 0, BLOCK_LEN - block_used);
|
||||||
|
ProcessBlock(&block[0]);
|
||||||
|
|
||||||
|
// Pad a new block
|
||||||
|
std::memset(&block[0], 0, MSG_LEN_POS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Pad current block
|
||||||
|
std::memset(&block[block_used], 0, MSG_LEN_POS - block_used);
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::BigEndianValue<u64> msg_bitlen(msg_len * 8);
|
||||||
|
std::memcpy(&block[MSG_LEN_POS], &msg_bitlen, sizeof(msg_bitlen));
|
||||||
|
|
||||||
|
ProcessBlock(&block[0]);
|
||||||
|
|
||||||
|
return GetDigest();
|
||||||
|
}
|
||||||
|
|
||||||
|
alignas(64) std::array<u8, BLOCK_LEN> block{};
|
||||||
|
size_t block_used{};
|
||||||
|
size_t msg_len{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ValueType, size_t Size>
|
||||||
|
class CyclicArray
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline ValueType operator[](size_t i) const { return data[i % Size]; }
|
||||||
|
inline ValueType& operator[](size_t i) { return data[i % Size]; }
|
||||||
|
constexpr size_t size() { return Size; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<ValueType, Size> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _M_X86_64
|
||||||
|
|
||||||
|
// Uses the dedicated SHA1 instructions. Normal SSE(AVX*) would be needed for parallel
|
||||||
|
// multi-message processing. While Dolphin could gain from such implementation, it requires the
|
||||||
|
// calling code to be modified and/or making the SHA1 implementation asynchronous so it can
|
||||||
|
// optimistically batch.
|
||||||
|
class ContextX64SHA1 final : public BlockContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ContextX64SHA1()
|
||||||
|
{
|
||||||
|
state[0] = _mm_set_epi32(H[0], H[1], H[2], H[3]);
|
||||||
|
state[1] = _mm_set_epi32(H[4], 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
using WorkBlock = CyclicArray<__m128i, 4>;
|
||||||
|
|
||||||
|
ATTRIBUTE_TARGET("ssse3")
|
||||||
|
static inline __m128i byterev_16B(__m128i x)
|
||||||
|
{
|
||||||
|
return _mm_shuffle_epi8(x, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t I>
|
||||||
|
ATTRIBUTE_TARGET("sha")
|
||||||
|
static inline __m128i MsgSchedule(WorkBlock* wblock)
|
||||||
|
{
|
||||||
|
auto& w = *wblock;
|
||||||
|
// Update and return this location
|
||||||
|
auto& wx = w[I];
|
||||||
|
// Do all the xors and rol(x,1) required for 4 rounds of msg schedule
|
||||||
|
wx = _mm_sha1msg1_epu32(wx, w[I + 1]);
|
||||||
|
wx = _mm_xor_si128(wx, w[I + 2]);
|
||||||
|
wx = _mm_sha1msg2_epu32(wx, w[I + 3]);
|
||||||
|
return wx;
|
||||||
|
}
|
||||||
|
|
||||||
|
ATTRIBUTE_TARGET("sha")
|
||||||
|
virtual void ProcessBlock(const u8* msg) override
|
||||||
|
{
|
||||||
|
// There are 80 rounds with 4 bytes per round, giving 0x140 byte work space, but we can keep
|
||||||
|
// active state in just 0x40 bytes.
|
||||||
|
// see FIPS 180-4 6.1.3 Alternate Method for Computing a SHA-1 Message Digest
|
||||||
|
WorkBlock w;
|
||||||
|
auto msg_block = (const __m128i*)msg;
|
||||||
|
for (size_t i = 0; i < w.size(); i++)
|
||||||
|
w[i] = byterev_16B(_mm_loadu_si128(&msg_block[i]));
|
||||||
|
|
||||||
|
// 0: abcd, 1: e
|
||||||
|
auto abcde = state;
|
||||||
|
|
||||||
|
// Not sure of a (non-ugly) way to have constant-evaluated for-loop, so just rely on inlining.
|
||||||
|
// Problem is that sha1rnds4 requires imm8 arg, and first/last rounds have different behavior.
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
// E0 += MSG0, special case of "nexte", can do normal add
|
||||||
|
abcde[1] = _mm_sha1rnds4_epu32(abcde[0], _mm_add_epi32(abcde[1], w[0]), 0);
|
||||||
|
abcde[0] = _mm_sha1rnds4_epu32(abcde[1], _mm_sha1nexte_epu32(abcde[0], w[1]), 0);
|
||||||
|
abcde[1] = _mm_sha1rnds4_epu32(abcde[0], _mm_sha1nexte_epu32(abcde[1], w[2]), 0);
|
||||||
|
abcde[0] = _mm_sha1rnds4_epu32(abcde[1], _mm_sha1nexte_epu32(abcde[0], w[3]), 0);
|
||||||
|
abcde[1] = _mm_sha1rnds4_epu32(abcde[0], _mm_sha1nexte_epu32(abcde[1], MsgSchedule<4>(&w)), 0);
|
||||||
|
abcde[0] = _mm_sha1rnds4_epu32(abcde[1], _mm_sha1nexte_epu32(abcde[0], MsgSchedule<5>(&w)), 1);
|
||||||
|
abcde[1] = _mm_sha1rnds4_epu32(abcde[0], _mm_sha1nexte_epu32(abcde[1], MsgSchedule<6>(&w)), 1);
|
||||||
|
abcde[0] = _mm_sha1rnds4_epu32(abcde[1], _mm_sha1nexte_epu32(abcde[0], MsgSchedule<7>(&w)), 1);
|
||||||
|
abcde[1] = _mm_sha1rnds4_epu32(abcde[0], _mm_sha1nexte_epu32(abcde[1], MsgSchedule<8>(&w)), 1);
|
||||||
|
abcde[0] = _mm_sha1rnds4_epu32(abcde[1], _mm_sha1nexte_epu32(abcde[0], MsgSchedule<9>(&w)), 1);
|
||||||
|
abcde[1] = _mm_sha1rnds4_epu32(abcde[0], _mm_sha1nexte_epu32(abcde[1], MsgSchedule<10>(&w)), 2);
|
||||||
|
abcde[0] = _mm_sha1rnds4_epu32(abcde[1], _mm_sha1nexte_epu32(abcde[0], MsgSchedule<11>(&w)), 2);
|
||||||
|
abcde[1] = _mm_sha1rnds4_epu32(abcde[0], _mm_sha1nexte_epu32(abcde[1], MsgSchedule<12>(&w)), 2);
|
||||||
|
abcde[0] = _mm_sha1rnds4_epu32(abcde[1], _mm_sha1nexte_epu32(abcde[0], MsgSchedule<13>(&w)), 2);
|
||||||
|
abcde[1] = _mm_sha1rnds4_epu32(abcde[0], _mm_sha1nexte_epu32(abcde[1], MsgSchedule<14>(&w)), 2);
|
||||||
|
abcde[0] = _mm_sha1rnds4_epu32(abcde[1], _mm_sha1nexte_epu32(abcde[0], MsgSchedule<15>(&w)), 3);
|
||||||
|
abcde[1] = _mm_sha1rnds4_epu32(abcde[0], _mm_sha1nexte_epu32(abcde[1], MsgSchedule<16>(&w)), 3);
|
||||||
|
abcde[0] = _mm_sha1rnds4_epu32(abcde[1], _mm_sha1nexte_epu32(abcde[0], MsgSchedule<17>(&w)), 3);
|
||||||
|
abcde[1] = _mm_sha1rnds4_epu32(abcde[0], _mm_sha1nexte_epu32(abcde[1], MsgSchedule<18>(&w)), 3);
|
||||||
|
abcde[0] = _mm_sha1rnds4_epu32(abcde[1], _mm_sha1nexte_epu32(abcde[0], MsgSchedule<19>(&w)), 3);
|
||||||
|
// state += abcde
|
||||||
|
state[1] = _mm_sha1nexte_epu32(abcde[1], state[1]);
|
||||||
|
state[0] = _mm_add_epi32(abcde[0], state[0]);
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Digest GetDigest() override
|
||||||
|
{
|
||||||
|
Digest digest;
|
||||||
|
_mm_storeu_si128((__m128i*)&digest[0], byterev_16B(state[0]));
|
||||||
|
u32 hi = _mm_cvtsi128_si32(byterev_16B(state[1]));
|
||||||
|
std::memcpy(&digest[sizeof(__m128i)], &hi, sizeof(hi));
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<__m128i, 2> state{};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _M_ARM_64
|
||||||
|
|
||||||
|
// The armv8 flags are very annoying:
|
||||||
|
// clang inserts "+" prefixes itself, gcc does not.
|
||||||
|
// clang has deprecated "crypto" (removed in clang 13), gcc has not.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define TARGET_ARMV8_SHA1
|
||||||
|
#elif defined(__clang__)
|
||||||
|
#define TARGET_ARMV8_SHA1 [[gnu::target("sha2")]]
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define TARGET_ARMV8_SHA1 [[gnu::target("+crypto")]]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class ContextNeon final : public BlockContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ContextNeon()
|
||||||
|
{
|
||||||
|
state.abcd = vld1q_u32(&H[0]);
|
||||||
|
state.e = H[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
using WorkBlock = CyclicArray<uint32x4_t, 4>;
|
||||||
|
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
// ARM thought they were being clever by exposing e as u32, but it actually makes non-asm
|
||||||
|
// implementations pretty annoying/makes compiler's life needlessly difficult.
|
||||||
|
uint32x4_t abcd{};
|
||||||
|
u32 e{};
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline uint32x4_t byterev_16B(uint32x4_t x)
|
||||||
|
{
|
||||||
|
// Just rev32 with casting wrappers
|
||||||
|
return vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TARGET_ARMV8_SHA1
|
||||||
|
static inline uint32x4_t MsgSchedule(WorkBlock* wblock, size_t i)
|
||||||
|
{
|
||||||
|
auto& w = *wblock;
|
||||||
|
// Update and return this location
|
||||||
|
auto& wx = w[0 + i];
|
||||||
|
wx = vsha1su0q_u32(wx, w[1 + i], w[2 + i]);
|
||||||
|
wx = vsha1su1q_u32(wx, w[3 + i]);
|
||||||
|
return wx;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t Func>
|
||||||
|
TARGET_ARMV8_SHA1 static inline constexpr uint32x4_t f(State state, uint32x4_t w)
|
||||||
|
{
|
||||||
|
const auto wk = vaddq_u32(w, vdupq_n_u32(K[Func]));
|
||||||
|
if constexpr (Func == 0)
|
||||||
|
return vsha1cq_u32(state.abcd, state.e, wk);
|
||||||
|
if constexpr (Func == 1 || Func == 3)
|
||||||
|
return vsha1pq_u32(state.abcd, state.e, wk);
|
||||||
|
if constexpr (Func == 2)
|
||||||
|
return vsha1mq_u32(state.abcd, state.e, wk);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t Func>
|
||||||
|
TARGET_ARMV8_SHA1 static inline constexpr State FourRounds(State state, uint32x4_t w)
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// FIXME it seems the msvc optimizer gets a little too happy
|
||||||
|
_ReadBarrier();
|
||||||
|
#endif
|
||||||
|
return {f<Func>(state, w), vsha1h_u32(vgetq_lane_u32(state.abcd, 0))};
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void ProcessBlock(const u8* msg) override
|
||||||
|
{
|
||||||
|
WorkBlock w;
|
||||||
|
for (size_t i = 0; i < w.size(); i++)
|
||||||
|
w[i] = byterev_16B(vld1q_u8(&msg[sizeof(uint32x4_t) * i]));
|
||||||
|
|
||||||
|
std::array<State, 2> states{state};
|
||||||
|
|
||||||
|
// Fashioned to look like x64 impl.
|
||||||
|
// In each case the goal is to have compiler inline + unroll everything.
|
||||||
|
states[1] = FourRounds<0>(states[0], w[0]);
|
||||||
|
states[0] = FourRounds<0>(states[1], w[1]);
|
||||||
|
states[1] = FourRounds<0>(states[0], w[2]);
|
||||||
|
states[0] = FourRounds<0>(states[1], w[3]);
|
||||||
|
states[1] = FourRounds<0>(states[0], MsgSchedule(&w, 4));
|
||||||
|
states[0] = FourRounds<1>(states[1], MsgSchedule(&w, 5));
|
||||||
|
states[1] = FourRounds<1>(states[0], MsgSchedule(&w, 6));
|
||||||
|
states[0] = FourRounds<1>(states[1], MsgSchedule(&w, 7));
|
||||||
|
states[1] = FourRounds<1>(states[0], MsgSchedule(&w, 8));
|
||||||
|
states[0] = FourRounds<1>(states[1], MsgSchedule(&w, 9));
|
||||||
|
states[1] = FourRounds<2>(states[0], MsgSchedule(&w, 10));
|
||||||
|
states[0] = FourRounds<2>(states[1], MsgSchedule(&w, 11));
|
||||||
|
states[1] = FourRounds<2>(states[0], MsgSchedule(&w, 12));
|
||||||
|
states[0] = FourRounds<2>(states[1], MsgSchedule(&w, 13));
|
||||||
|
states[1] = FourRounds<2>(states[0], MsgSchedule(&w, 14));
|
||||||
|
states[0] = FourRounds<3>(states[1], MsgSchedule(&w, 15));
|
||||||
|
states[1] = FourRounds<3>(states[0], MsgSchedule(&w, 16));
|
||||||
|
states[0] = FourRounds<3>(states[1], MsgSchedule(&w, 17));
|
||||||
|
states[1] = FourRounds<3>(states[0], MsgSchedule(&w, 18));
|
||||||
|
states[0] = FourRounds<3>(states[1], MsgSchedule(&w, 19));
|
||||||
|
|
||||||
|
state = {vaddq_u32(state.abcd, states[0].abcd), state.e + states[0].e};
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Digest GetDigest() override
|
||||||
|
{
|
||||||
|
Digest digest;
|
||||||
|
vst1q_u8(&digest[0], byterev_16B(state.abcd));
|
||||||
|
u32 e = Common::FromBigEndian(state.e);
|
||||||
|
std::memcpy(&digest[sizeof(state.abcd)], &e, sizeof(e));
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
State state;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::unique_ptr<Context> CreateContext()
|
||||||
|
{
|
||||||
|
if (cpu_info.bSHA1)
|
||||||
|
{
|
||||||
|
#ifdef _M_X86_64
|
||||||
|
// Note: As of mid 2022, > 99% of CPUs reporting to Steam survey have SSSE3, ~40% have SHA.
|
||||||
|
// Seems unlikely we'll see any cpus supporting SHA but not SSSE3 (in the foreseeable future at
|
||||||
|
// least).
|
||||||
|
if (cpu_info.bSSSE3)
|
||||||
|
return std::make_unique<ContextX64SHA1>();
|
||||||
|
#elif defined(_M_ARM_64)
|
||||||
|
return std::make_unique<ContextNeon>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return std::make_unique<ContextMbed>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Digest CalculateDigest(const u8* msg, size_t len)
|
||||||
|
{
|
||||||
|
auto ctx = CreateContext();
|
||||||
|
ctx->Update(msg, len);
|
||||||
|
return ctx->Finish();
|
||||||
|
}
|
||||||
|
} // namespace Common::SHA1
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
namespace Common::SHA1
|
||||||
|
{
|
||||||
|
using Digest = std::array<u8, 160 / 8>;
|
||||||
|
static constexpr size_t DIGEST_LEN = sizeof(Digest);
|
||||||
|
|
||||||
|
class Context
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Context() = default;
|
||||||
|
virtual void Update(const u8* msg, size_t len) = 0;
|
||||||
|
void Update(const std::vector<u8>& msg) { return Update(msg.data(), msg.size()); }
|
||||||
|
virtual Digest Finish() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Context> CreateContext();
|
||||||
|
|
||||||
|
Digest CalculateDigest(const u8* msg, size_t len);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline Digest CalculateDigest(const std::vector<T>& msg)
|
||||||
|
{
|
||||||
|
static_assert(std::is_trivially_copyable_v<T>);
|
||||||
|
ASSERT(std::numeric_limits<size_t>::max() / sizeof(T) >= msg.size());
|
||||||
|
return CalculateDigest(reinterpret_cast<const u8*>(msg.data()), sizeof(T) * msg.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Digest CalculateDigest(const std::string_view& msg)
|
||||||
|
{
|
||||||
|
return CalculateDigest(reinterpret_cast<const u8*>(msg.data()), msg.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t Size>
|
||||||
|
inline Digest CalculateDigest(const std::array<T, Size>& msg)
|
||||||
|
{
|
||||||
|
static_assert(std::is_trivially_copyable_v<T>);
|
||||||
|
return CalculateDigest(reinterpret_cast<const u8*>(msg.data()), sizeof(msg));
|
||||||
|
}
|
||||||
|
} // namespace Common::SHA1
|
|
@ -10,7 +10,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
@ -25,6 +24,7 @@
|
||||||
#include "Common/CPUDetect.h"
|
#include "Common/CPUDetect.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Config/Config.h"
|
#include "Common/Config/Config.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/Random.h"
|
#include "Common/Random.h"
|
||||||
#include "Common/Timer.h"
|
#include "Common/Timer.h"
|
||||||
#include "Common/Version.h"
|
#include "Common/Version.h"
|
||||||
|
@ -100,9 +100,8 @@ void DolphinAnalytics::GenerateNewIdentity()
|
||||||
|
|
||||||
std::string DolphinAnalytics::MakeUniqueId(std::string_view data) const
|
std::string DolphinAnalytics::MakeUniqueId(std::string_view data) const
|
||||||
{
|
{
|
||||||
std::array<u8, 20> digest;
|
|
||||||
const auto input = std::string{m_unique_id}.append(data);
|
const auto input = std::string{m_unique_id}.append(data);
|
||||||
mbedtls_sha1_ret(reinterpret_cast<const u8*>(input.c_str()), input.size(), digest.data());
|
const auto digest = Common::SHA1::CalculateDigest(input);
|
||||||
|
|
||||||
// Convert to hex string and truncate to 64 bits.
|
// Convert to hex string and truncate to 64 bits.
|
||||||
std::string out;
|
std::string out;
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
#include "Core/HW/GBACore.h"
|
#include "Core/HW/GBACore.h"
|
||||||
|
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#define PYCPARSE // Remove static functions from the header
|
#define PYCPARSE // Remove static functions from the header
|
||||||
#include <mgba/core/interface.h>
|
#include <mgba/core/interface.h>
|
||||||
#undef PYCPARSE
|
#undef PYCPARSE
|
||||||
|
@ -20,6 +18,7 @@
|
||||||
#include "Common/CommonPaths.h"
|
#include "Common/CommonPaths.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Config/Config.h"
|
#include "Common/Config/Config.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/IOFile.h"
|
#include "Common/IOFile.h"
|
||||||
#include "Common/MinizipUtil.h"
|
#include "Common/MinizipUtil.h"
|
||||||
|
@ -143,11 +142,10 @@ static std::array<u8, 20> GetROMHash(VFile* rom)
|
||||||
size_t size = rom->size(rom);
|
size_t size = rom->size(rom);
|
||||||
u8* buffer = static_cast<u8*>(rom->map(rom, size, MAP_READ));
|
u8* buffer = static_cast<u8*>(rom->map(rom, size, MAP_READ));
|
||||||
|
|
||||||
std::array<u8, 20> hash;
|
const auto digest = Common::SHA1::CalculateDigest(buffer, size);
|
||||||
mbedtls_sha1_ret(buffer, size, hash.data());
|
|
||||||
rom->unmap(rom, buffer, size);
|
rom->unmap(rom, buffer, size);
|
||||||
|
|
||||||
return hash;
|
return digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::Core(int device_number) : m_device_number(device_number)
|
Core::Core(int device_number) : m_device_number(device_number)
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <mbedtls/md5.h>
|
#include <mbedtls/md5.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -24,6 +23,7 @@
|
||||||
|
|
||||||
#include "Common/Align.h"
|
#include "Common/Align.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/Crypto/ec.h"
|
#include "Common/Crypto/ec.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/IOFile.h"
|
#include "Common/IOFile.h"
|
||||||
|
@ -439,14 +439,14 @@ private:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Read data to sign.
|
// Read data to sign.
|
||||||
std::array<u8, 20> data_sha1;
|
Common::SHA1::Digest data_sha1;
|
||||||
{
|
{
|
||||||
const u32 data_size = bk_header->size_of_files + sizeof(BkHeader);
|
const u32 data_size = bk_header->size_of_files + sizeof(BkHeader);
|
||||||
auto data = std::make_unique<u8[]>(data_size);
|
auto data = std::make_unique<u8[]>(data_size);
|
||||||
m_file.Seek(sizeof(Header), File::SeekOrigin::Begin);
|
m_file.Seek(sizeof(Header), File::SeekOrigin::Begin);
|
||||||
if (!m_file.ReadBytes(data.get(), data_size))
|
if (!m_file.ReadBytes(data.get(), data_size))
|
||||||
return false;
|
return false;
|
||||||
mbedtls_sha1_ret(data.get(), data_size, data_sha1.data());
|
data_sha1 = Common::SHA1::CalculateDigest(data.get(), data_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign the data.
|
// Sign the data.
|
||||||
|
|
|
@ -14,11 +14,11 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/NandPaths.h"
|
#include "Common/NandPaths.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
@ -109,10 +109,8 @@ static size_t GetIssuerOffset(SignatureType signature_type)
|
||||||
|
|
||||||
std::array<u8, 20> SignedBlobReader::GetSha1() const
|
std::array<u8, 20> SignedBlobReader::GetSha1() const
|
||||||
{
|
{
|
||||||
std::array<u8, 20> sha1;
|
|
||||||
const size_t skip = GetIssuerOffset(GetSignatureType());
|
const size_t skip = GetIssuerOffset(GetSignatureType());
|
||||||
mbedtls_sha1_ret(m_bytes.data() + skip, m_bytes.size() - skip, sha1.data());
|
return Common::SHA1::CalculateDigest(m_bytes.data() + skip, m_bytes.size() - skip);
|
||||||
return sha1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SignedBlobReader::IsSignatureValid() const
|
bool SignedBlobReader::IsSignatureValid() const
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <mbedtls/sha1.h>
|
#include "Common/Crypto/SHA1.h"
|
||||||
|
|
||||||
#include "Common/Crypto/ec.h"
|
#include "Common/Crypto/ec.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/ScopeGuard.h"
|
#include "Common/ScopeGuard.h"
|
||||||
|
@ -171,9 +170,8 @@ ReturnCode ESDevice::VerifySign(const std::vector<u8>& hash, const std::vector<u
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<u8, 20> sha1;
|
const auto hash_digest = Common::SHA1::CalculateDigest(hash);
|
||||||
mbedtls_sha1_ret(hash.data(), hash.size(), sha1.data());
|
ret = iosc.VerifyPublicKeySign(hash_digest, ap_cert, ecc_signature, PID_ES);
|
||||||
ret = iosc.VerifyPublicKeySign(sha1, ap_cert, ecc_signature, PID_ES);
|
|
||||||
if (ret != IPC_SUCCESS)
|
if (ret != IPC_SUCCESS)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(IOS_ES, "VerifySign: IOSC_VerifyPublicKeySign(data) failed with error {}", ret);
|
ERROR_LOG_FMT(IOS_ES, "VerifySign: IOSC_VerifyPublicKeySign(data) failed with error {}", ret);
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/NandPaths.h"
|
#include "Common/NandPaths.h"
|
||||||
#include "Common/ScopeGuard.h"
|
#include "Common/ScopeGuard.h"
|
||||||
|
@ -197,9 +197,7 @@ ESDevice::GetStoredContentsFromTMD(const ES::TMDReader& tmd,
|
||||||
std::vector<u8> content_data(file->GetStatus()->size);
|
std::vector<u8> content_data(file->GetStatus()->size);
|
||||||
if (!file->Read(content_data.data(), content_data.size()))
|
if (!file->Read(content_data.data(), content_data.size()))
|
||||||
return false;
|
return false;
|
||||||
std::array<u8, 20> sha1{};
|
return Common::SHA1::CalculateDigest(content_data) == content.sha1;
|
||||||
mbedtls_sha1_ret(content_data.data(), content_data.size(), sha1.data());
|
|
||||||
return sha1 == content.sha1;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return stored_contents;
|
return stored_contents;
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/Align.h"
|
#include "Common/Align.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/NandPaths.h"
|
#include "Common/NandPaths.h"
|
||||||
#include "Core/CommonTitles.h"
|
#include "Core/CommonTitles.h"
|
||||||
|
@ -353,9 +353,7 @@ IPCReply ESDevice::ImportContentData(Context& context, const IOCtlVRequest& requ
|
||||||
|
|
||||||
static bool CheckIfContentHashMatches(const std::vector<u8>& content, const ES::Content& info)
|
static bool CheckIfContentHashMatches(const std::vector<u8>& content, const ES::Content& info)
|
||||||
{
|
{
|
||||||
std::array<u8, 20> sha1;
|
return Common::SHA1::CalculateDigest(content.data(), info.size) == info.sha1;
|
||||||
mbedtls_sha1_ret(content.data(), info.size, sha1.data());
|
|
||||||
return sha1 == info.sha1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetImportContentPath(u64 title_id, u32 content_id)
|
static std::string GetImportContentPath(u64 title_id, u32 content_id)
|
||||||
|
|
|
@ -14,11 +14,11 @@
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <mbedtls/md.h>
|
#include <mbedtls/md.h>
|
||||||
#include <mbedtls/rsa.h>
|
#include <mbedtls/rsa.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/Crypto/AES.h"
|
#include "Common/Crypto/AES.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/Crypto/ec.h"
|
#include "Common/Crypto/ec.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/IOFile.h"
|
#include "Common/IOFile.h"
|
||||||
|
@ -249,8 +249,7 @@ ReturnCode IOSC::ComputeSharedKey(Handle dest_handle, Handle private_handle, Han
|
||||||
const std::array<u8, 0x3c> shared_secret =
|
const std::array<u8, 0x3c> shared_secret =
|
||||||
Common::ec::ComputeSharedSecret(private_entry->data.data(), public_entry->data.data());
|
Common::ec::ComputeSharedSecret(private_entry->data.data(), public_entry->data.data());
|
||||||
|
|
||||||
std::array<u8, 20> sha1;
|
const auto sha1 = Common::SHA1::CalculateDigest(shared_secret.data(), shared_secret.size() / 2);
|
||||||
mbedtls_sha1_ret(shared_secret.data(), shared_secret.size() / 2, sha1.data());
|
|
||||||
|
|
||||||
dest_entry->data.resize(AES128_KEY_SIZE);
|
dest_entry->data.resize(AES128_KEY_SIZE);
|
||||||
std::copy_n(sha1.cbegin(), AES128_KEY_SIZE, dest_entry->data.begin());
|
std::copy_n(sha1.cbegin(), AES128_KEY_SIZE, dest_entry->data.begin());
|
||||||
|
@ -437,7 +436,6 @@ CertECC IOSC::GetDeviceCertificate() const
|
||||||
|
|
||||||
void IOSC::Sign(u8* sig_out, u8* ap_cert_out, u64 title_id, const u8* data, u32 data_size) const
|
void IOSC::Sign(u8* sig_out, u8* ap_cert_out, u64 title_id, const u8* data, u32 data_size) const
|
||||||
{
|
{
|
||||||
std::array<u8, 20> hash{};
|
|
||||||
std::array<u8, 30> ap_priv{};
|
std::array<u8, 30> ap_priv{};
|
||||||
|
|
||||||
ap_priv[0x1d] = 1;
|
ap_priv[0x1d] = 1;
|
||||||
|
@ -451,13 +449,15 @@ void IOSC::Sign(u8* sig_out, u8* ap_cert_out, u64 title_id, const u8* data, u32
|
||||||
CertECC cert = MakeBlankEccCert(signer, name, ap_priv.data(), 0);
|
CertECC cert = MakeBlankEccCert(signer, name, ap_priv.data(), 0);
|
||||||
// Sign the AP cert.
|
// Sign the AP cert.
|
||||||
const size_t skip = offsetof(CertECC, signature.issuer);
|
const size_t skip = offsetof(CertECC, signature.issuer);
|
||||||
mbedtls_sha1_ret(reinterpret_cast<const u8*>(&cert) + skip, sizeof(cert) - skip, hash.data());
|
const auto ap_cert_digest =
|
||||||
cert.signature.sig = Common::ec::Sign(m_key_entries[HANDLE_CONSOLE_KEY].data.data(), hash.data());
|
Common::SHA1::CalculateDigest(reinterpret_cast<const u8*>(&cert) + skip, sizeof(cert) - skip);
|
||||||
|
cert.signature.sig =
|
||||||
|
Common::ec::Sign(m_key_entries[HANDLE_CONSOLE_KEY].data.data(), ap_cert_digest.data());
|
||||||
std::memcpy(ap_cert_out, &cert, sizeof(cert));
|
std::memcpy(ap_cert_out, &cert, sizeof(cert));
|
||||||
|
|
||||||
// Sign the data.
|
// Sign the data.
|
||||||
mbedtls_sha1_ret(data, data_size, hash.data());
|
const auto data_digest = Common::SHA1::CalculateDigest(data, data_size);
|
||||||
const auto signature = Common::ec::Sign(ap_priv.data(), hash.data());
|
const auto signature = Common::ec::Sign(ap_priv.data(), data_digest.data());
|
||||||
std::copy(signature.cbegin(), signature.cend(), sig_out);
|
std::copy(signature.cbegin(), signature.cend(), sig_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,8 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
#include "Core/IOS/ES/Formats.h"
|
#include "Core/IOS/ES/Formats.h"
|
||||||
|
@ -33,21 +32,21 @@ const IOS::ES::TMDReader Volume::INVALID_TMD{};
|
||||||
const std::vector<u8> Volume::INVALID_CERT_CHAIN{};
|
const std::vector<u8> Volume::INVALID_CERT_CHAIN{};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void AddToSyncHash(mbedtls_sha1_context* context, const T& data)
|
static void AddToSyncHash(Common::SHA1::Context* context, const T& data)
|
||||||
{
|
{
|
||||||
static_assert(std::is_trivially_copyable_v<T>);
|
static_assert(std::is_trivially_copyable_v<T>);
|
||||||
mbedtls_sha1_update_ret(context, reinterpret_cast<const u8*>(&data), sizeof(data));
|
context->Update(reinterpret_cast<const u8*>(&data), sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Volume::ReadAndAddToSyncHash(mbedtls_sha1_context* context, u64 offset, u64 length,
|
void Volume::ReadAndAddToSyncHash(Common::SHA1::Context* context, u64 offset, u64 length,
|
||||||
const Partition& partition) const
|
const Partition& partition) const
|
||||||
{
|
{
|
||||||
std::vector<u8> buffer(length);
|
std::vector<u8> buffer(length);
|
||||||
if (Read(offset, length, buffer.data(), partition))
|
if (Read(offset, length, buffer.data(), partition))
|
||||||
mbedtls_sha1_update_ret(context, buffer.data(), buffer.size());
|
context->Update(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Volume::AddTMDToSyncHash(mbedtls_sha1_context* context, const Partition& partition) const
|
void Volume::AddTMDToSyncHash(Common::SHA1::Context* context, const Partition& partition) const
|
||||||
{
|
{
|
||||||
// We want to hash some important parts of the TMD, but nothing that changes when fakesigning.
|
// We want to hash some important parts of the TMD, but nothing that changes when fakesigning.
|
||||||
// (Fakesigned WADs are very popular, and we don't want people with properly signed WADs to
|
// (Fakesigned WADs are very popular, and we don't want people with properly signed WADs to
|
||||||
|
|
|
@ -11,9 +11,8 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Common/Swap.h"
|
#include "Common/Swap.h"
|
||||||
#include "Core/IOS/ES/Formats.h"
|
#include "Core/IOS/ES/Formats.h"
|
||||||
|
@ -164,9 +163,9 @@ protected:
|
||||||
return CP1252ToUTF8(string);
|
return CP1252ToUTF8(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadAndAddToSyncHash(mbedtls_sha1_context* context, u64 offset, u64 length,
|
void ReadAndAddToSyncHash(Common::SHA1::Context* context, u64 offset, u64 length,
|
||||||
const Partition& partition) const;
|
const Partition& partition) const;
|
||||||
void AddTMDToSyncHash(mbedtls_sha1_context* context, const Partition& partition) const;
|
void AddTMDToSyncHash(Common::SHA1::Context* context, const Partition& partition) const;
|
||||||
|
|
||||||
virtual u32 GetOffsetShift() const { return 0; }
|
virtual u32 GetOffsetShift() const { return 0; }
|
||||||
static std::map<Language, std::string> ReadWiiNames(const std::vector<char16_t>& data);
|
static std::map<Language, std::string> ReadWiiNames(const std::vector<char16_t>& data);
|
||||||
|
|
|
@ -8,9 +8,8 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "DiscIO/DiscUtils.h"
|
#include "DiscIO/DiscUtils.h"
|
||||||
#include "DiscIO/Enums.h"
|
#include "DiscIO/Enums.h"
|
||||||
#include "DiscIO/Filesystem.h"
|
#include "DiscIO/Filesystem.h"
|
||||||
|
@ -95,7 +94,7 @@ bool VolumeDisc::IsNKit() const
|
||||||
return ReadSwapped<u32>(0x200, PARTITION_NONE) == NKIT_MAGIC;
|
return ReadSwapped<u32>(0x200, PARTITION_NONE) == NKIT_MAGIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolumeDisc::AddGamePartitionToSyncHash(mbedtls_sha1_context* context) const
|
void VolumeDisc::AddGamePartitionToSyncHash(Common::SHA1::Context* context) const
|
||||||
{
|
{
|
||||||
const Partition partition = GetGamePartition();
|
const Partition partition = GetGamePartition();
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,8 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "DiscIO/Volume.h"
|
#include "DiscIO/Volume.h"
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
|
@ -27,7 +26,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Region RegionCodeToRegion(std::optional<u32> region_code) const;
|
Region RegionCodeToRegion(std::optional<u32> region_code) const;
|
||||||
void AddGamePartitionToSyncHash(mbedtls_sha1_context* context) const;
|
void AddGamePartitionToSyncHash(Common::SHA1::Context* context) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace DiscIO
|
} // namespace DiscIO
|
||||||
|
|
|
@ -11,11 +11,10 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/ColorUtil.h"
|
#include "Common/ColorUtil.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
@ -152,15 +151,11 @@ bool VolumeGC::IsDatelDisc() const
|
||||||
|
|
||||||
std::array<u8, 20> VolumeGC::GetSyncHash() const
|
std::array<u8, 20> VolumeGC::GetSyncHash() const
|
||||||
{
|
{
|
||||||
mbedtls_sha1_context context;
|
auto context = Common::SHA1::CreateContext();
|
||||||
mbedtls_sha1_init(&context);
|
|
||||||
mbedtls_sha1_starts_ret(&context);
|
|
||||||
|
|
||||||
AddGamePartitionToSyncHash(&context);
|
AddGamePartitionToSyncHash(context.get());
|
||||||
|
|
||||||
std::array<u8, 20> hash;
|
return context->Finish();
|
||||||
mbedtls_sha1_finish_ret(&context, hash.data());
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VolumeGC::ConvertedGCBanner VolumeGC::LoadBannerFile() const
|
VolumeGC::ConvertedGCBanner VolumeGC::LoadBannerFile() const
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <mbedtls/md5.h>
|
#include <mbedtls/md5.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
#include <mz_compat.h>
|
#include <mz_compat.h>
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
|
|
||||||
|
@ -21,6 +20,7 @@
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonPaths.h"
|
#include "Common/CommonPaths.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/Hash.h"
|
#include "Common/Hash.h"
|
||||||
#include "Common/HttpRequest.h"
|
#include "Common/HttpRequest.h"
|
||||||
|
@ -1053,8 +1053,7 @@ void VolumeVerifier::SetUpHashing()
|
||||||
|
|
||||||
if (m_hashes_to_calculate.sha1)
|
if (m_hashes_to_calculate.sha1)
|
||||||
{
|
{
|
||||||
mbedtls_sha1_init(&m_sha1_context);
|
m_sha1_context = Common::SHA1::CreateContext();
|
||||||
mbedtls_sha1_starts_ret(&m_sha1_context);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1191,7 +1190,7 @@ void VolumeVerifier::Process()
|
||||||
if (m_hashes_to_calculate.sha1)
|
if (m_hashes_to_calculate.sha1)
|
||||||
{
|
{
|
||||||
m_sha1_future = std::async(std::launch::async, [this, byte_increment] {
|
m_sha1_future = std::async(std::launch::async, [this, byte_increment] {
|
||||||
mbedtls_sha1_update_ret(&m_sha1_context, m_data.data(), byte_increment);
|
m_sha1_context->Update(m_data.data(), byte_increment);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1283,8 +1282,8 @@ void VolumeVerifier::Finish()
|
||||||
|
|
||||||
if (m_hashes_to_calculate.sha1)
|
if (m_hashes_to_calculate.sha1)
|
||||||
{
|
{
|
||||||
m_result.hashes.sha1 = std::vector<u8>(20);
|
const auto digest = m_sha1_context->Finish();
|
||||||
mbedtls_sha1_finish_ret(&m_sha1_context, m_result.hashes.sha1.data());
|
m_result.hashes.sha1 = std::vector<u8>(digest.begin(), digest.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,15 @@
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <mbedtls/md5.h>
|
#include <mbedtls/md5.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Core/IOS/ES/Formats.h"
|
#include "Core/IOS/ES/Formats.h"
|
||||||
#include "DiscIO/DiscScrubber.h"
|
#include "DiscIO/DiscScrubber.h"
|
||||||
#include "DiscIO/Volume.h"
|
#include "DiscIO/Volume.h"
|
||||||
|
@ -174,7 +175,7 @@ private:
|
||||||
bool m_calculating_any_hash = false;
|
bool m_calculating_any_hash = false;
|
||||||
u32 m_crc32_context = 0;
|
u32 m_crc32_context = 0;
|
||||||
mbedtls_md5_context m_md5_context{};
|
mbedtls_md5_context m_md5_context{};
|
||||||
mbedtls_sha1_context m_sha1_context{};
|
std::unique_ptr<Common::SHA1::Context> m_sha1_context;
|
||||||
|
|
||||||
u64 m_excess_bytes = 0;
|
u64 m_excess_bytes = 0;
|
||||||
std::vector<u8> m_data;
|
std::vector<u8> m_data;
|
||||||
|
|
|
@ -14,11 +14,11 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <mbedtls/aes.h>
|
#include <mbedtls/aes.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/Align.h"
|
#include "Common/Align.h"
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
@ -171,9 +171,7 @@ bool VolumeWAD::CheckContentIntegrity(const IOS::ES::Content& content,
|
||||||
mbedtls_aes_crypt_cbc(&context, MBEDTLS_AES_DECRYPT, decrypted_data.size(), iv.data(),
|
mbedtls_aes_crypt_cbc(&context, MBEDTLS_AES_DECRYPT, decrypted_data.size(), iv.data(),
|
||||||
encrypted_data.data(), decrypted_data.data());
|
encrypted_data.data(), decrypted_data.data());
|
||||||
|
|
||||||
std::array<u8, 20> sha1;
|
return Common::SHA1::CalculateDigest(decrypted_data.data(), content.size) == content.sha1;
|
||||||
mbedtls_sha1_ret(decrypted_data.data(), content.size, sha1.data());
|
|
||||||
return sha1 == content.sha1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VolumeWAD::CheckContentIntegrity(const IOS::ES::Content& content, u64 content_offset,
|
bool VolumeWAD::CheckContentIntegrity(const IOS::ES::Content& content, u64 content_offset,
|
||||||
|
@ -349,17 +347,13 @@ std::array<u8, 20> VolumeWAD::GetSyncHash() const
|
||||||
// We can skip hashing the contents since the TMD contains hashes of the contents.
|
// We can skip hashing the contents since the TMD contains hashes of the contents.
|
||||||
// We specifically don't hash the ticket, since its console ID can differ without any problems.
|
// We specifically don't hash the ticket, since its console ID can differ without any problems.
|
||||||
|
|
||||||
mbedtls_sha1_context context;
|
auto context = Common::SHA1::CreateContext();
|
||||||
mbedtls_sha1_init(&context);
|
|
||||||
mbedtls_sha1_starts_ret(&context);
|
|
||||||
|
|
||||||
AddTMDToSyncHash(&context, PARTITION_NONE);
|
AddTMDToSyncHash(context.get(), PARTITION_NONE);
|
||||||
|
|
||||||
ReadAndAddToSyncHash(&context, m_opening_bnr_offset, m_opening_bnr_size, PARTITION_NONE);
|
ReadAndAddToSyncHash(context.get(), m_opening_bnr_offset, m_opening_bnr_size, PARTITION_NONE);
|
||||||
|
|
||||||
std::array<u8, 20> hash;
|
return context->Finish();
|
||||||
mbedtls_sha1_finish_ret(&context, hash.data());
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace DiscIO
|
} // namespace DiscIO
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <mbedtls/aes.h>
|
#include <mbedtls/aes.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
|
|
||||||
#include "Common/Align.h"
|
#include "Common/Align.h"
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/Swap.h"
|
#include "Common/Swap.h"
|
||||||
|
|
||||||
|
@ -366,29 +366,25 @@ const BlobReader& VolumeWii::GetBlobReader() const
|
||||||
|
|
||||||
std::array<u8, 20> VolumeWii::GetSyncHash() const
|
std::array<u8, 20> VolumeWii::GetSyncHash() const
|
||||||
{
|
{
|
||||||
mbedtls_sha1_context context;
|
auto context = Common::SHA1::CreateContext();
|
||||||
mbedtls_sha1_init(&context);
|
|
||||||
mbedtls_sha1_starts_ret(&context);
|
|
||||||
|
|
||||||
// Disc header
|
// Disc header
|
||||||
ReadAndAddToSyncHash(&context, 0, 0x80, PARTITION_NONE);
|
ReadAndAddToSyncHash(context.get(), 0, 0x80, PARTITION_NONE);
|
||||||
|
|
||||||
// Region code
|
// Region code
|
||||||
ReadAndAddToSyncHash(&context, 0x4E000, 4, PARTITION_NONE);
|
ReadAndAddToSyncHash(context.get(), 0x4E000, 4, PARTITION_NONE);
|
||||||
|
|
||||||
// The data offset of the game partition - an important factor for disc drive timings
|
// The data offset of the game partition - an important factor for disc drive timings
|
||||||
const u64 data_offset = PartitionOffsetToRawOffset(0, GetGamePartition());
|
const u64 data_offset = PartitionOffsetToRawOffset(0, GetGamePartition());
|
||||||
mbedtls_sha1_update_ret(&context, reinterpret_cast<const u8*>(&data_offset), sizeof(data_offset));
|
context->Update(reinterpret_cast<const u8*>(&data_offset), sizeof(data_offset));
|
||||||
|
|
||||||
// TMD
|
// TMD
|
||||||
AddTMDToSyncHash(&context, GetGamePartition());
|
AddTMDToSyncHash(context.get(), GetGamePartition());
|
||||||
|
|
||||||
// Game partition contents
|
// Game partition contents
|
||||||
AddGamePartitionToSyncHash(&context);
|
AddGamePartitionToSyncHash(context.get());
|
||||||
|
|
||||||
std::array<u8, 20> hash;
|
return context->Finish();
|
||||||
mbedtls_sha1_finish_ret(&context, hash.data());
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VolumeWii::CheckH3TableIntegrity(const Partition& partition) const
|
bool VolumeWii::CheckH3TableIntegrity(const Partition& partition) const
|
||||||
|
@ -410,9 +406,7 @@ bool VolumeWii::CheckH3TableIntegrity(const Partition& partition) const
|
||||||
if (contents.size() != 1)
|
if (contents.size() != 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::array<u8, 20> h3_table_sha1;
|
return Common::SHA1::CalculateDigest(h3_table) == contents[0].sha1;
|
||||||
mbedtls_sha1_ret(h3_table.data(), h3_table.size(), h3_table_sha1.data());
|
|
||||||
return h3_table_sha1 == contents[0].sha1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VolumeWii::CheckBlockIntegrity(u64 block_index, const u8* encrypted_data,
|
bool VolumeWii::CheckBlockIntegrity(u64 block_index, const u8* encrypted_data,
|
||||||
|
@ -423,7 +417,8 @@ bool VolumeWii::CheckBlockIntegrity(u64 block_index, const u8* encrypted_data,
|
||||||
return false;
|
return false;
|
||||||
const PartitionDetails& partition_details = it->second;
|
const PartitionDetails& partition_details = it->second;
|
||||||
|
|
||||||
if (block_index / BLOCKS_PER_GROUP * SHA1_SIZE >= partition_details.h3_table->size())
|
if (block_index / BLOCKS_PER_GROUP * Common::SHA1::DIGEST_LEN >=
|
||||||
|
partition_details.h3_table->size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
mbedtls_aes_context* aes_context = partition_details.key->get();
|
mbedtls_aes_context* aes_context = partition_details.key->get();
|
||||||
|
@ -438,25 +433,22 @@ bool VolumeWii::CheckBlockIntegrity(u64 block_index, const u8* encrypted_data,
|
||||||
|
|
||||||
for (u32 hash_index = 0; hash_index < 31; ++hash_index)
|
for (u32 hash_index = 0; hash_index < 31; ++hash_index)
|
||||||
{
|
{
|
||||||
u8 h0_hash[SHA1_SIZE];
|
if (Common::SHA1::CalculateDigest(cluster_data + hash_index * 0x400, 0x400) !=
|
||||||
mbedtls_sha1_ret(cluster_data + hash_index * 0x400, 0x400, h0_hash);
|
hashes.h0[hash_index])
|
||||||
if (memcmp(h0_hash, hashes.h0[hash_index], SHA1_SIZE))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 h1_hash[SHA1_SIZE];
|
if (Common::SHA1::CalculateDigest(hashes.h0) != hashes.h1[block_index % 8])
|
||||||
mbedtls_sha1_ret(reinterpret_cast<u8*>(hashes.h0), sizeof(hashes.h0), h1_hash);
|
|
||||||
if (memcmp(h1_hash, hashes.h1[block_index % 8], SHA1_SIZE))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
u8 h2_hash[SHA1_SIZE];
|
if (Common::SHA1::CalculateDigest(hashes.h1) != hashes.h2[block_index / 8 % 8])
|
||||||
mbedtls_sha1_ret(reinterpret_cast<u8*>(hashes.h1), sizeof(hashes.h1), h2_hash);
|
|
||||||
if (memcmp(h2_hash, hashes.h2[block_index / 8 % 8], SHA1_SIZE))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
u8 h3_hash[SHA1_SIZE];
|
Common::SHA1::Digest h3_digest;
|
||||||
mbedtls_sha1_ret(reinterpret_cast<u8*>(hashes.h2), sizeof(hashes.h2), h3_hash);
|
auto h3_digest_ptr =
|
||||||
if (memcmp(h3_hash, partition_details.h3_table->data() + block_index / 64 * SHA1_SIZE, SHA1_SIZE))
|
partition_details.h3_table->data() + block_index / 64 * Common::SHA1::DIGEST_LEN;
|
||||||
|
memcpy(h3_digest.data(), h3_digest_ptr, sizeof(h3_digest));
|
||||||
|
if (Common::SHA1::CalculateDigest(hashes.h2) != h3_digest)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -496,14 +488,13 @@ bool VolumeWii::HashGroup(const std::array<u8, BLOCK_DATA_SIZE> in[BLOCKS_PER_GR
|
||||||
{
|
{
|
||||||
// H0 hashes
|
// H0 hashes
|
||||||
for (size_t j = 0; j < 31; ++j)
|
for (size_t j = 0; j < 31; ++j)
|
||||||
mbedtls_sha1_ret(in[i].data() + j * 0x400, 0x400, out[i].h0[j]);
|
out[i].h0[j] = Common::SHA1::CalculateDigest(in[i].data() + j * 0x400, 0x400);
|
||||||
|
|
||||||
// H0 padding
|
// H0 padding
|
||||||
std::memset(out[i].padding_0, 0, sizeof(HashBlock::padding_0));
|
out[i].padding_0 = {};
|
||||||
|
|
||||||
// H1 hash
|
// H1 hash
|
||||||
mbedtls_sha1_ret(reinterpret_cast<u8*>(out[i].h0), sizeof(HashBlock::h0),
|
out[h1_base].h1[i - h1_base] = Common::SHA1::CalculateDigest(out[i].h0);
|
||||||
out[h1_base].h1[i - h1_base]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i % 8 == 7)
|
if (i % 8 == 7)
|
||||||
|
@ -514,15 +505,14 @@ bool VolumeWii::HashGroup(const std::array<u8, BLOCK_DATA_SIZE> in[BLOCKS_PER_GR
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
// H1 padding
|
// H1 padding
|
||||||
std::memset(out[h1_base].padding_1, 0, sizeof(HashBlock::padding_1));
|
out[h1_base].padding_1 = {};
|
||||||
|
|
||||||
// H1 copies
|
// H1 copies
|
||||||
for (size_t j = 1; j < 8; ++j)
|
for (size_t j = 1; j < 8; ++j)
|
||||||
std::memcpy(out[h1_base + j].h1, out[h1_base].h1, sizeof(HashBlock::h1));
|
out[h1_base + j].h1 = out[h1_base].h1;
|
||||||
|
|
||||||
// H2 hash
|
// H2 hash
|
||||||
mbedtls_sha1_ret(reinterpret_cast<u8*>(out[i].h1), sizeof(HashBlock::h1),
|
out[0].h2[h1_base / 8] = Common::SHA1::CalculateDigest(out[i].h1);
|
||||||
out[0].h2[h1_base / 8]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == BLOCKS_PER_GROUP - 1)
|
if (i == BLOCKS_PER_GROUP - 1)
|
||||||
|
@ -533,11 +523,11 @@ bool VolumeWii::HashGroup(const std::array<u8, BLOCK_DATA_SIZE> in[BLOCKS_PER_GR
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
// H2 padding
|
// H2 padding
|
||||||
std::memset(out[0].padding_2, 0, sizeof(HashBlock::padding_2));
|
out[0].padding_2 = {};
|
||||||
|
|
||||||
// H2 copies
|
// H2 copies
|
||||||
for (size_t j = 1; j < BLOCKS_PER_GROUP; ++j)
|
for (size_t j = 1; j < BLOCKS_PER_GROUP; ++j)
|
||||||
std::memcpy(out[j].h2, out[0].h2, sizeof(HashBlock::h2));
|
out[j].h2 = out[0].h2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <mbedtls/aes.h>
|
#include <mbedtls/aes.h>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/Lazy.h"
|
#include "Common/Lazy.h"
|
||||||
#include "Core/IOS/ES/Formats.h"
|
#include "Core/IOS/ES/Formats.h"
|
||||||
#include "DiscIO/Filesystem.h"
|
#include "DiscIO/Filesystem.h"
|
||||||
|
@ -34,7 +35,6 @@ class VolumeWii : public VolumeDisc
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static constexpr size_t AES_KEY_SIZE = 16;
|
static constexpr size_t AES_KEY_SIZE = 16;
|
||||||
static constexpr size_t SHA1_SIZE = 20;
|
|
||||||
|
|
||||||
static constexpr u32 BLOCKS_PER_GROUP = 0x40;
|
static constexpr u32 BLOCKS_PER_GROUP = 0x40;
|
||||||
|
|
||||||
|
@ -48,12 +48,12 @@ public:
|
||||||
|
|
||||||
struct HashBlock
|
struct HashBlock
|
||||||
{
|
{
|
||||||
u8 h0[31][SHA1_SIZE];
|
std::array<Common::SHA1::Digest, 31> h0;
|
||||||
u8 padding_0[20];
|
std::array<u8, 20> padding_0;
|
||||||
u8 h1[8][SHA1_SIZE];
|
std::array<Common::SHA1::Digest, 8> h1;
|
||||||
u8 padding_1[32];
|
std::array<u8, 32> padding_1;
|
||||||
u8 h2[8][SHA1_SIZE];
|
std::array<Common::SHA1::Digest, 8> h2;
|
||||||
u8 padding_2[32];
|
std::array<u8, 32> padding_2;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(HashBlock) == BLOCK_HEADER_SIZE);
|
static_assert(sizeof(HashBlock) == BLOCK_HEADER_SIZE);
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
|
|
||||||
#include "Common/Align.h"
|
#include "Common/Align.h"
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/IOFile.h"
|
#include "Common/IOFile.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
@ -109,9 +109,8 @@ bool WIARVZFileReader<RVZ>::Initialize(const std::string& path)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHA1 header_1_actual_hash;
|
const auto header_1_actual_hash = Common::SHA1::CalculateDigest(
|
||||||
mbedtls_sha1_ret(reinterpret_cast<const u8*>(&m_header_1), sizeof(m_header_1) - sizeof(SHA1),
|
reinterpret_cast<const u8*>(&m_header_1), sizeof(m_header_1) - Common::SHA1::DIGEST_LEN);
|
||||||
header_1_actual_hash.data());
|
|
||||||
if (m_header_1.header_1_hash != header_1_actual_hash)
|
if (m_header_1.header_1_hash != header_1_actual_hash)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -130,8 +129,7 @@ bool WIARVZFileReader<RVZ>::Initialize(const std::string& path)
|
||||||
if (!m_file.ReadBytes(header_2.data(), header_2.size()))
|
if (!m_file.ReadBytes(header_2.data(), header_2.size()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SHA1 header_2_actual_hash;
|
const auto header_2_actual_hash = Common::SHA1::CalculateDigest(header_2);
|
||||||
mbedtls_sha1_ret(header_2.data(), header_2.size(), header_2_actual_hash.data());
|
|
||||||
if (m_header_1.header_2_hash != header_2_actual_hash)
|
if (m_header_1.header_2_hash != header_2_actual_hash)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -168,9 +166,7 @@ bool WIARVZFileReader<RVZ>::Initialize(const std::string& path)
|
||||||
if (!m_file.ReadBytes(partition_entries.data(), partition_entries.size()))
|
if (!m_file.ReadBytes(partition_entries.data(), partition_entries.size()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SHA1 partition_entries_actual_hash;
|
const auto partition_entries_actual_hash = Common::SHA1::CalculateDigest(partition_entries);
|
||||||
mbedtls_sha1_ret(reinterpret_cast<const u8*>(partition_entries.data()), partition_entries.size(),
|
|
||||||
partition_entries_actual_hash.data());
|
|
||||||
if (m_header_2.partition_entries_hash != partition_entries_actual_hash)
|
if (m_header_2.partition_entries_hash != partition_entries_actual_hash)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -635,8 +631,8 @@ WIARVZFileReader<RVZ>::Chunk::Chunk(File::IOFile* file, u64 offset_in_file, u64
|
||||||
m_rvz_packed_size(rvz_packed_size), m_data_offset(data_offset)
|
m_rvz_packed_size(rvz_packed_size), m_data_offset(data_offset)
|
||||||
{
|
{
|
||||||
constexpr size_t MAX_SIZE_PER_EXCEPTION_LIST =
|
constexpr size_t MAX_SIZE_PER_EXCEPTION_LIST =
|
||||||
Common::AlignUp(VolumeWii::BLOCK_HEADER_SIZE, sizeof(SHA1)) / sizeof(SHA1) *
|
Common::AlignUp(VolumeWii::BLOCK_HEADER_SIZE, Common::SHA1::DIGEST_LEN) /
|
||||||
VolumeWii::BLOCKS_PER_GROUP * sizeof(HashExceptionEntry) +
|
Common::SHA1::DIGEST_LEN * VolumeWii::BLOCKS_PER_GROUP * sizeof(HashExceptionEntry) +
|
||||||
sizeof(u16);
|
sizeof(u16);
|
||||||
|
|
||||||
m_out_bytes_allocated_for_exceptions =
|
m_out_bytes_allocated_for_exceptions =
|
||||||
|
@ -861,11 +857,11 @@ bool WIARVZFileReader<RVZ>::ApplyHashExceptions(
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const size_t offset_in_block = offset % VolumeWii::BLOCK_HEADER_SIZE;
|
const size_t offset_in_block = offset % VolumeWii::BLOCK_HEADER_SIZE;
|
||||||
if (offset_in_block + sizeof(SHA1) > VolumeWii::BLOCK_HEADER_SIZE)
|
if (offset_in_block + Common::SHA1::DIGEST_LEN > VolumeWii::BLOCK_HEADER_SIZE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::memcpy(reinterpret_cast<u8*>(&hash_blocks[block_index]) + offset_in_block, &exception.hash,
|
std::memcpy(reinterpret_cast<u8*>(&hash_blocks[block_index]) + offset_in_block, &exception.hash,
|
||||||
sizeof(SHA1));
|
Common::SHA1::DIGEST_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1420,7 +1416,7 @@ WIARVZFileReader<RVZ>::ProcessAndCompress(CompressThreadState* state, CompressPa
|
||||||
&aes_context);
|
&aes_context);
|
||||||
|
|
||||||
const auto compare_hash = [&](size_t offset_in_block) {
|
const auto compare_hash = [&](size_t offset_in_block) {
|
||||||
ASSERT(offset_in_block + sizeof(SHA1) <= VolumeWii::BLOCK_HEADER_SIZE);
|
ASSERT(offset_in_block + Common::SHA1::DIGEST_LEN <= VolumeWii::BLOCK_HEADER_SIZE);
|
||||||
|
|
||||||
const u8* desired_hash = reinterpret_cast<u8*>(&hashes) + offset_in_block;
|
const u8* desired_hash = reinterpret_cast<u8*>(&hashes) + offset_in_block;
|
||||||
const u8* computed_hash =
|
const u8* computed_hash =
|
||||||
|
@ -1432,22 +1428,22 @@ WIARVZFileReader<RVZ>::ProcessAndCompress(CompressThreadState* state, CompressPa
|
||||||
// that affects the recalculated hashes. Chunks which have been marked as reusable at
|
// that affects the recalculated hashes. Chunks which have been marked as reusable at
|
||||||
// this point normally have zero matching hashes anyway, so this shouldn't waste space.
|
// this point normally have zero matching hashes anyway, so this shouldn't waste space.
|
||||||
if ((chunks_per_wii_group != 1 && output_entries[chunk_index].reuse_id) ||
|
if ((chunks_per_wii_group != 1 && output_entries[chunk_index].reuse_id) ||
|
||||||
!std::equal(desired_hash, desired_hash + sizeof(SHA1), computed_hash))
|
!std::equal(desired_hash, desired_hash + Common::SHA1::DIGEST_LEN, computed_hash))
|
||||||
{
|
{
|
||||||
const u64 hash_offset = hash_offset_of_block + offset_in_block;
|
const u64 hash_offset = hash_offset_of_block + offset_in_block;
|
||||||
ASSERT(hash_offset <= std::numeric_limits<u16>::max());
|
ASSERT(hash_offset <= std::numeric_limits<u16>::max());
|
||||||
|
|
||||||
HashExceptionEntry& exception = exception_lists[exception_list_index].emplace_back();
|
HashExceptionEntry& exception = exception_lists[exception_list_index].emplace_back();
|
||||||
exception.offset = static_cast<u16>(Common::swap16(hash_offset));
|
exception.offset = static_cast<u16>(Common::swap16(hash_offset));
|
||||||
std::memcpy(exception.hash.data(), desired_hash, sizeof(SHA1));
|
std::memcpy(exception.hash.data(), desired_hash, Common::SHA1::DIGEST_LEN);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto compare_hashes = [&compare_hash](size_t offset, size_t size) {
|
const auto compare_hashes = [&compare_hash](size_t offset, size_t size) {
|
||||||
for (size_t l = 0; l < size; l += sizeof(SHA1))
|
for (size_t l = 0; l < size; l += Common::SHA1::DIGEST_LEN)
|
||||||
// The std::min is to ensure that we don't go beyond the end of HashBlock with
|
// The std::min is to ensure that we don't go beyond the end of HashBlock with
|
||||||
// padding_2, which is 32 bytes long (not divisible by sizeof(SHA1), which is 20).
|
// padding_2, which is 32 bytes long (not divisible by SHA1::DIGEST_LEN, which is 20).
|
||||||
compare_hash(offset + std::min(l, size - sizeof(SHA1)));
|
compare_hash(offset + std::min(l, size - Common::SHA1::DIGEST_LEN));
|
||||||
};
|
};
|
||||||
|
|
||||||
using HashBlock = VolumeWii::HashBlock;
|
using HashBlock = VolumeWii::HashBlock;
|
||||||
|
@ -1995,10 +1991,7 @@ WIARVZFileReader<RVZ>::Convert(BlobReader* infile, const VolumeDisc* infile_volu
|
||||||
header_2.partition_entry_size = Common::swap32(sizeof(PartitionEntry));
|
header_2.partition_entry_size = Common::swap32(sizeof(PartitionEntry));
|
||||||
header_2.partition_entries_offset = Common::swap64(partition_entries_offset);
|
header_2.partition_entries_offset = Common::swap64(partition_entries_offset);
|
||||||
|
|
||||||
if (partition_entries.data() == nullptr)
|
header_2.partition_entries_hash = Common::SHA1::CalculateDigest(partition_entries);
|
||||||
partition_entries.reserve(1); // Avoid a crash in mbedtls_sha1_ret
|
|
||||||
mbedtls_sha1_ret(reinterpret_cast<const u8*>(partition_entries.data()), partition_entries_size,
|
|
||||||
header_2.partition_entries_hash.data());
|
|
||||||
|
|
||||||
header_2.number_of_raw_data_entries = Common::swap32(static_cast<u32>(raw_data_entries.size()));
|
header_2.number_of_raw_data_entries = Common::swap32(static_cast<u32>(raw_data_entries.size()));
|
||||||
header_2.raw_data_entries_offset = Common::swap64(raw_data_entries_offset);
|
header_2.raw_data_entries_offset = Common::swap64(raw_data_entries_offset);
|
||||||
|
@ -2014,12 +2007,12 @@ WIARVZFileReader<RVZ>::Convert(BlobReader* infile, const VolumeDisc* infile_volu
|
||||||
header_1.version_compatible =
|
header_1.version_compatible =
|
||||||
Common::swap32(RVZ ? RVZ_VERSION_WRITE_COMPATIBLE : WIA_VERSION_WRITE_COMPATIBLE);
|
Common::swap32(RVZ ? RVZ_VERSION_WRITE_COMPATIBLE : WIA_VERSION_WRITE_COMPATIBLE);
|
||||||
header_1.header_2_size = Common::swap32(sizeof(WIAHeader2));
|
header_1.header_2_size = Common::swap32(sizeof(WIAHeader2));
|
||||||
mbedtls_sha1_ret(reinterpret_cast<const u8*>(&header_2), sizeof(header_2),
|
header_1.header_2_hash =
|
||||||
header_1.header_2_hash.data());
|
Common::SHA1::CalculateDigest(reinterpret_cast<const u8*>(&header_2), sizeof(header_2));
|
||||||
header_1.iso_file_size = Common::swap64(infile->GetDataSize());
|
header_1.iso_file_size = Common::swap64(infile->GetDataSize());
|
||||||
header_1.wia_file_size = Common::swap64(outfile->GetSize());
|
header_1.wia_file_size = Common::swap64(outfile->GetSize());
|
||||||
mbedtls_sha1_ret(reinterpret_cast<const u8*>(&header_1), offsetof(WIAHeader1, header_1_hash),
|
header_1.header_1_hash = Common::SHA1::CalculateDigest(reinterpret_cast<const u8*>(&header_1),
|
||||||
header_1.header_1_hash.data());
|
offsetof(WIAHeader1, header_1_hash));
|
||||||
|
|
||||||
if (!outfile->Seek(0, File::SeekOrigin::Begin))
|
if (!outfile->Seek(0, File::SeekOrigin::Begin))
|
||||||
return ConversionResultCode::WriteFailed;
|
return ConversionResultCode::WriteFailed;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/IOFile.h"
|
#include "Common/IOFile.h"
|
||||||
#include "Common/Swap.h"
|
#include "Common/Swap.h"
|
||||||
#include "DiscIO/Blob.h"
|
#include "DiscIO/Blob.h"
|
||||||
|
@ -70,7 +71,6 @@ public:
|
||||||
int compression_level, int chunk_size, CompressCB callback);
|
int compression_level, int chunk_size, CompressCB callback);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using SHA1 = std::array<u8, 20>;
|
|
||||||
using WiiKey = std::array<u8, 16>;
|
using WiiKey = std::array<u8, 16>;
|
||||||
|
|
||||||
// See docs/WiaAndRvz.md for details about the format
|
// See docs/WiaAndRvz.md for details about the format
|
||||||
|
@ -82,10 +82,10 @@ private:
|
||||||
u32 version;
|
u32 version;
|
||||||
u32 version_compatible;
|
u32 version_compatible;
|
||||||
u32 header_2_size;
|
u32 header_2_size;
|
||||||
SHA1 header_2_hash;
|
Common::SHA1::Digest header_2_hash;
|
||||||
u64 iso_file_size;
|
u64 iso_file_size;
|
||||||
u64 wia_file_size;
|
u64 wia_file_size;
|
||||||
SHA1 header_1_hash;
|
Common::SHA1::Digest header_1_hash;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(WIAHeader1) == 0x48, "Wrong size for WIA header 1");
|
static_assert(sizeof(WIAHeader1) == 0x48, "Wrong size for WIA header 1");
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ private:
|
||||||
u32 number_of_partition_entries;
|
u32 number_of_partition_entries;
|
||||||
u32 partition_entry_size;
|
u32 partition_entry_size;
|
||||||
u64 partition_entries_offset;
|
u64 partition_entries_offset;
|
||||||
SHA1 partition_entries_hash;
|
Common::SHA1::Digest partition_entries_hash;
|
||||||
|
|
||||||
u32 number_of_raw_data_entries;
|
u32 number_of_raw_data_entries;
|
||||||
u64 raw_data_entries_offset;
|
u64 raw_data_entries_offset;
|
||||||
|
@ -161,7 +161,7 @@ private:
|
||||||
struct HashExceptionEntry
|
struct HashExceptionEntry
|
||||||
{
|
{
|
||||||
u16 offset;
|
u16 offset;
|
||||||
SHA1 hash;
|
Common::SHA1::Digest hash;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(HashExceptionEntry) == 0x16, "Wrong size for WIA hash exception entry");
|
static_assert(sizeof(HashExceptionEntry) == 0x16, "Wrong size for WIA hash exception entry");
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
#include <bzlib.h>
|
#include <bzlib.h>
|
||||||
#include <lzma.h>
|
#include <lzma.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
|
@ -48,7 +47,6 @@ bool NoneDecompressor::Decompress(const DecompressionBuffer& in, DecompressionBu
|
||||||
|
|
||||||
PurgeDecompressor::PurgeDecompressor(u64 decompressed_size) : m_decompressed_size(decompressed_size)
|
PurgeDecompressor::PurgeDecompressor(u64 decompressed_size) : m_decompressed_size(decompressed_size)
|
||||||
{
|
{
|
||||||
mbedtls_sha1_init(&m_sha1_context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PurgeDecompressor::Decompress(const DecompressionBuffer& in, DecompressionBuffer* out,
|
bool PurgeDecompressor::Decompress(const DecompressionBuffer& in, DecompressionBuffer* out,
|
||||||
|
@ -56,10 +54,10 @@ bool PurgeDecompressor::Decompress(const DecompressionBuffer& in, DecompressionB
|
||||||
{
|
{
|
||||||
if (!m_started)
|
if (!m_started)
|
||||||
{
|
{
|
||||||
mbedtls_sha1_starts_ret(&m_sha1_context);
|
m_sha1_context = Common::SHA1::CreateContext();
|
||||||
|
|
||||||
// Include the exception lists in the SHA-1 calculation (but not in the compression...)
|
// Include the exception lists in the SHA-1 calculation (but not in the compression...)
|
||||||
mbedtls_sha1_update_ret(&m_sha1_context, in.data.data(), *in_bytes_read);
|
m_sha1_context->Update(in.data.data(), *in_bytes_read);
|
||||||
|
|
||||||
m_started = true;
|
m_started = true;
|
||||||
}
|
}
|
||||||
|
@ -67,7 +65,7 @@ bool PurgeDecompressor::Decompress(const DecompressionBuffer& in, DecompressionB
|
||||||
while (!m_done && in.bytes_written != *in_bytes_read &&
|
while (!m_done && in.bytes_written != *in_bytes_read &&
|
||||||
(m_segment_bytes_written < sizeof(m_segment) || out->data.size() != out->bytes_written))
|
(m_segment_bytes_written < sizeof(m_segment) || out->data.size() != out->bytes_written))
|
||||||
{
|
{
|
||||||
if (m_segment_bytes_written == 0 && *in_bytes_read == in.data.size() - sizeof(SHA1))
|
if (m_segment_bytes_written == 0 && *in_bytes_read == in.data.size() - Common::SHA1::DIGEST_LEN)
|
||||||
{
|
{
|
||||||
const size_t zeroes_to_write = std::min<size_t>(m_decompressed_size - m_out_bytes_written,
|
const size_t zeroes_to_write = std::min<size_t>(m_decompressed_size - m_out_bytes_written,
|
||||||
out->data.size() - out->bytes_written);
|
out->data.size() - out->bytes_written);
|
||||||
|
@ -79,10 +77,9 @@ bool PurgeDecompressor::Decompress(const DecompressionBuffer& in, DecompressionB
|
||||||
|
|
||||||
if (m_out_bytes_written == m_decompressed_size && in.bytes_written == in.data.size())
|
if (m_out_bytes_written == m_decompressed_size && in.bytes_written == in.data.size())
|
||||||
{
|
{
|
||||||
SHA1 actual_hash;
|
const auto actual_hash = m_sha1_context->Finish();
|
||||||
mbedtls_sha1_finish_ret(&m_sha1_context, actual_hash.data());
|
|
||||||
|
|
||||||
SHA1 expected_hash;
|
Common::SHA1::Digest expected_hash;
|
||||||
std::memcpy(expected_hash.data(), in.data.data() + *in_bytes_read, expected_hash.size());
|
std::memcpy(expected_hash.data(), in.data.data() + *in_bytes_read, expected_hash.size());
|
||||||
|
|
||||||
*in_bytes_read += expected_hash.size();
|
*in_bytes_read += expected_hash.size();
|
||||||
|
@ -102,7 +99,7 @@ bool PurgeDecompressor::Decompress(const DecompressionBuffer& in, DecompressionB
|
||||||
|
|
||||||
std::memcpy(reinterpret_cast<u8*>(&m_segment) + m_segment_bytes_written,
|
std::memcpy(reinterpret_cast<u8*>(&m_segment) + m_segment_bytes_written,
|
||||||
in.data.data() + *in_bytes_read, bytes_to_copy);
|
in.data.data() + *in_bytes_read, bytes_to_copy);
|
||||||
mbedtls_sha1_update_ret(&m_sha1_context, in.data.data() + *in_bytes_read, bytes_to_copy);
|
m_sha1_context->Update(in.data.data() + *in_bytes_read, bytes_to_copy);
|
||||||
|
|
||||||
*in_bytes_read += bytes_to_copy;
|
*in_bytes_read += bytes_to_copy;
|
||||||
m_bytes_read += bytes_to_copy;
|
m_bytes_read += bytes_to_copy;
|
||||||
|
@ -134,7 +131,7 @@ bool PurgeDecompressor::Decompress(const DecompressionBuffer& in, DecompressionB
|
||||||
|
|
||||||
std::memcpy(out->data.data() + out->bytes_written, in.data.data() + *in_bytes_read,
|
std::memcpy(out->data.data() + out->bytes_written, in.data.data() + *in_bytes_read,
|
||||||
bytes_to_copy);
|
bytes_to_copy);
|
||||||
mbedtls_sha1_update_ret(&m_sha1_context, in.data.data() + *in_bytes_read, bytes_to_copy);
|
m_sha1_context->Update(in.data.data() + *in_bytes_read, bytes_to_copy);
|
||||||
|
|
||||||
*in_bytes_read += bytes_to_copy;
|
*in_bytes_read += bytes_to_copy;
|
||||||
m_bytes_read += bytes_to_copy;
|
m_bytes_read += bytes_to_copy;
|
||||||
|
@ -435,10 +432,7 @@ bool RVZPackDecompressor::Done() const
|
||||||
|
|
||||||
Compressor::~Compressor() = default;
|
Compressor::~Compressor() = default;
|
||||||
|
|
||||||
PurgeCompressor::PurgeCompressor()
|
PurgeCompressor::PurgeCompressor() = default;
|
||||||
{
|
|
||||||
mbedtls_sha1_init(&m_sha1_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
PurgeCompressor::~PurgeCompressor() = default;
|
PurgeCompressor::~PurgeCompressor() = default;
|
||||||
|
|
||||||
|
@ -447,14 +441,14 @@ bool PurgeCompressor::Start(std::optional<u64> size)
|
||||||
m_buffer.clear();
|
m_buffer.clear();
|
||||||
m_bytes_written = 0;
|
m_bytes_written = 0;
|
||||||
|
|
||||||
mbedtls_sha1_starts_ret(&m_sha1_context);
|
m_sha1_context = Common::SHA1::CreateContext();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PurgeCompressor::AddPrecedingDataOnlyForPurgeHashing(const u8* data, size_t size)
|
bool PurgeCompressor::AddPrecedingDataOnlyForPurgeHashing(const u8* data, size_t size)
|
||||||
{
|
{
|
||||||
mbedtls_sha1_update_ret(&m_sha1_context, data, size);
|
m_sha1_context->Update(data, size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,7 +459,7 @@ bool PurgeCompressor::Compress(const u8* data, size_t size)
|
||||||
ASSERT_MSG(DISCIO, m_bytes_written == 0,
|
ASSERT_MSG(DISCIO, m_bytes_written == 0,
|
||||||
"Calling PurgeCompressor::Compress() twice is not supported");
|
"Calling PurgeCompressor::Compress() twice is not supported");
|
||||||
|
|
||||||
m_buffer.resize(size + sizeof(PurgeSegment) + sizeof(SHA1));
|
m_buffer.resize(size + sizeof(PurgeSegment) + Common::SHA1::DIGEST_LEN);
|
||||||
|
|
||||||
size_t bytes_read = 0;
|
size_t bytes_read = 0;
|
||||||
|
|
||||||
|
@ -517,10 +511,12 @@ bool PurgeCompressor::Compress(const u8* data, size_t size)
|
||||||
|
|
||||||
bool PurgeCompressor::End()
|
bool PurgeCompressor::End()
|
||||||
{
|
{
|
||||||
mbedtls_sha1_update_ret(&m_sha1_context, m_buffer.data(), m_bytes_written);
|
m_sha1_context->Update(m_buffer.data(), m_bytes_written);
|
||||||
|
|
||||||
mbedtls_sha1_finish_ret(&m_sha1_context, m_buffer.data() + m_bytes_written);
|
const auto digest = m_sha1_context->Finish();
|
||||||
m_bytes_written += sizeof(SHA1);
|
std::memcpy(m_buffer.data() + m_bytes_written, digest.data(), sizeof(digest));
|
||||||
|
|
||||||
|
m_bytes_written += sizeof(digest);
|
||||||
|
|
||||||
ASSERT(m_bytes_written <= m_buffer.size());
|
ASSERT(m_bytes_written <= m_buffer.size());
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
|
|
||||||
#include <bzlib.h>
|
#include <bzlib.h>
|
||||||
#include <lzma.h>
|
#include <lzma.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "DiscIO/LaggedFibonacciGenerator.h"
|
#include "DiscIO/LaggedFibonacciGenerator.h"
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
|
@ -24,8 +24,6 @@ struct DecompressionBuffer
|
||||||
size_t bytes_written = 0;
|
size_t bytes_written = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using SHA1 = std::array<u8, 20>;
|
|
||||||
|
|
||||||
struct PurgeSegment
|
struct PurgeSegment
|
||||||
{
|
{
|
||||||
u32 offset;
|
u32 offset;
|
||||||
|
@ -71,7 +69,7 @@ private:
|
||||||
size_t m_out_bytes_written = 0;
|
size_t m_out_bytes_written = 0;
|
||||||
bool m_started = false;
|
bool m_started = false;
|
||||||
|
|
||||||
mbedtls_sha1_context m_sha1_context;
|
std::unique_ptr<Common::SHA1::Context> m_sha1_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Bzip2Decompressor final : public Decompressor
|
class Bzip2Decompressor final : public Decompressor
|
||||||
|
@ -179,7 +177,7 @@ public:
|
||||||
private:
|
private:
|
||||||
std::vector<u8> m_buffer;
|
std::vector<u8> m_buffer;
|
||||||
size_t m_bytes_written = 0;
|
size_t m_bytes_written = 0;
|
||||||
mbedtls_sha1_context m_sha1_context;
|
std::unique_ptr<Common::SHA1::Context> m_sha1_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Bzip2Compressor final : public Compressor
|
class Bzip2Compressor final : public Compressor
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
<ClInclude Include="Common\Crypto\AES.h" />
|
<ClInclude Include="Common\Crypto\AES.h" />
|
||||||
<ClInclude Include="Common\Crypto\bn.h" />
|
<ClInclude Include="Common\Crypto\bn.h" />
|
||||||
<ClInclude Include="Common\Crypto\ec.h" />
|
<ClInclude Include="Common\Crypto\ec.h" />
|
||||||
|
<ClInclude Include="Common\Crypto\SHA1.h" />
|
||||||
<ClInclude Include="Common\Debug\MemoryPatches.h" />
|
<ClInclude Include="Common\Debug\MemoryPatches.h" />
|
||||||
<ClInclude Include="Common\Debug\Threads.h" />
|
<ClInclude Include="Common\Debug\Threads.h" />
|
||||||
<ClInclude Include="Common\Debug\Watches.h" />
|
<ClInclude Include="Common\Debug\Watches.h" />
|
||||||
|
@ -722,6 +723,7 @@
|
||||||
<ClCompile Include="Common\Crypto\AES.cpp" />
|
<ClCompile Include="Common\Crypto\AES.cpp" />
|
||||||
<ClCompile Include="Common\Crypto\bn.cpp" />
|
<ClCompile Include="Common\Crypto\bn.cpp" />
|
||||||
<ClCompile Include="Common\Crypto\ec.cpp" />
|
<ClCompile Include="Common\Crypto\ec.cpp" />
|
||||||
|
<ClCompile Include="Common\Crypto\SHA1.cpp" />
|
||||||
<ClCompile Include="Common\Debug\MemoryPatches.cpp" />
|
<ClCompile Include="Common\Debug\MemoryPatches.cpp" />
|
||||||
<ClCompile Include="Common\Debug\Watches.cpp" />
|
<ClCompile Include="Common\Debug\Watches.cpp" />
|
||||||
<ClCompile Include="Common\DynamicLibrary.cpp" />
|
<ClCompile Include="Common\DynamicLibrary.cpp" />
|
||||||
|
|
|
@ -18,13 +18,13 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <mbedtls/sha1.h>
|
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
|
|
||||||
#include "Common/BitUtils.h"
|
#include "Common/BitUtils.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/CommonPaths.h"
|
#include "Common/CommonPaths.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/HttpRequest.h"
|
#include "Common/HttpRequest.h"
|
||||||
#include "Common/IOFile.h"
|
#include "Common/IOFile.h"
|
||||||
|
@ -627,22 +627,18 @@ std::string GameFile::GetNetPlayName(const Core::TitleDatabase& title_database)
|
||||||
return name + " (" + ss.str() + ")";
|
return name + " (" + ss.str() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::array<u8, 20> GetHash(u32 value)
|
static Common::SHA1::Digest GetHash(u32 value)
|
||||||
{
|
{
|
||||||
auto data = Common::BitCastToArray<u8>(value);
|
auto data = Common::BitCastToArray<u8>(value);
|
||||||
std::array<u8, 20> hash;
|
return Common::SHA1::CalculateDigest(data);
|
||||||
mbedtls_sha1_ret(reinterpret_cast<const unsigned char*>(data.data()), data.size(), hash.data());
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::array<u8, 20> GetHash(std::string_view str)
|
static Common::SHA1::Digest GetHash(std::string_view str)
|
||||||
{
|
{
|
||||||
std::array<u8, 20> hash;
|
return Common::SHA1::CalculateDigest(str);
|
||||||
mbedtls_sha1_ret(reinterpret_cast<const unsigned char*>(str.data()), str.size(), hash.data());
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<std::array<u8, 20>> GetFileHash(const std::string& path)
|
static std::optional<Common::SHA1::Digest> GetFileHash(const std::string& path)
|
||||||
{
|
{
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
if (!File::ReadFileToString(path, buffer))
|
if (!File::ReadFileToString(path, buffer))
|
||||||
|
@ -650,22 +646,22 @@ static std::optional<std::array<u8, 20>> GetFileHash(const std::string& path)
|
||||||
return GetHash(buffer);
|
return GetHash(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<std::array<u8, 20>> MixHash(const std::optional<std::array<u8, 20>>& lhs,
|
static std::optional<Common::SHA1::Digest> MixHash(const std::optional<Common::SHA1::Digest>& lhs,
|
||||||
const std::optional<std::array<u8, 20>>& rhs)
|
const std::optional<Common::SHA1::Digest>& rhs)
|
||||||
{
|
{
|
||||||
if (!lhs && !rhs)
|
if (!lhs && !rhs)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
if (!lhs || !rhs)
|
if (!lhs || !rhs)
|
||||||
return !rhs ? lhs : rhs;
|
return !rhs ? lhs : rhs;
|
||||||
std::array<u8, 20> result;
|
Common::SHA1::Digest result;
|
||||||
for (size_t i = 0; i < result.size(); ++i)
|
for (size_t i = 0; i < result.size(); ++i)
|
||||||
result[i] = (*lhs)[i] ^ (*rhs)[(i + 1) % result.size()];
|
result[i] = (*lhs)[i] ^ (*rhs)[(i + 1) % result.size()];
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<u8, 20> GameFile::GetSyncHash() const
|
Common::SHA1::Digest GameFile::GetSyncHash() const
|
||||||
{
|
{
|
||||||
std::optional<std::array<u8, 20>> hash;
|
std::optional<Common::SHA1::Digest> hash;
|
||||||
|
|
||||||
if (m_platform == DiscIO::Platform::ELFOrDOL)
|
if (m_platform == DiscIO::Platform::ELFOrDOL)
|
||||||
{
|
{
|
||||||
|
@ -703,7 +699,7 @@ std::array<u8, 20> GameFile::GetSyncHash() const
|
||||||
hash = volume->GetSyncHash();
|
hash = volume->GetSyncHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash.value_or(std::array<u8, 20>{});
|
return hash.value_or(Common::SHA1::Digest{});
|
||||||
}
|
}
|
||||||
|
|
||||||
NetPlay::SyncIdentifier GameFile::GetSyncIdentifier() const
|
NetPlay::SyncIdentifier GameFile::GetSyncIdentifier() const
|
||||||
|
|
|
@ -5,6 +5,7 @@ add_dolphin_test(BlockingLoopTest BlockingLoopTest.cpp)
|
||||||
add_dolphin_test(BusyLoopTest BusyLoopTest.cpp)
|
add_dolphin_test(BusyLoopTest BusyLoopTest.cpp)
|
||||||
add_dolphin_test(CommonFuncsTest CommonFuncsTest.cpp)
|
add_dolphin_test(CommonFuncsTest CommonFuncsTest.cpp)
|
||||||
add_dolphin_test(CryptoEcTest Crypto/EcTest.cpp)
|
add_dolphin_test(CryptoEcTest Crypto/EcTest.cpp)
|
||||||
|
add_dolphin_test(CryptoSHA1Test Crypto/SHA1Test.cpp)
|
||||||
add_dolphin_test(EnumFormatterTest EnumFormatterTest.cpp)
|
add_dolphin_test(EnumFormatterTest EnumFormatterTest.cpp)
|
||||||
add_dolphin_test(EventTest EventTest.cpp)
|
add_dolphin_test(EventTest EventTest.cpp)
|
||||||
add_dolphin_test(FileUtilTest FileUtilTest.cpp)
|
add_dolphin_test(FileUtilTest FileUtilTest.cpp)
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "Common/Crypto/SHA1.h"
|
||||||
|
|
||||||
|
// Just a few quick sanity checks
|
||||||
|
TEST(SHA1, Vectors)
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
const char* msg;
|
||||||
|
const Common::SHA1::Digest expected;
|
||||||
|
} const vectors[]{
|
||||||
|
{"", {0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
|
||||||
|
0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09}},
|
||||||
|
{"abc", {0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e,
|
||||||
|
0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d}},
|
||||||
|
{"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
||||||
|
{0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae,
|
||||||
|
0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1}},
|
||||||
|
{"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmn"
|
||||||
|
"opqklmnopqrlmnopqrsmnopqrstnopqrstu",
|
||||||
|
{0xa4, 0x9b, 0x24, 0x46, 0xa0, 0x2c, 0x64, 0x5b, 0xf4, 0x19,
|
||||||
|
0xf9, 0x95, 0xb6, 0x70, 0x91, 0x25, 0x3a, 0x04, 0xa2, 0x59}},
|
||||||
|
};
|
||||||
|
for (auto& test : vectors)
|
||||||
|
{
|
||||||
|
auto actual = Common::SHA1::CalculateDigest(test.msg);
|
||||||
|
EXPECT_EQ(test.expected, actual);
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,7 @@
|
||||||
<ClCompile Include="Common\BusyLoopTest.cpp" />
|
<ClCompile Include="Common\BusyLoopTest.cpp" />
|
||||||
<ClCompile Include="Common\CommonFuncsTest.cpp" />
|
<ClCompile Include="Common\CommonFuncsTest.cpp" />
|
||||||
<ClCompile Include="Common\Crypto\EcTest.cpp" />
|
<ClCompile Include="Common\Crypto\EcTest.cpp" />
|
||||||
|
<ClCompile Include="Common\Crypto\SHA1Test.cpp" />
|
||||||
<ClCompile Include="Common\EnumFormatterTest.cpp" />
|
<ClCompile Include="Common\EnumFormatterTest.cpp" />
|
||||||
<ClCompile Include="Common\EventTest.cpp" />
|
<ClCompile Include="Common\EventTest.cpp" />
|
||||||
<ClCompile Include="Common\FileUtilTest.cpp" />
|
<ClCompile Include="Common\FileUtilTest.cpp" />
|
||||||
|
|
Loading…
Reference in New Issue