Read IW4 signed headers

This commit is contained in:
Jan
2020-09-06 14:39:19 +02:00
parent 3a69b3b0b0
commit 060e5678b5
40 changed files with 1767 additions and 24 deletions

View File

@ -0,0 +1,11 @@
#include "InvalidHashException.h"
std::string InvalidHashException::DetailedMessage()
{
return "Loaded fastfile has an invalid hash.";
}
char const* InvalidHashException::what() const
{
return "Loaded fastfile has an invalid hash.";
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "LoadingException.h"
class InvalidHashException final : public LoadingException
{
public:
std::string DetailedMessage() override;
char const* what() const override;
};

View File

@ -0,0 +1,8 @@
#pragma once
#include <cstdint>
class ICapturedDataProvider
{
public:
virtual void GetCapturedData(const uint8_t** pCapturedData, size_t* pSize) = 0;
};

View File

@ -0,0 +1,8 @@
#pragma once
#include <cstdint>
class IHashProvider
{
public:
virtual void GetHash(unsigned hashIndex, const uint8_t** pHash, size_t* pSize) = 0;
};

View File

@ -1,8 +0,0 @@
#pragma once
#include <cstdint>
class ISignatureDataProvider
{
public:
virtual void GetSignatureData(const uint8_t** pSignatureData, size_t* pSize) = 0;
};

View File

@ -0,0 +1,47 @@
#include "ProcessorAuthedBlocks.h"
class ProcessorAuthedBlocks::Impl final : public StreamProcessor
{
const int m_authed_chunk_count;
const int m_max_master_block_count;
IHashProvider* m_hash_provider;
public:
Impl(const int authedChunkCount, const int maxMasterBlockCount, IHashProvider* masterBlockHashProvider)
: m_authed_chunk_count(authedChunkCount),
m_max_master_block_count(maxMasterBlockCount),
m_hash_provider(masterBlockHashProvider)
{
}
size_t Load(void* buffer, size_t length) override
{
return 0;
}
int64_t Pos() override
{
return 0;
}
};
ProcessorAuthedBlocks::ProcessorAuthedBlocks(const int authedChunkCount, const int maxMasterBlockCount, IHashProvider* masterBlockHashProvider)
: m_impl(new Impl(authedChunkCount, maxMasterBlockCount, masterBlockHashProvider))
{
}
ProcessorAuthedBlocks::~ProcessorAuthedBlocks()
{
delete m_impl;
m_impl = nullptr;
}
size_t ProcessorAuthedBlocks::Load(void* buffer, const size_t length)
{
return m_impl->Load(buffer, length);
}
int64_t ProcessorAuthedBlocks::Pos()
{
return m_impl->Pos();
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "Loading/StreamProcessor.h"
#include "Loading/IHashProvider.h"
class ProcessorAuthedBlocks : public StreamProcessor
{
class Impl;
Impl* m_impl;
public:
ProcessorAuthedBlocks(int authedChunkCount, int maxMasterBlockCount, IHashProvider* masterBlockHashProvider);
~ProcessorAuthedBlocks() override;
size_t Load(void* buffer, size_t length) override;
int64_t Pos() override;
};

View File

@ -0,0 +1,50 @@
#include "ProcessorCaptureData.h"
#include <cassert>
ProcessorCaptureData::ProcessorCaptureData(const size_t captureSize)
: m_data(std::make_unique<uint8_t[]>(captureSize)),
m_capture_size(captureSize),
m_captured_data_size(0)
{
}
ProcessorCaptureData::~ProcessorCaptureData()
= default;
size_t ProcessorCaptureData::Load(void* buffer, const size_t length)
{
if (m_captured_data_size >= m_capture_size)
return m_base_stream->Load(buffer, length);
size_t dataToCapture = m_capture_size - m_captured_data_size;
if (length < dataToCapture)
dataToCapture = length;
size_t loadedSize = m_base_stream->Load(&m_data[m_captured_data_size], dataToCapture);
memcpy_s(buffer, length, &m_data[m_captured_data_size], loadedSize);
m_captured_data_size += loadedSize;
if(length > dataToCapture)
loadedSize += m_base_stream->Load(&static_cast<uint8_t*>(buffer)[dataToCapture], length - dataToCapture);
return loadedSize;
}
int64_t ProcessorCaptureData::Pos()
{
return m_base_stream->Pos();
}
void ProcessorCaptureData::GetCapturedData(const uint8_t** pCapturedData, size_t* pSize)
{
assert(pCapturedData != nullptr);
assert(pSize != nullptr);
assert(m_captured_data_size == m_capture_size);
*pCapturedData = m_data.get();
*pSize = m_captured_data_size;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <memory>
#include "Loading/StreamProcessor.h"
#include "Loading/ICapturedDataProvider.h"
class ProcessorCaptureData final : public StreamProcessor, public ICapturedDataProvider
{
std::unique_ptr<uint8_t[]> m_data;
const size_t m_capture_size;
size_t m_captured_data_size;
public:
explicit ProcessorCaptureData(size_t captureSize);
~ProcessorCaptureData() override;
size_t Load(void* buffer, size_t length) override;
int64_t Pos() override;
void GetCapturedData(const uint8_t** pCapturedData, size_t* pSize) override;
};

View File

@ -150,7 +150,7 @@ size_t ChunkProcessorSalsa20::Process(const int streamNumber, const uint8_t* inp
return m_impl->Process(streamNumber, input, inputLength, output, outputBufferSize);
}
void ChunkProcessorSalsa20::GetSignatureData(const uint8_t** pSignatureData, size_t* pSize)
void ChunkProcessorSalsa20::GetCapturedData(const uint8_t** pCapturedData, size_t* pSize)
{
m_impl->GetSignatureData(pSignatureData, pSize);
m_impl->GetSignatureData(pCapturedData, pSize);
}

View File

@ -1,9 +1,9 @@
#pragma once
#include "IXChunkProcessor.h"
#include "Loading/ISignatureDataProvider.h"
#include "Loading/ICapturedDataProvider.h"
#include <string>
class ChunkProcessorSalsa20 : public IXChunkProcessor, public ISignatureDataProvider
class ChunkProcessorSalsa20 : public IXChunkProcessor, public ICapturedDataProvider
{
class ChunkProcessorSalsa20Impl;
ChunkProcessorSalsa20Impl* m_impl;
@ -13,5 +13,5 @@ public:
~ChunkProcessorSalsa20() override;
size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) override;
void GetSignatureData(const uint8_t** pSignatureData, size_t* pSize) override;
void GetCapturedData(const uint8_t** pCapturedData, size_t* pSize) override;
};

View File

@ -0,0 +1,42 @@
#include "StepLoadHash.h"
#include "Loading/Exception/UnexpectedEndOfFileException.h"
#include <cassert>
StepLoadHash::StepLoadHash(const size_t hashSize, const unsigned hashCount)
: m_hash_size(hashSize),
m_hash_count(hashCount),
m_hashes(std::make_unique<uint8_t[]>(hashSize * hashCount))
{
}
StepLoadHash::~StepLoadHash()
= default;
void StepLoadHash::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
assert(stream != nullptr);
if (stream->Load(m_hashes.get(), m_hash_size * m_hash_count) != m_hash_size * m_hash_count)
throw UnexpectedEndOfFileException();
}
void StepLoadHash::GetHash(const unsigned hashIndex, const uint8_t** pHash, size_t* pSize)
{
assert(pHash != nullptr);
assert(pSize != nullptr);
assert(hashIndex >= 0 && hashIndex < m_hash_count);
assert(m_hashes);
*pHash = &m_hashes[m_hash_size * hashIndex];
*pSize = m_hash_size;
}
void StepLoadHash::GetCapturedData(const uint8_t** pCapturedData, size_t* pSize)
{
assert(pCapturedData != nullptr);
assert(pSize != nullptr);
*pCapturedData = m_hashes.get();
*pSize = m_hash_size * m_hash_count;
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <memory>
#include "Loading/ICapturedDataProvider.h"
#include "Loading/ILoadingStep.h"
#include "Loading/IHashProvider.h"
class StepLoadHash final : public ILoadingStep, public IHashProvider, public ICapturedDataProvider
{
const size_t m_hash_size;
const unsigned m_hash_count;
std::unique_ptr<uint8_t[]> m_hashes;
public:
StepLoadHash(size_t hashSize, unsigned hashCount);
~StepLoadHash() override;
StepLoadHash(const StepLoadHash& other) = delete;
StepLoadHash(StepLoadHash&& other) noexcept = default;
StepLoadHash& operator=(const StepLoadHash& other) = delete;
StepLoadHash& operator=(StepLoadHash&& other) noexcept = delete;
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
void GetHash(unsigned hashIndex, const uint8_t** pHash, size_t* pSize) override;
void GetCapturedData(const uint8_t** pCapturedData, size_t* pSize) override;
};

View File

@ -0,0 +1,26 @@
#include "StepRemoveProcessor.h"
#include <cassert>
StepRemoveProcessor::StepRemoveProcessor(StreamProcessor* streamProcessor)
: m_stream_processor(streamProcessor),
m_removed(false)
{
}
StepRemoveProcessor::~StepRemoveProcessor()
{
if(m_removed)
{
delete m_stream_processor;
m_stream_processor = nullptr;
}
}
void StepRemoveProcessor::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
assert(zoneLoader != nullptr);
assert(m_stream_processor != nullptr);
zoneLoader->RemoveStreamProcessor(m_stream_processor);
m_removed = true;
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "Loading/ILoadingStep.h"
class StepRemoveProcessor final : public ILoadingStep
{
StreamProcessor* m_stream_processor;
bool m_removed;
public:
explicit StepRemoveProcessor(StreamProcessor* streamProcessor);
~StepRemoveProcessor() override;
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
};

View File

@ -1,4 +1,7 @@
#include "StepVerifyFileName.h"
#include <sstream>
#include "Loading/Exception/InvalidFileNameException.h"
StepVerifyFileName::StepVerifyFileName(std::string fileName, const size_t fileNameBufferSize)
@ -12,7 +15,7 @@ StepVerifyFileName::StepVerifyFileName(std::string fileName, const size_t fileNa
void StepVerifyFileName::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
std::string originalFileName;
std::stringstream originalFilenameStream;
unsigned bufferOffset = 0;
char c;
@ -27,7 +30,7 @@ void StepVerifyFileName::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* str
break;
}
originalFileName += c;
originalFilenameStream << c;
}
// Skip the rest of the buffer which should be null bytes
@ -37,6 +40,8 @@ void StepVerifyFileName::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* str
bufferOffset++;
}
std::string originalFileName = originalFilenameStream.str();
if(originalFileName != m_file_name)
throw InvalidFileNameException(m_file_name, originalFileName);
}

View File

@ -0,0 +1,39 @@
#include "StepVerifyHash.h"
#include <memory>
#include "Loading/Exception/InvalidHashException.h"
StepVerifyHash::StepVerifyHash(std::unique_ptr<IHashFunction> hashFunction, const unsigned hashIndex, IHashProvider* hashProvider,
ICapturedDataProvider* dataProvider)
: m_hash_function(std::move(hashFunction)),
m_hash_index(hashIndex),
m_hash_provider(hashProvider),
m_data_provider(dataProvider)
{
}
StepVerifyHash::~StepVerifyHash()
= default;
void StepVerifyHash::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
{
const uint8_t* dataToHash = nullptr;
size_t dataToHashSize = 0;
m_data_provider->GetCapturedData(&dataToHash, &dataToHashSize);
const uint8_t* hashData = nullptr;
size_t hashSize = 0;
m_hash_provider->GetHash(m_hash_index, &hashData, &hashSize);
if (hashSize != m_hash_function->GetHashSize())
throw InvalidHashException();
const std::unique_ptr<uint8_t[]> hashMemory = std::make_unique<uint8_t[]>(m_hash_function->GetHashSize());
m_hash_function->Init();
m_hash_function->Process(dataToHash, dataToHashSize);
m_hash_function->Finish(hashMemory.get());
if(std::memcmp(hashData, hashMemory.get(), m_hash_function->GetHashSize()) != 0)
throw InvalidHashException();
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <memory>
#include "Crypto.h"
#include "Loading/ILoadingStep.h"
#include "Loading/ICapturedDataProvider.h"
#include "Loading/IHashProvider.h"
class StepVerifyHash final : public ILoadingStep
{
std::unique_ptr<IHashFunction> m_hash_function;
unsigned m_hash_index;
IHashProvider* m_hash_provider;
ICapturedDataProvider* m_data_provider;
public:
StepVerifyHash(std::unique_ptr<IHashFunction> hashFunction, unsigned hashIndex, IHashProvider* hashProvider, ICapturedDataProvider* dataProvider);
~StepVerifyHash();
StepVerifyHash(const StepVerifyHash& other) = delete;
StepVerifyHash(StepVerifyHash&& other) noexcept = default;
StepVerifyHash& operator=(const StepVerifyHash& other) = delete;
StepVerifyHash& operator=(StepVerifyHash&& other) noexcept = default;
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
};

View File

@ -2,7 +2,7 @@
#include "Loading/Exception/InvalidSignatureException.h"
#include <cassert>
StepVerifySignature::StepVerifySignature(IPublicKeyAlgorithm* signatureAlgorithm, ISignatureProvider* signatureProvider, ISignatureDataProvider* signatureDataProvider)
StepVerifySignature::StepVerifySignature(IPublicKeyAlgorithm* signatureAlgorithm, ISignatureProvider* signatureProvider, ICapturedDataProvider* signatureDataProvider)
{
m_algorithm = signatureAlgorithm;
m_signature_provider = signatureProvider;
@ -27,7 +27,7 @@ void StepVerifySignature::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* st
const uint8_t* signatureData;
size_t signatureDataSize;
m_signature_data_provider->GetSignatureData(&signatureData, &signatureDataSize);
m_signature_data_provider->GetCapturedData(&signatureData, &signatureDataSize);
if(!m_algorithm->Verify(signatureData, signatureDataSize, signature, signatureSize))
{

View File

@ -3,17 +3,21 @@
#include "Loading/ILoadingStep.h"
#include "Crypto.h"
#include "Loading/ISignatureProvider.h"
#include "Loading/ISignatureDataProvider.h"
#include "Loading/ICapturedDataProvider.h"
class StepVerifySignature final : public ILoadingStep
{
IPublicKeyAlgorithm* m_algorithm;
ISignatureProvider* m_signature_provider;
ISignatureDataProvider* m_signature_data_provider;
ICapturedDataProvider* m_signature_data_provider;
public:
StepVerifySignature(IPublicKeyAlgorithm* signatureAlgorithm, ISignatureProvider* signatureProvider, ISignatureDataProvider* signatureDataProvider);
StepVerifySignature(IPublicKeyAlgorithm* signatureAlgorithm, ISignatureProvider* signatureProvider, ICapturedDataProvider* signatureDataProvider);
~StepVerifySignature();
StepVerifySignature(const StepVerifySignature& other) = default;
StepVerifySignature(StepVerifySignature&& other) noexcept = default;
StepVerifySignature& operator=(const StepVerifySignature& other) = default;
StepVerifySignature& operator=(StepVerifySignature&& other) noexcept = default;
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
};

View File

@ -63,6 +63,17 @@ void ZoneLoader::AddStreamProcessor(StreamProcessor* streamProcessor)
m_processor_chain_dirty = true;
}
void ZoneLoader::RemoveStreamProcessor(StreamProcessor* streamProcessor)
{
const auto foundEntry = std::find(m_processors.begin(), m_processors.end(), streamProcessor);
if(foundEntry != m_processors.end())
{
m_processors.erase(foundEntry);
m_processor_chain_dirty = true;
}
}
Zone* ZoneLoader::LoadZone(FileAPI::File* file)
{
LoadingFileStream fileStream(file);
@ -93,4 +104,4 @@ Zone* ZoneLoader::LoadZone(FileAPI::File* file)
m_zone->Register();
return m_zone;
}
}

View File

@ -31,5 +31,7 @@ public:
void AddLoadingStep(ILoadingStep* step);
void AddStreamProcessor(StreamProcessor* streamProcessor);
void RemoveStreamProcessor(StreamProcessor* streamProcessor);
Zone* LoadZone(FileAPI::File* file);
};