mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-19 15:52:53 +00:00
Move XChunk processors to ZoneCommon
This commit is contained in:
parent
ca1329323b
commit
f22012d282
@ -4,22 +4,22 @@
|
||||
#include "Impl/AlgorithmSalsa20.h"
|
||||
#include "Impl/AlgorithmSHA256.h"
|
||||
|
||||
IHashFunction* Crypto::CreateSHA1()
|
||||
std::unique_ptr<IHashFunction> Crypto::CreateSHA1()
|
||||
{
|
||||
return new AlgorithmSHA1();
|
||||
return std::make_unique<AlgorithmSHA1>();
|
||||
}
|
||||
|
||||
IHashFunction* Crypto::CreateSHA256()
|
||||
std::unique_ptr<IHashFunction> Crypto::CreateSHA256()
|
||||
{
|
||||
return new AlgorithmSHA256();
|
||||
return std::make_unique<AlgorithmSHA256>();
|
||||
}
|
||||
|
||||
IStreamCipher* Crypto::CreateSalsa20(const uint8_t* keyBytes, const size_t keySize)
|
||||
std::unique_ptr<IStreamCipher> Crypto::CreateSalsa20(const uint8_t* keyBytes, const size_t keySize)
|
||||
{
|
||||
return new AlgorithmSalsa20(keyBytes, keySize);
|
||||
return std::make_unique<AlgorithmSalsa20>(keyBytes, keySize);
|
||||
}
|
||||
|
||||
IPublicKeyAlgorithm* Crypto::CreateRSA(const IPublicKeyAlgorithm::HashingAlgorithm hashingAlgorithm, const RSAPaddingMode paddingMode)
|
||||
std::unique_ptr<IPublicKeyAlgorithm> Crypto::CreateRSA(const IPublicKeyAlgorithm::HashingAlgorithm hashingAlgorithm, const RSAPaddingMode paddingMode)
|
||||
{
|
||||
return new AlgorithmRSA(hashingAlgorithm, paddingMode);
|
||||
return std::make_unique<AlgorithmRSA>(hashingAlgorithm, paddingMode);
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
|
||||
#include "IHashFunction.h"
|
||||
#include "IStreamCipher.h"
|
||||
@ -15,10 +17,10 @@ public:
|
||||
RSA_PADDING_PSS,
|
||||
};
|
||||
|
||||
static IHashFunction* CreateSHA1();
|
||||
static IHashFunction* CreateSHA256();
|
||||
static std::unique_ptr<IHashFunction> CreateSHA1();
|
||||
static std::unique_ptr<IHashFunction> CreateSHA256();
|
||||
|
||||
static IStreamCipher* CreateSalsa20(const uint8_t* keyBytes, size_t keySize);
|
||||
static std::unique_ptr<IStreamCipher> CreateSalsa20(const uint8_t* keyBytes, size_t keySize);
|
||||
|
||||
static IPublicKeyAlgorithm* CreateRSA(IPublicKeyAlgorithm::HashingAlgorithm hashingAlgorithm, RSAPaddingMode paddingMode);
|
||||
static std::unique_ptr<IPublicKeyAlgorithm> CreateRSA(IPublicKeyAlgorithm::HashingAlgorithm hashingAlgorithm, RSAPaddingMode paddingMode);
|
||||
};
|
||||
|
@ -9,12 +9,14 @@ function ZoneCommon:include(includes)
|
||||
Common:include(includes)
|
||||
ObjCommon:include(includes)
|
||||
Parser:include(includes)
|
||||
Crypto:include(includes)
|
||||
end
|
||||
end
|
||||
|
||||
function ZoneCommon:link(links)
|
||||
links:add(self:name())
|
||||
links:linkto(Common)
|
||||
links:linkto(Crypto)
|
||||
links:linkto(ObjCommon)
|
||||
links:linkto(Parser)
|
||||
links:linkto(Utils)
|
||||
|
53
src/ZoneCommon/Zone/XChunk/AbstractSalsa20Processor.cpp
Normal file
53
src/ZoneCommon/Zone/XChunk/AbstractSalsa20Processor.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include "AbstractSalsa20Processor.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
AbstractSalsa20Processor::AbstractSalsa20Processor(const int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize)
|
||||
: m_stream_count(streamCount),
|
||||
m_stream_contexts(std::make_unique<StreamContext[]>(streamCount)),
|
||||
m_block_hashes(std::make_unique<uint8_t[]>(BLOCK_HASHES_COUNT * streamCount * SHA1_HASH_SIZE)),
|
||||
m_stream_block_indices(std::make_unique<unsigned int[]>(streamCount))
|
||||
{
|
||||
InitStreams(zoneName, salsa20Key, keySize);
|
||||
}
|
||||
|
||||
uint8_t* AbstractSalsa20Processor::GetHashBlock(const int streamNumber) const
|
||||
{
|
||||
const auto blockIndexOffset = m_stream_block_indices[streamNumber] * m_stream_count * SHA1_HASH_SIZE;
|
||||
const auto streamOffset = static_cast<size_t>(streamNumber) * SHA1_HASH_SIZE;
|
||||
|
||||
return &m_block_hashes[blockIndexOffset + streamOffset];
|
||||
}
|
||||
|
||||
void AbstractSalsa20Processor::InitStreams(std::string& zoneName, const uint8_t* salsa20Key, size_t keySize) const
|
||||
{
|
||||
const int zoneNameLength = zoneName.length();
|
||||
const size_t blockHashBufferSize = BLOCK_HASHES_COUNT * m_stream_count * SHA1_HASH_SIZE;
|
||||
|
||||
assert(blockHashBufferSize % 4 == 0);
|
||||
|
||||
size_t zoneNameOffset = 0;
|
||||
for (size_t i = 0; i < blockHashBufferSize; i += 4)
|
||||
{
|
||||
*reinterpret_cast<uint32_t*>(&m_block_hashes[i]) = 0x1010101 * zoneName[zoneNameOffset++];
|
||||
|
||||
zoneNameOffset %= zoneNameLength;
|
||||
}
|
||||
|
||||
for (auto stream = 0; stream < m_stream_count; stream++)
|
||||
{
|
||||
m_stream_block_indices[stream] = 0;
|
||||
|
||||
m_stream_contexts[stream].m_salsa20 = Crypto::CreateSalsa20(salsa20Key, keySize);
|
||||
m_stream_contexts[stream].m_sha1 = Crypto::CreateSHA1();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractSalsa20Processor::GetCapturedData(const uint8_t** pCapturedData, size_t* pSize)
|
||||
{
|
||||
assert(pCapturedData != nullptr);
|
||||
assert(pSize != nullptr);
|
||||
|
||||
*pCapturedData = m_block_hashes.get();
|
||||
*pSize = BLOCK_HASHES_COUNT * m_stream_count * SHA1_HASH_SIZE;
|
||||
}
|
45
src/ZoneCommon/Zone/XChunk/AbstractSalsa20Processor.h
Normal file
45
src/ZoneCommon/Zone/XChunk/AbstractSalsa20Processor.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Crypto.h"
|
||||
#include "Utils/ICapturedDataProvider.h"
|
||||
|
||||
class AbstractSalsa20Processor : public ICapturedDataProvider
|
||||
{
|
||||
protected:
|
||||
static constexpr int BLOCK_HASHES_COUNT = 200;
|
||||
static constexpr int SHA1_HASH_SIZE = 20;
|
||||
static constexpr int SALSA20_IV_SIZE = 8;
|
||||
|
||||
class StreamContext
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<IStreamCipher> m_salsa20;
|
||||
std::unique_ptr<IHashFunction> m_sha1;
|
||||
};
|
||||
|
||||
int m_stream_count;
|
||||
std::unique_ptr<StreamContext[]> m_stream_contexts;
|
||||
|
||||
// m_block_hashes[BLOCK_HASHES_COUNT][numStreams][HASH_SIZE]
|
||||
std::unique_ptr<uint8_t[]> m_block_hashes;
|
||||
std::unique_ptr<unsigned int[]> m_stream_block_indices;
|
||||
|
||||
AbstractSalsa20Processor(int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize);
|
||||
|
||||
_NODISCARD uint8_t* GetHashBlock(int streamNumber) const;
|
||||
|
||||
void InitStreams(std::string& zoneName, const uint8_t* salsa20Key, size_t keySize) const;
|
||||
|
||||
public:
|
||||
virtual ~AbstractSalsa20Processor() = default;
|
||||
AbstractSalsa20Processor(const AbstractSalsa20Processor& other) = delete;
|
||||
AbstractSalsa20Processor(AbstractSalsa20Processor&& other) noexcept = default;
|
||||
AbstractSalsa20Processor& operator=(const AbstractSalsa20Processor& other) = delete;
|
||||
AbstractSalsa20Processor& operator=(AbstractSalsa20Processor&& other) noexcept = default;
|
||||
|
||||
void GetCapturedData(const uint8_t** pCapturedData, size_t* pSize) override;
|
||||
};
|
16
src/ZoneCommon/Zone/XChunk/XChunkException.cpp
Normal file
16
src/ZoneCommon/Zone/XChunk/XChunkException.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include "XChunkException.h"
|
||||
|
||||
XChunkException::XChunkException(std::string message)
|
||||
: m_message(std::move(message))
|
||||
{
|
||||
}
|
||||
|
||||
char const* XChunkException::what() const
|
||||
{
|
||||
return m_message.c_str();
|
||||
}
|
||||
|
||||
const std::string& XChunkException::Message() const
|
||||
{
|
||||
return m_message;
|
||||
}
|
16
src/ZoneCommon/Zone/XChunk/XChunkException.h
Normal file
16
src/ZoneCommon/Zone/XChunk/XChunkException.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
#include "Utils/ClassUtils.h"
|
||||
|
||||
class XChunkException final : public std::exception
|
||||
{
|
||||
std::string m_message;
|
||||
|
||||
public:
|
||||
explicit XChunkException(std::string message);
|
||||
|
||||
_NODISCARD char const* what() const override;
|
||||
_NODISCARD const std::string& Message() const;
|
||||
};
|
33
src/ZoneCommon/Zone/XChunk/XChunkProcessorDeflate.cpp
Normal file
33
src/ZoneCommon/Zone/XChunk/XChunkProcessorDeflate.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "XChunkProcessorDeflate.h"
|
||||
|
||||
#include <zlib.h>
|
||||
#include <zutil.h>
|
||||
|
||||
#include "XChunkException.h"
|
||||
|
||||
size_t XChunkProcessorDeflate::Process(int streamNumber, const uint8_t* input, const size_t inputLength, uint8_t* output, const size_t outputBufferSize)
|
||||
{
|
||||
z_stream stream{};
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
stream.opaque = Z_NULL;
|
||||
|
||||
auto ret = deflateInit2(&stream, Z_BEST_COMPRESSION, Z_DEFLATED, -DEF_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
|
||||
if (ret != Z_OK)
|
||||
throw XChunkException("Initializing deflate failed.");
|
||||
|
||||
stream.avail_in = inputLength;
|
||||
stream.next_in = input;
|
||||
stream.avail_out = outputBufferSize;
|
||||
stream.next_out = output;
|
||||
|
||||
ret = deflate(&stream, Z_FINISH);
|
||||
if (ret != Z_STREAM_END)
|
||||
throw XChunkException("Zone has invalid or unsupported compression. Deflate failed");
|
||||
|
||||
const size_t outputSize = stream.total_out;
|
||||
|
||||
deflateEnd(&stream);
|
||||
|
||||
return outputSize;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "IXChunkProcessor.h"
|
||||
|
||||
class ChunkProcessorInflate : public IXChunkProcessor
|
||||
class XChunkProcessorDeflate final : public IXChunkProcessor
|
||||
{
|
||||
public:
|
||||
size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) override;
|
33
src/ZoneCommon/Zone/XChunk/XChunkProcessorInflate.cpp
Normal file
33
src/ZoneCommon/Zone/XChunk/XChunkProcessorInflate.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "XChunkProcessorInflate.h"
|
||||
|
||||
#include <zlib.h>
|
||||
#include <zutil.h>
|
||||
|
||||
#include "XChunkException.h"
|
||||
|
||||
size_t XChunkProcessorInflate::Process(int streamNumber, const uint8_t* input, const size_t inputLength, uint8_t* output, const size_t outputBufferSize)
|
||||
{
|
||||
z_stream stream{};
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
stream.opaque = Z_NULL;
|
||||
|
||||
auto ret = inflateInit2(&stream, -DEF_WBITS);
|
||||
if (ret != Z_OK)
|
||||
throw XChunkException("Initializing inflate failed.");
|
||||
|
||||
stream.avail_in = inputLength;
|
||||
stream.next_in = input;
|
||||
stream.avail_out = outputBufferSize;
|
||||
stream.next_out = output;
|
||||
|
||||
ret = inflate(&stream, Z_FULL_FLUSH);
|
||||
if (ret != Z_STREAM_END)
|
||||
throw XChunkException("Zone has invalid or unsupported compression. Inflate failed");
|
||||
|
||||
const size_t outputSize = stream.total_out;
|
||||
|
||||
inflateEnd(&stream);
|
||||
|
||||
return outputSize;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "IXChunkOutputProcessor.h"
|
||||
#include "IXChunkProcessor.h"
|
||||
|
||||
class XChunkOutputProcessorDeflate final : public IXChunkOutputProcessor
|
||||
class XChunkProcessorInflate final : public IXChunkProcessor
|
||||
{
|
||||
public:
|
||||
size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) override;
|
@ -0,0 +1,44 @@
|
||||
#include "XChunkProcessorSalsa20Decryption.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "Crypto.h"
|
||||
#include "AbstractSalsa20Processor.h"
|
||||
|
||||
XChunkProcessorSalsa20Decryption::XChunkProcessorSalsa20Decryption(const int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize)
|
||||
: AbstractSalsa20Processor(streamCount, zoneName, salsa20Key, keySize)
|
||||
{
|
||||
}
|
||||
|
||||
size_t XChunkProcessorSalsa20Decryption::Process(const int streamNumber, const uint8_t* input, const size_t inputLength, uint8_t* output, const size_t outputBufferSize)
|
||||
{
|
||||
assert(streamNumber >= 0 && streamNumber < m_stream_count);
|
||||
assert(input != nullptr);
|
||||
assert(output != nullptr);
|
||||
assert(inputLength <= outputBufferSize);
|
||||
|
||||
auto& streamContext = m_stream_contexts[streamNumber];
|
||||
|
||||
// Initialize Salsa20 with an IV of the first 8 bytes of the current hash block
|
||||
streamContext.m_salsa20->SetIV(GetHashBlock(streamNumber), SALSA20_IV_SIZE);
|
||||
streamContext.m_salsa20->Process(input, output, inputLength);
|
||||
|
||||
// Hash decrypted XChunk
|
||||
uint8_t blockSha1Hash[SHA1_HASH_SIZE];
|
||||
streamContext.m_sha1->Init();
|
||||
streamContext.m_sha1->Process(output, inputLength);
|
||||
streamContext.m_sha1->Finish(&blockSha1Hash);
|
||||
|
||||
// Advance index to next hash block
|
||||
m_stream_block_indices[streamNumber] = (m_stream_block_indices[streamNumber] + 1) % BLOCK_HASHES_COUNT;
|
||||
|
||||
auto* nextHashBlock = GetHashBlock(streamNumber);
|
||||
|
||||
// XOR the upcoming hash block with the hash of the XChunk utilizing the previous hash block
|
||||
for (unsigned int hashOffset = 0; hashOffset < sizeof(blockSha1Hash); hashOffset++)
|
||||
{
|
||||
nextHashBlock[hashOffset] ^= blockSha1Hash[hashOffset];
|
||||
}
|
||||
|
||||
return inputLength;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include "IXChunkProcessor.h"
|
||||
#include "AbstractSalsa20Processor.h"
|
||||
|
||||
class XChunkProcessorSalsa20Decryption final : public IXChunkProcessor, public AbstractSalsa20Processor
|
||||
{
|
||||
public:
|
||||
XChunkProcessorSalsa20Decryption(int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize);
|
||||
|
||||
size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) override;
|
||||
};
|
@ -0,0 +1,41 @@
|
||||
#include "XChunkProcessorSalsa20Encryption.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
XChunkProcessorSalsa20Encryption::XChunkProcessorSalsa20Encryption(const int streamCount, std::string& zoneName, const uint8_t* salsa20Key, const size_t keySize)
|
||||
: AbstractSalsa20Processor(streamCount, zoneName, salsa20Key, keySize)
|
||||
{
|
||||
}
|
||||
|
||||
size_t XChunkProcessorSalsa20Encryption::Process(const int streamNumber, const uint8_t* input, const size_t inputLength, uint8_t* output, const size_t outputBufferSize)
|
||||
{
|
||||
assert(streamNumber >= 0 && streamNumber < m_stream_count);
|
||||
assert(input != nullptr);
|
||||
assert(output != nullptr);
|
||||
assert(inputLength <= outputBufferSize);
|
||||
|
||||
auto& streamContext = m_stream_contexts[streamNumber];
|
||||
|
||||
// Hash not yet encrypted XChunk
|
||||
uint8_t blockSha1Hash[SHA1_HASH_SIZE];
|
||||
streamContext.m_sha1->Init();
|
||||
streamContext.m_sha1->Process(input, inputLength);
|
||||
streamContext.m_sha1->Finish(&blockSha1Hash);
|
||||
|
||||
// Initialize Salsa20 with an IV of the first 8 bytes of the current hash block
|
||||
streamContext.m_salsa20->SetIV(GetHashBlock(streamNumber), SALSA20_IV_SIZE);
|
||||
streamContext.m_salsa20->Process(input, output, inputLength);
|
||||
|
||||
// Advance index to next hash block
|
||||
m_stream_block_indices[streamNumber] = (m_stream_block_indices[streamNumber] + 1) % BLOCK_HASHES_COUNT;
|
||||
|
||||
auto* nextHashBlock = GetHashBlock(streamNumber);
|
||||
|
||||
// XOR the upcoming hash block with the hash of the XChunk utilizing the previous hash block
|
||||
for (unsigned int hashOffset = 0; hashOffset < sizeof(blockSha1Hash); hashOffset++)
|
||||
{
|
||||
nextHashBlock[hashOffset] ^= blockSha1Hash[hashOffset];
|
||||
}
|
||||
|
||||
return inputLength;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "AbstractSalsa20Processor.h"
|
||||
#include "IXChunkProcessor.h"
|
||||
|
||||
class XChunkProcessorSalsa20Encryption final : public IXChunkProcessor, public AbstractSalsa20Processor
|
||||
{
|
||||
public:
|
||||
XChunkProcessorSalsa20Encryption(int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize);
|
||||
|
||||
size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) override;
|
||||
};
|
@ -79,18 +79,16 @@ class ZoneLoaderFactory::Impl
|
||||
#undef XBLOCK_DEF
|
||||
}
|
||||
|
||||
static IPublicKeyAlgorithm* SetupRSA(const bool isOfficial)
|
||||
static std::unique_ptr<IPublicKeyAlgorithm> SetupRSA(const bool isOfficial)
|
||||
{
|
||||
if (isOfficial)
|
||||
{
|
||||
auto* rsa = Crypto::CreateRSA(IPublicKeyAlgorithm::HashingAlgorithm::RSA_HASH_SHA256,
|
||||
auto rsa = Crypto::CreateRSA(IPublicKeyAlgorithm::HashingAlgorithm::RSA_HASH_SHA256,
|
||||
Crypto::RSAPaddingMode::RSA_PADDING_PSS);
|
||||
|
||||
if (!rsa->SetKey(ZoneConstants::RSA_PUBLIC_KEY_INFINITY_WARD, sizeof(ZoneConstants::RSA_PUBLIC_KEY_INFINITY_WARD)))
|
||||
{
|
||||
printf("Invalid public key for signature checking\n");
|
||||
|
||||
delete rsa;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -113,7 +111,7 @@ class ZoneLoaderFactory::Impl
|
||||
return;
|
||||
|
||||
// If file is signed setup a RSA instance.
|
||||
IPublicKeyAlgorithm* rsa = SetupRSA(isOfficial);
|
||||
auto rsa = SetupRSA(isOfficial);
|
||||
|
||||
zoneLoader->AddLoadingStep(std::make_unique<StepVerifyMagic>(ZoneConstants::MAGIC_AUTH_HEADER));
|
||||
zoneLoader->AddLoadingStep(std::make_unique<StepSkipBytes>(4)); // Skip reserved
|
||||
@ -126,7 +124,7 @@ class ZoneLoaderFactory::Impl
|
||||
auto* subHeaderHashSignaturePtr = subHeaderHashSignature.get();
|
||||
zoneLoader->AddLoadingStep(std::move(subHeaderHashSignature));
|
||||
|
||||
zoneLoader->AddLoadingStep(std::make_unique<StepVerifySignature>(rsa, subHeaderHashSignaturePtr, subHeaderHashPtr));
|
||||
zoneLoader->AddLoadingStep(std::make_unique<StepVerifySignature>(std::move(rsa), subHeaderHashSignaturePtr, subHeaderHashPtr));
|
||||
|
||||
auto subHeaderCapture = std::make_unique<ProcessorCaptureData>(sizeof(DB_AuthSubHeader));
|
||||
auto* subHeaderCapturePtr = subHeaderCapture.get();
|
||||
|
@ -12,8 +12,8 @@
|
||||
#include "Game/GameLanguage.h"
|
||||
#include "Game/T6/GameT6.h"
|
||||
#include "Loading/Processor/ProcessorXChunks.h"
|
||||
#include "Loading/Processor/XChunks/ChunkProcessorSalsa20.h"
|
||||
#include "Loading/Processor/XChunks/ChunkProcessorInflate.h"
|
||||
#include "Zone/XChunk/XChunkProcessorSalsa20Decryption.h"
|
||||
#include "Zone/XChunk/XChunkProcessorInflate.h"
|
||||
#include "Loading/Steps/StepVerifyMagic.h"
|
||||
#include "Loading/Steps/StepSkipBytes.h"
|
||||
#include "Loading/Steps/StepVerifyFileName.h"
|
||||
@ -104,17 +104,15 @@ class ZoneLoaderFactory::Impl
|
||||
#undef XBLOCK_DEF
|
||||
}
|
||||
|
||||
static IPublicKeyAlgorithm* SetupRSA(const bool isOfficial)
|
||||
static std::unique_ptr<IPublicKeyAlgorithm> SetupRSA(const bool isOfficial)
|
||||
{
|
||||
if (isOfficial)
|
||||
{
|
||||
auto* rsa = Crypto::CreateRSA(IPublicKeyAlgorithm::HashingAlgorithm::RSA_HASH_SHA256, Crypto::RSAPaddingMode::RSA_PADDING_PSS);
|
||||
auto rsa = Crypto::CreateRSA(IPublicKeyAlgorithm::HashingAlgorithm::RSA_HASH_SHA256, Crypto::RSAPaddingMode::RSA_PADDING_PSS);
|
||||
|
||||
if (!rsa->SetKey(ZoneConstants::RSA_PUBLIC_KEY_TREYARCH, sizeof(ZoneConstants::RSA_PUBLIC_KEY_TREYARCH)))
|
||||
{
|
||||
printf("Invalid public key for signature checking\n");
|
||||
|
||||
delete rsa;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -154,14 +152,14 @@ class ZoneLoaderFactory::Impl
|
||||
if (isEncrypted)
|
||||
{
|
||||
// If zone is encrypted, the decryption is applied before the decompression. T6 Zones always use Salsa20.
|
||||
auto chunkProcessorSalsa20 = std::make_unique<ChunkProcessorSalsa20>(ZoneConstants::STREAM_COUNT, fileName, ZoneConstants::SALSA20_KEY_TREYARCH,
|
||||
auto chunkProcessorSalsa20 = std::make_unique<XChunkProcessorSalsa20Decryption>(ZoneConstants::STREAM_COUNT, fileName, ZoneConstants::SALSA20_KEY_TREYARCH,
|
||||
sizeof(ZoneConstants::SALSA20_KEY_TREYARCH));
|
||||
result = chunkProcessorSalsa20.get();
|
||||
xChunkProcessor->AddChunkProcessor(std::move(chunkProcessorSalsa20));
|
||||
}
|
||||
|
||||
// Decompress the chunks using zlib
|
||||
xChunkProcessor->AddChunkProcessor(std::make_unique<ChunkProcessorInflate>());
|
||||
xChunkProcessor->AddChunkProcessor(std::make_unique<XChunkProcessorInflate>());
|
||||
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(std::move(xChunkProcessor)));
|
||||
|
||||
// If there is encryption, the signed data of the zone is the final hash blocks provided by the Salsa20 IV adaption algorithm
|
||||
@ -190,7 +188,7 @@ public:
|
||||
SetupBlock(zoneLoader);
|
||||
|
||||
// If file is signed setup a RSA instance.
|
||||
IPublicKeyAlgorithm* rsa = isSecure ? SetupRSA(isOfficial) : nullptr;
|
||||
auto rsa = isSecure ? SetupRSA(isOfficial) : nullptr;
|
||||
|
||||
// Add steps for loading the auth header which also contain the signature of the zone if it is signed.
|
||||
ISignatureProvider* signatureProvider = AddAuthHeaderSteps(isSecure, zoneLoader, fileName);
|
||||
@ -207,7 +205,7 @@ public:
|
||||
|
||||
if (isSecure)
|
||||
{
|
||||
zoneLoader->AddLoadingStep(std::make_unique<StepVerifySignature>(rsa, signatureProvider, signatureDataProvider));
|
||||
zoneLoader->AddLoadingStep(std::make_unique<StepVerifySignature>(std::move(rsa), signatureProvider, signatureDataProvider));
|
||||
}
|
||||
|
||||
// Return the fully setup zoneloader
|
||||
|
@ -8,11 +8,14 @@
|
||||
#include <condition_variable>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
class DBLoadStream
|
||||
{
|
||||
int m_index;
|
||||
|
||||
std::unique_ptr<uint8_t[]> m_buffers[2];
|
||||
|
||||
uint8_t* m_input_buffer;
|
||||
size_t m_input_size;
|
||||
|
||||
@ -62,8 +65,11 @@ public:
|
||||
m_index = streamIndex;
|
||||
m_chunk_size = chunkSize;
|
||||
|
||||
m_input_buffer = new uint8_t[chunkSize];
|
||||
m_output_buffer = new uint8_t[chunkSize];
|
||||
for(auto& buffer : m_buffers)
|
||||
buffer = std::make_unique<uint8_t[]>(chunkSize);
|
||||
|
||||
m_input_buffer = m_buffers[0].get();
|
||||
m_output_buffer = m_buffers[1].get();
|
||||
|
||||
m_input_size = 0;
|
||||
m_output_size = 0;
|
||||
@ -71,15 +77,6 @@ public:
|
||||
m_is_loading = false;
|
||||
}
|
||||
|
||||
~DBLoadStream()
|
||||
{
|
||||
delete[] m_input_buffer;
|
||||
m_input_buffer = nullptr;
|
||||
|
||||
delete[] m_output_buffer;
|
||||
m_output_buffer = nullptr;
|
||||
}
|
||||
|
||||
uint8_t* GetInputBuffer() const
|
||||
{
|
||||
return m_input_buffer;
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "Loading/StreamProcessor.h"
|
||||
#include "XChunks/IXChunkProcessor.h"
|
||||
#include "Zone/XChunk/IXChunkProcessor.h"
|
||||
|
||||
class ProcessorXChunks : public StreamProcessor
|
||||
{
|
||||
|
@ -1,39 +0,0 @@
|
||||
#include "ChunkProcessorInflate.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "zlib.h"
|
||||
#include "zutil.h"
|
||||
|
||||
#include "Loading/Exception/InvalidCompressionException.h"
|
||||
|
||||
size_t ChunkProcessorInflate::Process(int streamNumber, const uint8_t* input, const size_t inputLength, uint8_t* output, const size_t outputBufferSize)
|
||||
{
|
||||
z_stream stream{};
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
stream.opaque = Z_NULL;
|
||||
|
||||
int ret = inflateInit2(&stream, -DEF_WBITS);
|
||||
if(ret != Z_OK)
|
||||
{
|
||||
throw std::runtime_error("Initializing inflate failed.");
|
||||
}
|
||||
|
||||
stream.avail_in = inputLength;
|
||||
stream.next_in = input;
|
||||
stream.avail_out = outputBufferSize;
|
||||
stream.next_out = output;
|
||||
|
||||
ret = inflate(&stream, Z_FULL_FLUSH);
|
||||
if(ret != Z_STREAM_END)
|
||||
{
|
||||
throw InvalidCompressionException();
|
||||
}
|
||||
|
||||
const size_t outputSize = stream.total_out;
|
||||
|
||||
inflateEnd(&stream);
|
||||
|
||||
return outputSize;
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
#include "ChunkProcessorSalsa20.h"
|
||||
#include "Crypto.h"
|
||||
#include <cassert>
|
||||
|
||||
class StreamContextSalsa20
|
||||
{
|
||||
public:
|
||||
IStreamCipher* m_salsa20;
|
||||
IHashFunction* m_sha1;
|
||||
|
||||
StreamContextSalsa20()
|
||||
{
|
||||
m_salsa20 = nullptr;
|
||||
m_sha1 = nullptr;
|
||||
}
|
||||
|
||||
~StreamContextSalsa20()
|
||||
{
|
||||
delete m_salsa20;
|
||||
m_salsa20 = nullptr;
|
||||
|
||||
delete m_sha1;
|
||||
m_sha1 = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
class ChunkProcessorSalsa20::ChunkProcessorSalsa20Impl
|
||||
{
|
||||
static const int BLOCK_HASHES_COUNT = 200;
|
||||
static const int SHA1_HASH_SIZE = 20;
|
||||
static const int SALSA20_IV_SIZE = 8;
|
||||
|
||||
int m_stream_count;
|
||||
StreamContextSalsa20* m_stream_contexts;
|
||||
|
||||
// m_block_hashes[BLOCK_HASHES_COUNT][numStreams][HASH_SIZE]
|
||||
uint8_t* m_block_hashes;
|
||||
unsigned int* m_stream_block_indices;
|
||||
|
||||
uint8_t* GetHashBlock(const int streamNumber) const
|
||||
{
|
||||
const size_t blockIndexOffset = m_stream_block_indices[streamNumber] * m_stream_count * SHA1_HASH_SIZE;
|
||||
const size_t streamOffset = streamNumber * SHA1_HASH_SIZE;
|
||||
|
||||
return &m_block_hashes[blockIndexOffset + streamOffset];
|
||||
}
|
||||
|
||||
public:
|
||||
ChunkProcessorSalsa20Impl(const int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize)
|
||||
{
|
||||
m_stream_count = streamCount;
|
||||
m_stream_contexts = new StreamContextSalsa20[streamCount];
|
||||
m_block_hashes = new uint8_t[BLOCK_HASHES_COUNT * streamCount * SHA1_HASH_SIZE];
|
||||
m_stream_block_indices = new unsigned int[streamCount];
|
||||
|
||||
InitStreams(zoneName, salsa20Key, keySize);
|
||||
}
|
||||
|
||||
~ChunkProcessorSalsa20Impl()
|
||||
{
|
||||
delete[] m_stream_contexts;
|
||||
|
||||
delete[] m_block_hashes;
|
||||
m_block_hashes = nullptr;
|
||||
|
||||
delete[] m_stream_block_indices;
|
||||
m_stream_block_indices = nullptr;
|
||||
}
|
||||
|
||||
void InitStreams(std::string& zoneName, const uint8_t* salsa20Key, size_t keySize) const
|
||||
{
|
||||
const int zoneNameLength = zoneName.length();
|
||||
const size_t blockHashBufferSize = BLOCK_HASHES_COUNT * m_stream_count * SHA1_HASH_SIZE;
|
||||
|
||||
assert(blockHashBufferSize % 4 == 0);
|
||||
|
||||
size_t zoneNameOffset = 0;
|
||||
for(size_t i = 0; i < blockHashBufferSize; i += 4)
|
||||
{
|
||||
*reinterpret_cast<uint32_t*>(&m_block_hashes[i]) = 0x1010101 * zoneName[zoneNameOffset++];
|
||||
|
||||
zoneNameOffset %= zoneNameLength;
|
||||
}
|
||||
|
||||
for(int stream = 0; stream < m_stream_count; stream++)
|
||||
{
|
||||
m_stream_block_indices[stream] = 0;
|
||||
|
||||
m_stream_contexts[stream].m_salsa20 = Crypto::CreateSalsa20(salsa20Key, keySize);
|
||||
m_stream_contexts[stream].m_sha1 = Crypto::CreateSHA1();
|
||||
}
|
||||
}
|
||||
|
||||
size_t Process(const int streamNumber, const uint8_t* input, const size_t inputLength, uint8_t* output, const size_t outputBufferSize) const
|
||||
{
|
||||
assert(streamNumber >= 0 && streamNumber < m_stream_count);
|
||||
assert(input != nullptr);
|
||||
assert(output != nullptr);
|
||||
assert(inputLength <= outputBufferSize);
|
||||
|
||||
StreamContextSalsa20& streamContext = m_stream_contexts[streamNumber];
|
||||
|
||||
// Initialize Salsa20 with an IV of the first 8 bytes of the current hash block
|
||||
streamContext.m_salsa20->SetIV(GetHashBlock(streamNumber), SALSA20_IV_SIZE);
|
||||
streamContext.m_salsa20->Process(input, output, inputLength);
|
||||
|
||||
// Hash decrypted XChunk
|
||||
uint8_t blockSha1Hash[SHA1_HASH_SIZE];
|
||||
streamContext.m_sha1->Init();
|
||||
streamContext.m_sha1->Process(output, inputLength);
|
||||
streamContext.m_sha1->Finish(&blockSha1Hash);
|
||||
|
||||
// Advance index to next hash block
|
||||
m_stream_block_indices[streamNumber] = (m_stream_block_indices[streamNumber] + 1) % BLOCK_HASHES_COUNT;
|
||||
|
||||
uint8_t* nextHashBlock = GetHashBlock(streamNumber);
|
||||
|
||||
// XOR the upcoming hash block with the hash of the XChunk utilizing the previous hash block
|
||||
for(unsigned int hashOffset = 0; hashOffset < sizeof(blockSha1Hash); hashOffset++)
|
||||
{
|
||||
nextHashBlock[hashOffset] ^= blockSha1Hash[hashOffset];
|
||||
}
|
||||
|
||||
return inputLength;
|
||||
}
|
||||
|
||||
void GetSignatureData(const uint8_t** pSignatureData, size_t* pSize) const
|
||||
{
|
||||
assert(pSignatureData != nullptr);
|
||||
assert(pSize != nullptr);
|
||||
|
||||
*pSignatureData = m_block_hashes;
|
||||
*pSize = BLOCK_HASHES_COUNT * m_stream_count * SHA1_HASH_SIZE;
|
||||
}
|
||||
};
|
||||
|
||||
ChunkProcessorSalsa20::ChunkProcessorSalsa20(const int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize)
|
||||
{
|
||||
m_impl = new ChunkProcessorSalsa20Impl(streamCount, zoneName, salsa20Key, keySize);
|
||||
}
|
||||
|
||||
ChunkProcessorSalsa20::~ChunkProcessorSalsa20()
|
||||
{
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
|
||||
size_t ChunkProcessorSalsa20::Process(const int streamNumber, const uint8_t* input, const size_t inputLength, uint8_t* output, const size_t outputBufferSize)
|
||||
{
|
||||
return m_impl->Process(streamNumber, input, inputLength, output, outputBufferSize);
|
||||
}
|
||||
|
||||
void ChunkProcessorSalsa20::GetCapturedData(const uint8_t** pCapturedData, size_t* pSize)
|
||||
{
|
||||
m_impl->GetSignatureData(pCapturedData, pSize);
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
#include "IXChunkProcessor.h"
|
||||
#include "Utils/ICapturedDataProvider.h"
|
||||
#include <string>
|
||||
|
||||
class ChunkProcessorSalsa20 : public IXChunkProcessor, public ICapturedDataProvider
|
||||
{
|
||||
class ChunkProcessorSalsa20Impl;
|
||||
ChunkProcessorSalsa20Impl* m_impl;
|
||||
|
||||
public:
|
||||
ChunkProcessorSalsa20(int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize);
|
||||
~ChunkProcessorSalsa20() override;
|
||||
|
||||
size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) override;
|
||||
void GetCapturedData(const uint8_t** pCapturedData, size_t* pSize) override;
|
||||
};
|
@ -2,17 +2,11 @@
|
||||
#include "Loading/Exception/InvalidSignatureException.h"
|
||||
#include <cassert>
|
||||
|
||||
StepVerifySignature::StepVerifySignature(IPublicKeyAlgorithm* signatureAlgorithm, ISignatureProvider* signatureProvider, ICapturedDataProvider* signatureDataProvider)
|
||||
StepVerifySignature::StepVerifySignature(std::unique_ptr<IPublicKeyAlgorithm> signatureAlgorithm, ISignatureProvider* signatureProvider, ICapturedDataProvider* signatureDataProvider)
|
||||
: m_algorithm(std::move(signatureAlgorithm)),
|
||||
m_signature_provider(signatureProvider),
|
||||
m_signature_data_provider(signatureDataProvider)
|
||||
{
|
||||
m_algorithm = signatureAlgorithm;
|
||||
m_signature_provider = signatureProvider;
|
||||
m_signature_data_provider = signatureDataProvider;
|
||||
}
|
||||
|
||||
StepVerifySignature::~StepVerifySignature()
|
||||
{
|
||||
delete m_algorithm;
|
||||
m_algorithm = nullptr;
|
||||
}
|
||||
|
||||
void StepVerifySignature::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
|
||||
@ -29,8 +23,8 @@ void StepVerifySignature::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* st
|
||||
size_t signatureDataSize;
|
||||
m_signature_data_provider->GetCapturedData(&signatureData, &signatureDataSize);
|
||||
|
||||
if(!m_algorithm->Verify(signatureData, signatureDataSize, signature, signatureSize))
|
||||
if (!m_algorithm->Verify(signatureData, signatureDataSize, signature, signatureSize))
|
||||
{
|
||||
throw InvalidSignatureException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,16 +7,16 @@
|
||||
|
||||
class StepVerifySignature final : public ILoadingStep
|
||||
{
|
||||
IPublicKeyAlgorithm* m_algorithm;
|
||||
std::unique_ptr<IPublicKeyAlgorithm> m_algorithm;
|
||||
ISignatureProvider* m_signature_provider;
|
||||
ICapturedDataProvider* m_signature_data_provider;
|
||||
|
||||
public:
|
||||
StepVerifySignature(IPublicKeyAlgorithm* signatureAlgorithm, ISignatureProvider* signatureProvider, ICapturedDataProvider* signatureDataProvider);
|
||||
~StepVerifySignature();
|
||||
StepVerifySignature(const StepVerifySignature& other) = default;
|
||||
StepVerifySignature(std::unique_ptr<IPublicKeyAlgorithm> signatureAlgorithm, ISignatureProvider* signatureProvider, ICapturedDataProvider* signatureDataProvider);
|
||||
~StepVerifySignature() override = default;
|
||||
StepVerifySignature(const StepVerifySignature& other) = delete;
|
||||
StepVerifySignature(StepVerifySignature&& other) noexcept = default;
|
||||
StepVerifySignature& operator=(const StepVerifySignature& other) = default;
|
||||
StepVerifySignature& operator=(const StepVerifySignature& other) = delete;
|
||||
StepVerifySignature& operator=(StepVerifySignature&& other) noexcept = default;
|
||||
|
||||
void PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream) override;
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include "Game/T6/GameT6.h"
|
||||
#include "Game/T6/ZoneConstantsT6.h"
|
||||
#include "Writing/Processor/OutputProcessorXChunks.h"
|
||||
#include "Writing/Processor/XChunks/XChunkOutputProcessorDeflate.h"
|
||||
#include "Writing/Processor/XChunks/XChunkOutputProcessorSalsa20.h"
|
||||
#include "Zone/XChunk/XChunkProcessorDeflate.h"
|
||||
#include "Zone/XChunk/XChunkProcessorSalsa20Encryption.h"
|
||||
#include "Writing/Steps/StepAddOutputProcessor.h"
|
||||
#include "Writing/Steps/StepWriteXBlockSizes.h"
|
||||
#include "Writing/Steps/StepWriteZoneContentToFile.h"
|
||||
@ -77,14 +77,14 @@ public:
|
||||
if (isEncrypted)
|
||||
{
|
||||
// If zone is encrypted, the decryption is applied before the decompression. T6 Zones always use Salsa20.
|
||||
auto chunkProcessorSalsa20 = std::make_unique<XChunkOutputProcessorSalsa20>(ZoneConstants::STREAM_COUNT, m_zone->m_name, ZoneConstants::SALSA20_KEY_TREYARCH,
|
||||
auto chunkProcessorSalsa20 = std::make_unique<XChunkProcessorSalsa20Encryption>(ZoneConstants::STREAM_COUNT, m_zone->m_name, ZoneConstants::SALSA20_KEY_TREYARCH,
|
||||
sizeof(ZoneConstants::SALSA20_KEY_TREYARCH));
|
||||
result = chunkProcessorSalsa20.get();
|
||||
xChunkProcessor->AddChunkProcessor(std::move(chunkProcessorSalsa20));
|
||||
}
|
||||
|
||||
// Decompress the chunks using zlib
|
||||
xChunkProcessor->AddChunkProcessor(std::make_unique<XChunkOutputProcessorDeflate>());
|
||||
xChunkProcessor->AddChunkProcessor(std::make_unique<XChunkProcessorDeflate>());
|
||||
m_writer->AddWritingStep(std::make_unique<StepAddOutputProcessor>(std::move(xChunkProcessor)));
|
||||
|
||||
// If there is encryption, the signed data of the zone is the final hash blocks provided by the Salsa20 IV adaption algorithm
|
||||
|
@ -32,7 +32,7 @@ OutputProcessorXChunks& OutputProcessorXChunks::operator=(OutputProcessorXChunks
|
||||
return *this;
|
||||
}
|
||||
|
||||
void OutputProcessorXChunks::AddChunkProcessor(std::unique_ptr<IXChunkOutputProcessor> chunkProcessor) const
|
||||
void OutputProcessorXChunks::AddChunkProcessor(std::unique_ptr<IXChunkProcessor> chunkProcessor) const
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "Writing/OutputStreamProcessor.h"
|
||||
#include "XChunks/IXChunkOutputProcessor.h"
|
||||
#include "Zone/XChunk/IXChunkProcessor.h"
|
||||
|
||||
class OutputProcessorXChunks final : public OutputStreamProcessor
|
||||
{
|
||||
@ -19,7 +19,7 @@ public:
|
||||
OutputProcessorXChunks& operator=(const OutputProcessorXChunks& other) = delete;
|
||||
OutputProcessorXChunks& operator=(OutputProcessorXChunks&& other) noexcept;
|
||||
|
||||
void AddChunkProcessor(std::unique_ptr<IXChunkOutputProcessor> chunkProcessor) const;
|
||||
void AddChunkProcessor(std::unique_ptr<IXChunkProcessor> chunkProcessor) const;
|
||||
|
||||
void Write(const void* buffer, size_t length) override;
|
||||
int64_t Pos() override;
|
||||
|
@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
class IXChunkOutputProcessor
|
||||
{
|
||||
public:
|
||||
IXChunkOutputProcessor() = default;
|
||||
virtual ~IXChunkOutputProcessor() = default;
|
||||
IXChunkOutputProcessor(const IXChunkOutputProcessor& other) = default;
|
||||
IXChunkOutputProcessor(IXChunkOutputProcessor&& other) noexcept = default;
|
||||
IXChunkOutputProcessor& operator=(const IXChunkOutputProcessor& other) = default;
|
||||
IXChunkOutputProcessor& operator=(IXChunkOutputProcessor&& other) noexcept = default;
|
||||
|
||||
virtual size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) = 0;
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
#include "IXChunkOutputProcessor.h"
|
||||
#include "Utils/ICapturedDataProvider.h"
|
||||
|
||||
class XChunkOutputProcessorSalsa20 final : public IXChunkOutputProcessor, public ICapturedDataProvider
|
||||
{
|
||||
class Impl;
|
||||
Impl* m_impl;
|
||||
|
||||
public:
|
||||
XChunkOutputProcessorSalsa20(int streamCount, std::string& zoneName, const uint8_t* salsa20Key, size_t keySize);
|
||||
~XChunkOutputProcessorSalsa20() override;
|
||||
XChunkOutputProcessorSalsa20(const XChunkOutputProcessorSalsa20& other) = delete;
|
||||
XChunkOutputProcessorSalsa20(XChunkOutputProcessorSalsa20&& other) noexcept = default;
|
||||
XChunkOutputProcessorSalsa20& operator=(const XChunkOutputProcessorSalsa20& other) = delete;
|
||||
XChunkOutputProcessorSalsa20& operator=(XChunkOutputProcessorSalsa20&& other) noexcept = default;
|
||||
|
||||
size_t Process(int streamNumber, const uint8_t* input, size_t inputLength, uint8_t* output, size_t outputBufferSize) override;
|
||||
void GetCapturedData(const uint8_t** pCapturedData, size_t* pSize) override;
|
||||
};
|
@ -12,5 +12,21 @@ IZoneWriterFactory* ZoneWriterFactories[]
|
||||
|
||||
bool ZoneWriting::WriteZone(std::ostream& stream, Zone* zone)
|
||||
{
|
||||
return true;
|
||||
std::unique_ptr<ZoneWriter> zoneWriter;
|
||||
for (auto* factory : ZoneWriterFactories)
|
||||
{
|
||||
if(factory->SupportsZone(zone))
|
||||
{
|
||||
zoneWriter = factory->CreateWriter(zone);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (zoneWriter == nullptr)
|
||||
{
|
||||
printf("Could not create ZoneWriter for zone '%s'.\n", zone->m_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return zoneWriter->WriteZone(stream);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user