diff options
author | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-08-20 02:25:28 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-20 02:25:28 +0300 |
commit | 37c69932a090010e49fe511cb0510e35c42532cd (patch) | |
tree | a6862e6c3cb67b6d762f4ad6c5243d8c3e1750cc | |
parent | f5fa8f9d8f9017e73ecad6e09abbbc481b81ae7b (diff) | |
parent | 1d9e8ec29c175786afb9fc9e384f072827fb0187 (diff) |
Merge pull request #269 from tslater2006/master
Add Encrypt/Decrypt CTB command line
-rw-r--r-- | UVtools.Core/FileFormats/CTBEncryptedFile.cs | 148 | ||||
-rw-r--r-- | UVtools.WPF/ConsoleArguments.cs | 8 |
2 files changed, 156 insertions, 0 deletions
diff --git a/UVtools.Core/FileFormats/CTBEncryptedFile.cs b/UVtools.Core/FileFormats/CTBEncryptedFile.cs index 9c2b757..34cd550 100644 --- a/UVtools.Core/FileFormats/CTBEncryptedFile.cs +++ b/UVtools.Core/FileFormats/CTBEncryptedFile.cs @@ -166,6 +166,154 @@ namespace UVtools.Core.FileFormats } } + public static void CryptFile(string filePath, bool encrypt) + { + using (MemoryStream decryptedStream = new MemoryStream(File.ReadAllBytes(filePath))) + { + BinaryWriter writer = new BinaryWriter(decryptedStream); + using MemoryStream ms = new MemoryStream(File.ReadAllBytes(filePath)); + BinaryReader reader = new BinaryReader(ms); + + /* magic */ + var magic = reader.ReadUInt32(); + if (magic != MAGIC_CBT_ENCRYPTED) + { + Console.Write("File does not appear to be an encrypted CTB. Aborting."); + return; + } + writer.Write(magic); + var headerLength = reader.ReadUInt32(); + writer.Write(headerLength); + var headerOffset = reader.ReadUInt32(); + writer.Write(headerOffset); + + /* pass through rest of data until encrypted header */ + var bytesToPassthru = headerOffset - ms.Position; + var temp = reader.ReadBytes((int)bytesToPassthru); + writer.Write(temp); + uint printerNameLength = 0; + + var originalHeader = reader.ReadBytes((int)headerLength); + + if (encrypt) + { + printerNameLength = BitExtensions.ToUIntLittleEndian(originalHeader, 164); + } + + /* decrypt header with recovered keys */ + var cryptedData = CryptExtensions.AesCryptBytes(originalHeader, Kong, CipherMode.CBC, PaddingMode.None, encrypt, CookieMonster); + writer.Write(cryptedData); + + /* get machine name length */ + if (!encrypt) + { + printerNameLength = BitExtensions.ToUIntLittleEndian(cryptedData, 164); + } + + /* pass through the next 2 dwords */ + writer.Write(reader.ReadUInt32()); + writer.Write(reader.ReadUInt32()); + + /* get offset and length of next section (not encrypted) */ + var nextOffset = reader.ReadUInt32(); + var nextLength = reader.ReadUInt32(); + + writer.Write(nextOffset); + writer.Write(nextLength); + + /* how many bytes from current position till the next offset */ + bytesToPassthru = nextOffset - ms.Position; + writer.Write(reader.ReadBytes((int)bytesToPassthru)); + + /* passthrough this whole block */ + writer.Write(reader.ReadBytes((int)nextLength)); + + /* pass throught the next 2 dwords */ + writer.Write(reader.ReadUInt32()); + writer.Write(reader.ReadUInt32()); + + /* get offset and length of next section (not encrypted) */ + nextOffset = reader.ReadUInt32(); + nextLength = reader.ReadUInt32(); + + writer.Write(nextOffset); + writer.Write(nextLength); + + /* how many bytes from current position till the next offset */ + bytesToPassthru = nextOffset - ms.Position; + writer.Write(reader.ReadBytes((int)bytesToPassthru)); + + /* passthrough this whole block */ + writer.Write(reader.ReadBytes((int)nextLength)); + + /* passes printer name and disclaimer */ + var x = reader.ReadBytes((int)(CTB_DISCLAIMER_SIZE + printerNameLength)); + writer.Write(x); + + /* we're at the layer offset table now */ + List<ulong> layerOffsets = new List<ulong>(); + var startOfTable = ms.Position; + ulong layerOffset = reader.ReadUInt64(); + ulong firstLayer = layerOffset; + while (ms.Position < (int)firstLayer) + { + layerOffsets.Add(layerOffset); + reader.ReadUInt64(); + layerOffset = reader.ReadUInt64(); + } + + ms.Position = (int)startOfTable; + + /* copy the rest of the file to the output memory stream, we'll decrypt layers next */ + writer.Write(reader.ReadBytes((int)(ms.Length - ms.Position))); + + byte[] cryptedFile = decryptedStream.ToArray(); + var layerCounter = 0; + foreach (var offset in layerOffsets) + { + layerCounter++; + ms.Position = (int)(offset + 0x10); + + ms.Position += 0x10; + var encryptedOffset = reader.ReadUInt32(); + var encryptedLength = reader.ReadUInt32(); + ms.Position -= 0x18; + + if (encryptedLength > 0) + { + Debug.WriteLine($"Layer {layerCounter} has {encryptedLength} bytes of encrypted data. (Layer data offset: {encryptedOffset})"); + var layerDataOffset = reader.ReadUInt32(); + + ms.Position = layerDataOffset + encryptedOffset; + + byte[] encryptedLayerData = reader.ReadBytes((int)encryptedLength); + + byte[] decryptedLayerData = CryptExtensions.AesCryptBytes(encryptedLayerData, Kong, CipherMode.CBC, PaddingMode.None, encrypt, CookieMonster); + + Array.Copy(decryptedLayerData, 0, cryptedFile, layerDataOffset + encryptedOffset, encryptedLength); + + + /* update encrypted markers in the layer header */ + byte[] empty = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; + Array.Copy(empty, 0, cryptedFile, layerDataOffset - 0x38, 8); + + } + else + { + Debug.WriteLine($"Layer {layerCounter} is not encrypted"); + } + } + + /* last 20 bytes are an encrypted sha256 */ + byte[] cipheredHash = cryptedFile[^0x20..]; + + byte[] plainHash = CryptExtensions.AesCryptBytes(cipheredHash, Kong, CipherMode.CBC, PaddingMode.None, encrypt, CookieMonster); + Array.Copy(plainHash, 0, cryptedFile, cryptedFile.Length - 0x20, 0x20); + + File.WriteAllBytes(filePath, cryptedFile); + } + } + public class LayerPointer { [FieldOrder(0)] public uint LayerOffset { get; set; } diff --git a/UVtools.WPF/ConsoleArguments.cs b/UVtools.WPF/ConsoleArguments.cs index cb8f691..50d9407 100644 --- a/UVtools.WPF/ConsoleArguments.cs +++ b/UVtools.WPF/ConsoleArguments.cs @@ -141,6 +141,14 @@ namespace UVtools.WPF return true; } + if (args[0] is "--encrypt-ctb" or "--decrypt-ctb") + { + bool isEncrypt = (args[0] is "--encrypt-ctb"); + + + CTBEncryptedFile.CryptFile(args[1], isEncrypt); + return true; + } return false; } |