forked from kOchirasu/Maple2.File
-
Notifications
You must be signed in to change notification settings - Fork 8
Remove DotNetZip & Upgrade dependencies #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,144 +1,183 @@ | ||
| using System.IO.MemoryMappedFiles; | ||
| using System.IO.Compression; | ||
| using System.IO.MemoryMappedFiles; | ||
| using System.Text; | ||
| using Ionic.Zlib; | ||
| using Maple2.File.IO.Crypto.Common; | ||
| using Maple2.File.IO.Crypto.Keys; | ||
| using Maple2.File.IO.Crypto.Stream; | ||
|
|
||
| namespace Maple2.File.IO.Crypto { | ||
| public static class CryptoManager { | ||
| public static byte[] DecryptFileString(IPackStream stream, System.IO.Stream buffer) { | ||
| if (stream.CompressedHeaderSize > 0 && stream.EncodedHeaderSize > 0 && | ||
| stream.HeaderSize > 0) { | ||
| byte[] src = new byte[stream.EncodedHeaderSize]; | ||
|
|
||
| if ((ulong) buffer.Read(src, 0, (int) stream.EncodedHeaderSize) == | ||
| stream.EncodedHeaderSize) { | ||
| return Decrypt(stream.Version, (uint) stream.EncodedHeaderSize, | ||
| (uint) stream.CompressedHeaderSize, Encryption.Aes | Encryption.Zlib, src); | ||
| } | ||
| } | ||
| namespace Maple2.File.IO.Crypto; | ||
|
|
||
| public static class CryptoManager { | ||
| public static byte[] DecryptFileString(IPackStream stream, System.IO.Stream buffer) { | ||
| if (stream.CompressedHeaderSize > 0 && stream.EncodedHeaderSize > 0 && stream.HeaderSize > 0) { | ||
| byte[] src = new byte[stream.EncodedHeaderSize]; | ||
|
|
||
| throw new Exception("ERROR decrypting file list: the size of the list is invalid."); | ||
| if ((ulong) buffer.Read(src, 0, (int) stream.EncodedHeaderSize) == stream.EncodedHeaderSize) { | ||
| return Decrypt(stream.Version, (uint) stream.EncodedHeaderSize, (uint) stream.CompressedHeaderSize, Encryption.Aes | Encryption.Zlib, src); | ||
| } | ||
| } | ||
|
|
||
| public static byte[] DecryptFileTable(IPackStream stream, System.IO.Stream buffer) { | ||
| if (stream.CompressedDataSize > 0 && stream.EncodedDataSize > 0 && stream.DataSize > 0) { | ||
| byte[] src = new byte[stream.EncodedDataSize]; | ||
| throw new Exception("ERROR decrypting file list: the size of the list is invalid."); | ||
| } | ||
|
|
||
| public static byte[] DecryptFileTable(IPackStream stream, System.IO.Stream buffer) { | ||
| if (stream.CompressedDataSize > 0 && stream.EncodedDataSize > 0 && stream.DataSize > 0) { | ||
| byte[] src = new byte[stream.EncodedDataSize]; | ||
|
|
||
| if ((ulong) buffer.Read(src, 0, (int) stream.EncodedDataSize) == stream.EncodedDataSize) { | ||
| return Decrypt(stream.Version, (uint) stream.EncodedDataSize, | ||
| (uint) stream.CompressedDataSize, Encryption.Aes | Encryption.Zlib, src); | ||
| } | ||
| if ((ulong) buffer.Read(src, 0, (int) stream.EncodedDataSize) == stream.EncodedDataSize) { | ||
| return Decrypt(stream.Version, (uint) stream.EncodedDataSize, (uint) stream.CompressedDataSize, Encryption.Aes | Encryption.Zlib, src); | ||
| } | ||
|
|
||
| throw new Exception("ERROR decrypting file table: the size of the table is invalid."); | ||
| } | ||
|
|
||
| public static byte[] DecryptData(IPackFileHeader pHeader, MemoryMappedFile data) { | ||
| if (pHeader.CompressedFileSize > 0 && pHeader.EncodedFileSize > 0 && pHeader.FileSize > 0) { | ||
| using MemoryMappedViewStream buffer = | ||
| data.CreateViewStream((long) pHeader.Offset, pHeader.EncodedFileSize); | ||
| byte[] src = new byte[pHeader.EncodedFileSize]; | ||
| throw new Exception("ERROR decrypting file table: the size of the table is invalid."); | ||
| } | ||
|
|
||
| public static byte[] DecryptData(IPackFileHeader pHeader, MemoryMappedFile data) { | ||
| if (pHeader.CompressedFileSize > 0 && pHeader.EncodedFileSize > 0 && pHeader.FileSize > 0) { | ||
| using MemoryMappedViewStream buffer = data.CreateViewStream((long) pHeader.Offset, pHeader.EncodedFileSize); | ||
| byte[] src = new byte[pHeader.EncodedFileSize]; | ||
|
|
||
| if (buffer.Read(src, 0, (int) pHeader.EncodedFileSize) == pHeader.EncodedFileSize) { | ||
| return Decrypt(pHeader.Version, pHeader.EncodedFileSize, | ||
| (uint) pHeader.CompressedFileSize, pHeader.BufferFlag, src); | ||
| } | ||
| if (buffer.Read(src, 0, (int) pHeader.EncodedFileSize) == pHeader.EncodedFileSize) { | ||
| return Decrypt(pHeader.Version, pHeader.EncodedFileSize, (uint) pHeader.CompressedFileSize, pHeader.BufferFlag, src); | ||
| } | ||
| } | ||
|
|
||
| throw new Exception("ERROR decrypting data file segment: the size of the block is invalid."); | ||
| } | ||
|
|
||
| throw new Exception("ERROR decrypting data file segment: the size of the block is invalid."); | ||
| // Decryption Routine: Base64 -> AES -> Zlib | ||
| private static byte[] Decrypt(PackVersion version, uint size, uint sizeCompressed, Encryption flag, byte[] src) { | ||
| if (flag.HasFlag(Encryption.Aes)) { | ||
| // Get the AES Key/IV for transformation | ||
| CipherKeys.GetKeyAndIV(version, sizeCompressed, out byte[] key, out byte[] iv); | ||
|
|
||
| // Decode the base64 encoded string | ||
| src = Convert.FromBase64String(Encoding.UTF8.GetString(src)); | ||
|
AngeloTadeucci marked this conversation as resolved.
|
||
|
|
||
| // Decrypt the AES encrypted block | ||
| var pCipher = new AESCipher(key, iv); | ||
| pCipher.TransformBlock(src, 0, size, src, 0); | ||
| } else if (flag.HasFlag(Encryption.Xor)) { | ||
| // Decrypt the XOR encrypted block | ||
| src = EncryptXor(version, src, size, sizeCompressed); | ||
| } | ||
|
|
||
| // Decryption Routine: Base64 -> AES -> Zlib | ||
| private static byte[] Decrypt(PackVersion version, uint size, uint sizeCompressed, Encryption flag, | ||
| byte[] src) { | ||
| if (flag.HasFlag(Encryption.Aes)) { | ||
| // Get the AES Key/IV for transformation | ||
| CipherKeys.GetKeyAndIV(version, sizeCompressed, out byte[] key, out byte[] iv); | ||
|
|
||
| // Decode the base64 encoded string | ||
| src = Convert.FromBase64String(Encoding.UTF8.GetString(src)); | ||
|
|
||
| // Decrypt the AES encrypted block | ||
| var pCipher = new AESCipher(key, iv); | ||
| pCipher.TransformBlock(src, 0, size, src, 0); | ||
| } else if (flag.HasFlag(Encryption.Xor)) { | ||
| // Decrypt the XOR encrypted block | ||
| src = EncryptXor(version, src, size, sizeCompressed); | ||
| } | ||
| return flag.HasFlag(Encryption.Zlib) ? UncompressBuffer(src) : src; | ||
| } | ||
|
|
||
| return flag.HasFlag(Encryption.Zlib) ? ZlibStream.UncompressBuffer(src) : src; | ||
| // Encryption Routine: Zlib -> AES -> Base64 | ||
| public static byte[] Encrypt(PackVersion version, byte[] src, Encryption flag, out uint size, out uint sizeCompressed, out uint sizeEncoded) { | ||
| byte[] pEncrypted; | ||
| if (flag.HasFlag(Encryption.Zlib)) { | ||
| pEncrypted = CompressBuffer(src); | ||
| } else { | ||
| pEncrypted = new byte[src.Length]; | ||
| Buffer.BlockCopy(src, 0, pEncrypted, 0, src.Length); | ||
| } | ||
|
|
||
| // Encryption Routine: Zlib -> AES -> Base64 | ||
| public static byte[] Encrypt(PackVersion version, byte[] src, Encryption flag, out uint size, | ||
| out uint sizeCompressed, out uint sizeEncoded) { | ||
| byte[] pEncrypted; | ||
| if (flag.HasFlag(Encryption.Zlib)) { | ||
| pEncrypted = ZlibStream.CompressBuffer(src); | ||
| } else { | ||
| pEncrypted = new byte[src.Length]; | ||
| Buffer.BlockCopy(src, 0, pEncrypted, 0, src.Length); | ||
| } | ||
| size = (uint) src.Length; | ||
| sizeCompressed = (uint) pEncrypted.Length; | ||
|
|
||
| size = (uint) src.Length; | ||
| sizeCompressed = (uint) pEncrypted.Length; | ||
| if (flag.HasFlag(Encryption.Aes)) { | ||
| // Get the AES Key/IV for transformation | ||
| CipherKeys.GetKeyAndIV(version, sizeCompressed, out byte[] key, out byte[] iv); | ||
|
|
||
| if (flag.HasFlag(Encryption.Aes)) { | ||
| // Get the AES Key/IV for transformation | ||
| CipherKeys.GetKeyAndIV(version, sizeCompressed, out byte[] key, out byte[] iv); | ||
| // Perform AES block encryption | ||
| var pCipher = new AESCipher(key, iv); | ||
| pCipher.TransformBlock(pEncrypted, 0, size, pEncrypted, 0); | ||
|
|
||
| // Perform AES block encryption | ||
| var pCipher = new AESCipher(key, iv); | ||
| pCipher.TransformBlock(pEncrypted, 0, size, pEncrypted, 0); | ||
| // Encode the encrypted data into a base64 encoded string | ||
| pEncrypted = Encoding.UTF8.GetBytes(Convert.ToBase64String(pEncrypted)); | ||
|
AngeloTadeucci marked this conversation as resolved.
|
||
| } else if (flag.HasFlag(Encryption.Xor)) { | ||
| // Perform XOR block encryption | ||
| pEncrypted = EncryptXor(version, pEncrypted, size, sizeCompressed); | ||
| } | ||
|
|
||
| // Encode the encrypted data into a base64 encoded string | ||
| pEncrypted = Encoding.UTF8.GetBytes(Convert.ToBase64String(pEncrypted)); | ||
| } else if (flag.HasFlag(Encryption.Xor)) { | ||
| // Perform XOR block encryption | ||
| pEncrypted = EncryptXor(version, pEncrypted, size, sizeCompressed); | ||
| } | ||
| sizeEncoded = (uint) pEncrypted.Length; | ||
|
|
||
| sizeEncoded = (uint) pEncrypted.Length; | ||
| return pEncrypted; | ||
| } | ||
|
|
||
| private static byte[] EncryptXor(PackVersion version, byte[] src, uint size, uint sizeCompressed) { | ||
| CipherKeys.GetXorKey(version, out byte[] key); | ||
|
|
||
| uint uBlock = size >> 2; | ||
| uint uBlockOffset = 0; | ||
| int nKeyOffset = 0; | ||
|
|
||
| if (uBlock != 0) { | ||
| while (uBlockOffset < uBlock) { | ||
| uint pBlockData = BitConverter.ToUInt32(src, (int) (4 * uBlockOffset)) ^ | ||
| BitConverter.ToUInt32(key, 4 * nKeyOffset); | ||
| Buffer.BlockCopy(BitConverter.GetBytes(pBlockData), 0, src, (int) (4 * uBlockOffset), | ||
| sizeof(uint)); | ||
|
|
||
| return pEncrypted; | ||
| nKeyOffset = ((ushort) nKeyOffset + 1) & 0x1FF; | ||
| uBlockOffset++; | ||
| } | ||
| } | ||
|
|
||
| private static byte[] EncryptXor(PackVersion version, byte[] src, uint size, uint sizeCompressed) { | ||
| CipherKeys.GetXorKey(version, out byte[] key); | ||
| uBlock = (size & 3); | ||
| if (uBlock != 0) { | ||
| int nStart = (int) (4 * uBlockOffset); | ||
|
|
||
| uint uBlock = size >> 2; | ||
| uint uBlockOffset = 0; | ||
| int nKeyOffset = 0; | ||
| uBlockOffset = 0; | ||
| nKeyOffset = 0; | ||
|
|
||
| if (uBlock != 0) { | ||
| while (uBlockOffset < uBlock) { | ||
| uint pBlockData = BitConverter.ToUInt32(src, (int) (4 * uBlockOffset)) ^ | ||
| BitConverter.ToUInt32(key, 4 * nKeyOffset); | ||
| Buffer.BlockCopy(BitConverter.GetBytes(pBlockData), 0, src, (int) (4 * uBlockOffset), | ||
| sizeof(uint)); | ||
| while (uBlockOffset < uBlock) { | ||
| src[nStart + uBlockOffset++] ^= (byte) (key[nKeyOffset]); | ||
|
|
||
| nKeyOffset = ((ushort) nKeyOffset + 1) & 0x1FF; | ||
| uBlockOffset++; | ||
| } | ||
| nKeyOffset = ((ushort) nKeyOffset + 1) & 0x7FF; | ||
| } | ||
| } | ||
|
|
||
| return src; | ||
| } | ||
|
|
||
| uBlock = (size & 3); | ||
| if (uBlock != 0) { | ||
| int nStart = (int) (4 * uBlockOffset); | ||
| private static byte[] UncompressBuffer(byte[] src) { | ||
| using var compressedStream = new MemoryStream(src, 2, src.Length - 6); | ||
| using var decompressStream = new DeflateStream(compressedStream, CompressionMode.Decompress); | ||
| using var resultStream = new MemoryStream(); | ||
|
|
||
| uBlockOffset = 0; | ||
| nKeyOffset = 0; | ||
| decompressStream.CopyTo(resultStream); | ||
| return resultStream.ToArray(); | ||
| } | ||
|
|
||
| while (uBlockOffset < uBlock) { | ||
| src[nStart + uBlockOffset++] ^= (byte) (key[nKeyOffset]); | ||
| private static byte[] CompressBuffer(byte[] src) { | ||
| using var outputStream = new MemoryStream(); | ||
|
|
||
| nKeyOffset = ((ushort) nKeyOffset + 1) & 0x7FF; | ||
| } | ||
| } | ||
| // Add Zlib header bytes | ||
| outputStream.WriteByte(0x78); // CMF byte (compression method and flags) | ||
| outputStream.WriteByte(0x9C); // Additional flags byte (default compression) | ||
|
|
||
| using (var compressionStream = new DeflateStream(outputStream, CompressionMode.Compress, true)) { | ||
| compressionStream.Write(src, 0, src.Length); | ||
| } | ||
|
|
||
| return src; | ||
| // Calculate and append Adler-32 checksum | ||
| uint adler32 = CalculateAdler32(src); | ||
| byte[] checksumBytes = [ | ||
| (byte) ((adler32 >> 24) & 0xFF), | ||
| (byte) ((adler32 >> 16) & 0xFF), | ||
| (byte) ((adler32 >> 8) & 0xFF), | ||
| (byte) (adler32 & 0xFF), | ||
| ]; | ||
|
AngeloTadeucci marked this conversation as resolved.
|
||
| outputStream.Write(checksumBytes, 0, 4); | ||
|
|
||
| return outputStream.ToArray(); | ||
| } | ||
|
|
||
| // Adler-32 checksum calculation (needed for Zlib format) | ||
| private static uint CalculateAdler32(byte[] data) { | ||
| // ReSharper disable once InconsistentNaming | ||
| const uint BASE = 65521; | ||
| uint a = 1, b = 0; | ||
|
|
||
| foreach (byte byteData in data) { | ||
| a = (a + byteData) % BASE; | ||
| b = (b + a) % BASE; | ||
| } | ||
|
|
||
| return (b << 16) | a; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.