From 33bdae86c2345db9514addbf9d5a698eada56fb2 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Mon, 17 May 2021 12:57:54 +0200 Subject: Added alignment-aware block encryption/decryption --- src/SBaseCommon.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 90 insertions(+), 21 deletions(-) (limited to 'src/SBaseCommon.cpp') diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index 43113a1..b81d492 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -414,52 +414,121 @@ DWORD GetDefaultSpecialFileFlags(DWORD dwFileSize, USHORT wFormatVersion) //----------------------------------------------------------------------------- // Encrypting/Decrypting MPQ data block +static DWORD EncryptUInt32Unaligned(PDWORD DataPointer, DWORD i, DWORD dwXorKey) +{ + LPBYTE pbDataPointer = (LPBYTE)(DataPointer + i); + LPBYTE pbXorKey = (LPBYTE)(&dwXorKey); + DWORD dwValue32; + + // Retrieve the value + dwValue32 = ((DWORD)pbDataPointer[0] << 0x00) | + ((DWORD)pbDataPointer[1] << 0x08) | + ((DWORD)pbDataPointer[2] << 0x10) | + ((DWORD)pbDataPointer[3] << 0x18); + + // Perform unaligned XOR + pbDataPointer[0] = (pbDataPointer[0] ^ pbXorKey[0]); + pbDataPointer[1] = (pbDataPointer[1] ^ pbXorKey[1]); + pbDataPointer[2] = (pbDataPointer[2] ^ pbXorKey[2]); + pbDataPointer[3] = (pbDataPointer[3] ^ pbXorKey[3]); + return dwValue32; +} + void EncryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey1) { - LPDWORD DataBlock = (LPDWORD)pvDataBlock; + LPDWORD DataPointer = (LPDWORD)pvDataBlock; DWORD dwValue32; DWORD dwKey2 = 0xEEEEEEEE; // Round to DWORDs dwLength >>= 2; - // Encrypt the data block at array of DWORDs - for(DWORD i = 0; i < dwLength; i++) + // We need different approach on non-aligned buffers + if(STORMLIB_DWORD_ALIGNED(DataPointer)) { - // Modify the second key - dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + for(DWORD i = 0; i < dwLength; i++) + { + // Modify the second key + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; - dwValue32 = DataBlock[i]; - DataBlock[i] = DataBlock[i] ^ (dwKey1 + dwKey2); + // We can use 32-bit approach, when the buffer is aligned + DataPointer[i] = (dwValue32 = DataPointer[i]) ^ (dwKey1 + dwKey2); - dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); - dwKey2 = dwValue32 + dwKey2 + (dwKey2 << 5) + 3; + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = dwValue32 + dwKey2 + (dwKey2 << 5) + 3; + } + } + else + { + for(DWORD i = 0; i < dwLength; i++) + { + // Modify the second key + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + + // The data are unaligned. Make sure we don't cause data misalignment error + dwValue32 = EncryptUInt32Unaligned(DataPointer, i, (dwKey1 + dwKey2)); + + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = dwValue32 + dwKey2 + (dwKey2 << 5) + 3; + } } } +static DWORD DecryptUInt32Unaligned(PDWORD DataPointer, DWORD i, DWORD dwXorKey) +{ + LPBYTE pbDataPointer = (LPBYTE)(DataPointer + i); + LPBYTE pbXorKey = (LPBYTE)(&dwXorKey); + + // Perform unaligned XOR + pbDataPointer[0] = (pbDataPointer[0] ^ pbXorKey[0]); + pbDataPointer[1] = (pbDataPointer[1] ^ pbXorKey[1]); + pbDataPointer[2] = (pbDataPointer[2] ^ pbXorKey[2]); + pbDataPointer[3] = (pbDataPointer[3] ^ pbXorKey[3]); + + // Retrieve the value + return ((DWORD)pbDataPointer[0] << 0x00) | + ((DWORD)pbDataPointer[1] << 0x08) | + ((DWORD)pbDataPointer[2] << 0x10) | + ((DWORD)pbDataPointer[3] << 0x18); +} + void DecryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey1) { - LPDWORD DataBlock = (LPDWORD)pvDataBlock; + PDWORD DataPointer = (PDWORD)pvDataBlock; DWORD dwValue32; DWORD dwKey2 = 0xEEEEEEEE; - // Check for alignment - //assert(((size_t)(pvDataBlock) & 0x03) == 0); - // Round to DWORDs dwLength >>= 2; - // Decrypt the data block at array of DWORDs - for(DWORD i = 0; i < dwLength; i++) + // We need different approach on non-aligned buffers + if(STORMLIB_DWORD_ALIGNED(DataPointer)) { - // Modify the second key - dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + for(DWORD i = 0; i < dwLength; i++) + { + // Modify the second key + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + + // We can use 32-bit approach, when the buffer is aligned + DataPointer[i] = dwValue32 = DataPointer[i] ^ (dwKey1 + dwKey2); + + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = dwValue32 + dwKey2 + (dwKey2 << 5) + 3; + } + } + else + { + for(DWORD i = 0; i < dwLength; i++) + { + // Modify the second key + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; - DataBlock[i] = DataBlock[i] ^ (dwKey1 + dwKey2); - dwValue32 = DataBlock[i]; + // The data are unaligned. Make sure we don't cause data misalignment error + dwValue32 = DecryptUInt32Unaligned(DataPointer, i, (dwKey1 + dwKey2)); - dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); - dwKey2 = dwValue32 + dwKey2 + (dwKey2 << 5) + 3; + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = dwValue32 + dwKey2 + (dwKey2 << 5) + 3; + } } } -- cgit v1.2.3 From 26b2f0e8b6e711aa05b67bf2466a715a063b2517 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Mon, 17 May 2021 15:19:36 +0200 Subject: PDWORD -> LPDWORD --- src/SBaseCommon.cpp | 6 +++--- test/StormTest.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/SBaseCommon.cpp') diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index b81d492..a1aa78e 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -414,7 +414,7 @@ DWORD GetDefaultSpecialFileFlags(DWORD dwFileSize, USHORT wFormatVersion) //----------------------------------------------------------------------------- // Encrypting/Decrypting MPQ data block -static DWORD EncryptUInt32Unaligned(PDWORD DataPointer, DWORD i, DWORD dwXorKey) +static DWORD EncryptUInt32Unaligned(LPDWORD DataPointer, DWORD i, DWORD dwXorKey) { LPBYTE pbDataPointer = (LPBYTE)(DataPointer + i); LPBYTE pbXorKey = (LPBYTE)(&dwXorKey); @@ -474,7 +474,7 @@ void EncryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey1) } } -static DWORD DecryptUInt32Unaligned(PDWORD DataPointer, DWORD i, DWORD dwXorKey) +static DWORD DecryptUInt32Unaligned(LPDWORD DataPointer, DWORD i, DWORD dwXorKey) { LPBYTE pbDataPointer = (LPBYTE)(DataPointer + i); LPBYTE pbXorKey = (LPBYTE)(&dwXorKey); @@ -494,7 +494,7 @@ static DWORD DecryptUInt32Unaligned(PDWORD DataPointer, DWORD i, DWORD dwXorKey) void DecryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey1) { - PDWORD DataPointer = (PDWORD)pvDataBlock; + LPDWORD DataPointer = (LPDWORD)pvDataBlock; DWORD dwValue32; DWORD dwKey2 = 0xEEEEEEEE; diff --git a/test/StormTest.cpp b/test/StormTest.cpp index ab003e4..5b32dc1 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -4285,13 +4285,13 @@ int _tmain(int argc, TCHAR * argv[]) // // Tests on a local listfile // - + /* if(dwErrCode == ERROR_SUCCESS) { TestOnLocalListFile(_T("FLAT-MAP:ListFile_Blizzard.txt")); dwErrCode = TestOnLocalListFile(_T("ListFile_Blizzard.txt")); } - + */ // // Open all files from the command line // -- cgit v1.2.3