FST: Refactor IV handling
Some checks failed
Build check / build (push) Waiting to run
Generate translation template / generate-pot (push) Failing after 1s

This commit is contained in:
Exzap 2025-05-27 16:51:46 +02:00
parent 783d88a892
commit 7168d20cde
3 changed files with 25 additions and 17 deletions

View file

@ -13,6 +13,8 @@
#define SET_FST_ERROR(__code) if (errorCodeOut) *errorCodeOut = ErrorCode::__code #define SET_FST_ERROR(__code) if (errorCodeOut) *errorCodeOut = ErrorCode::__code
static_assert(sizeof(NCrypto::AesIv) == 16); // make sure IV is actually 16 bytes
class FSTDataSource class FSTDataSource
{ {
public: public:
@ -868,7 +870,7 @@ static_assert(sizeof(FSTHashedBlock) == BLOCK_SIZE);
struct FSTCachedRawBlock struct FSTCachedRawBlock
{ {
FSTRawBlock blockData; FSTRawBlock blockData;
uint8 ivForNextBlock[16]; NCrypto::AesIv ivForNextBlock;
uint64 lastAccess; uint64 lastAccess;
}; };
@ -919,13 +921,13 @@ void FSTVolume::TrimCacheIfRequired(FSTCachedRawBlock** droppedRawBlock, FSTCach
} }
} }
void FSTVolume::DetermineUnhashedBlockIV(uint32 clusterIndex, uint32 blockIndex, uint8 ivOut[16]) void FSTVolume::DetermineUnhashedBlockIV(uint32 clusterIndex, uint32 blockIndex, NCrypto::AesIv& ivOut)
{ {
memset(ivOut, 0, sizeof(ivOut)); ivOut = {};
if(blockIndex == 0) if(blockIndex == 0)
{ {
ivOut[0] = (uint8)(clusterIndex >> 8); ivOut.iv[0] = (uint8)(clusterIndex >> 8);
ivOut[1] = (uint8)(clusterIndex >> 0); ivOut.iv[1] = (uint8)(clusterIndex >> 0);
} }
else else
{ {
@ -936,20 +938,20 @@ void FSTVolume::DetermineUnhashedBlockIV(uint32 clusterIndex, uint32 blockIndex,
auto itr = m_cacheDecryptedRawBlocks.find(cacheBlockId); auto itr = m_cacheDecryptedRawBlocks.find(cacheBlockId);
if (itr != m_cacheDecryptedRawBlocks.end()) if (itr != m_cacheDecryptedRawBlocks.end())
{ {
memcpy(ivOut, itr->second->ivForNextBlock, 16); ivOut = itr->second->ivForNextBlock;
} }
else else
{ {
cemu_assert(m_sectorSize >= 16); cemu_assert(m_sectorSize >= NCrypto::AesIv::SIZE);
uint64 clusterOffset = (uint64)m_cluster[clusterIndex].offset * m_sectorSize; uint64 clusterOffset = (uint64)m_cluster[clusterIndex].offset * m_sectorSize;
uint8 prevIV[16]; NCrypto::AesIv prevIV{};
if (m_dataSource->readData(clusterIndex, clusterOffset, blockIndex * m_sectorSize - 16, prevIV, 16) != 16) if (m_dataSource->readData(clusterIndex, clusterOffset, blockIndex * m_sectorSize - NCrypto::AesIv::SIZE, prevIV.iv, NCrypto::AesIv::SIZE) != NCrypto::AesIv::SIZE)
{ {
cemuLog_log(LogType::Force, "Failed to read IV for raw FST block"); cemuLog_log(LogType::Force, "Failed to read IV for raw FST block");
m_detectedCorruption = true; m_detectedCorruption = true;
return; return;
} }
memcpy(ivOut, prevIV, 16); ivOut = prevIV;
} }
} }
} }
@ -984,10 +986,10 @@ FSTCachedRawBlock* FSTVolume::GetDecryptedRawBlock(uint32 clusterIndex, uint32 b
return nullptr; return nullptr;
} }
// decrypt hash data // decrypt hash data
uint8 iv[16]{}; NCrypto::AesIv iv{};
DetermineUnhashedBlockIV(clusterIndex, blockIndex, iv); DetermineUnhashedBlockIV(clusterIndex, blockIndex, iv);
memcpy(block->ivForNextBlock, block->blockData.rawData.data() + m_sectorSize - 16, 16); std::copy(block->blockData.rawData.data() + m_sectorSize - NCrypto::AesIv::SIZE, block->blockData.rawData.data() + m_sectorSize, block->ivForNextBlock.iv);
AES128_CBC_decrypt(block->blockData.rawData.data(), block->blockData.rawData.data(), m_sectorSize, m_partitionTitlekey.b, iv); AES128_CBC_decrypt(block->blockData.rawData.data(), block->blockData.rawData.data(), m_sectorSize, m_partitionTitlekey.b, iv.iv);
// if this is the next block, then hash it // if this is the next block, then hash it
if(cluster.hasContentHash) if(cluster.hasContentHash)
{ {

View file

@ -83,7 +83,6 @@ public:
} }
private: private:
/* FST data (in memory) */ /* FST data (in memory) */
enum class ClusterHashMode : uint8 enum class ClusterHashMode : uint8
{ {
@ -193,7 +192,7 @@ private:
std::unordered_map<uint64, struct FSTCachedHashedBlock*> m_cacheDecryptedHashedBlocks; std::unordered_map<uint64, struct FSTCachedHashedBlock*> m_cacheDecryptedHashedBlocks;
uint64 m_cacheAccessCounter{}; uint64 m_cacheAccessCounter{};
void DetermineUnhashedBlockIV(uint32 clusterIndex, uint32 blockIndex, uint8 ivOut[16]); void DetermineUnhashedBlockIV(uint32 clusterIndex, uint32 blockIndex, NCrypto::AesIv& ivOut);
struct FSTCachedRawBlock* GetDecryptedRawBlock(uint32 clusterIndex, uint32 blockIndex); struct FSTCachedRawBlock* GetDecryptedRawBlock(uint32 clusterIndex, uint32 blockIndex);
struct FSTCachedHashedBlock* GetDecryptedHashedBlock(uint32 clusterIndex, uint32 blockIndex); struct FSTCachedHashedBlock* GetDecryptedHashedBlock(uint32 clusterIndex, uint32 blockIndex);

View file

@ -13,10 +13,17 @@ namespace NCrypto
std::string base64Encode(const void* inputMem, size_t inputLen); std::string base64Encode(const void* inputMem, size_t inputLen);
std::vector<uint8> base64Decode(std::string_view inputStr); std::vector<uint8> base64Decode(std::string_view inputStr);
/* key helper struct */ /* key and iv helper struct */
struct AesKey struct AesKey
{ {
uint8 b[16]; static constexpr size_t SIZE = 16;
uint8 b[SIZE];
};
struct AesIv
{
static constexpr size_t SIZE = 16;
uint8 iv[SIZE];
}; };
/* ECC Certificate */ /* ECC Certificate */