diff --git a/Cethleann.DataExporter/Cethleann.DataExporter.csproj b/Cethleann.DataExporter/Cethleann.DataExporter.csproj index 1329533..23cdeb5 100644 --- a/Cethleann.DataExporter/Cethleann.DataExporter.csproj +++ b/Cethleann.DataExporter/Cethleann.DataExporter.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Cethleann.DataProcessor/Cethleann.DataProcessor.csproj b/Cethleann.DataProcessor/Cethleann.DataProcessor.csproj index 180c5a3..925da35 100644 --- a/Cethleann.DataProcessor/Cethleann.DataProcessor.csproj +++ b/Cethleann.DataProcessor/Cethleann.DataProcessor.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Cethleann.Downloader/Cethleann.Downloader.csproj b/Cethleann.Downloader/Cethleann.Downloader.csproj index 180c5a3..925da35 100644 --- a/Cethleann.Downloader/Cethleann.Downloader.csproj +++ b/Cethleann.Downloader/Cethleann.Downloader.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Cethleann.Downloader/Program.cs b/Cethleann.Downloader/Program.cs index d7a6340..f448750 100644 --- a/Cethleann.Downloader/Program.cs +++ b/Cethleann.Downloader/Program.cs @@ -9,6 +9,7 @@ using DragonLib; using DragonLib.CLI; using DragonLib.IO; +using System.Net.Http; namespace Cethleann.Downloader { @@ -51,10 +52,17 @@ private static void Main(string[] args) var (url, dest, size) = pair; Logger.Info("Cethleann", url); if (flags.Dry) return; - using var http = new WebClient(); + using var http = new HttpClient(); try { - http.DownloadFile(url, dest); + var folder = Path.GetDirectoryName(dest); + if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + + using var stream = http.GetStreamAsync(url); + using var destStream = File.OpenWrite(dest); Logger.Info("Cethleann", $"Downloaded {size} to {dest}"); } catch (Exception e) diff --git a/Cethleann.Gz/Cethleann.Gz.csproj b/Cethleann.Gz/Cethleann.Gz.csproj index 180c5a3..925da35 100644 --- a/Cethleann.Gz/Cethleann.Gz.csproj +++ b/Cethleann.Gz/Cethleann.Gz.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Cethleann.Identify/Cethleann.Identify.csproj b/Cethleann.Identify/Cethleann.Identify.csproj index 180c5a3..925da35 100644 --- a/Cethleann.Identify/Cethleann.Identify.csproj +++ b/Cethleann.Identify/Cethleann.Identify.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Cethleann.Prototype/Cethleann.Prototype.csproj b/Cethleann.Prototype/Cethleann.Prototype.csproj index 57f7d5a..4bead7b 100644 --- a/Cethleann.Prototype/Cethleann.Prototype.csproj +++ b/Cethleann.Prototype/Cethleann.Prototype.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Debug x64 enable diff --git a/Cethleann.Structure/Cethleann.Structure.csproj b/Cethleann.Structure/Cethleann.Structure.csproj index 3608250..0d4f0d7 100644 --- a/Cethleann.Structure/Cethleann.Structure.csproj +++ b/Cethleann.Structure/Cethleann.Structure.csproj @@ -1,7 +1,7 @@ - net5.0 + net7.0 x64 win10-x64;osx-x64;linux-x64 1.0.0 diff --git a/Cethleann.Structure/KTID/RDBFlags.cs b/Cethleann.Structure/KTID/RDBFlags.cs index 1a08567..1693766 100644 --- a/Cethleann.Structure/KTID/RDBFlags.cs +++ b/Cethleann.Structure/KTID/RDBFlags.cs @@ -9,6 +9,6 @@ public enum RDBFlags Internal = 0x00020000, ZlibCompressed = 0x00100000, Lz4Compressed = 0x00200000, - Encrypted = 0x00200000, // reused in p5s pc + Encrypted = 0x00200000, // reused in Scramble } } diff --git a/Cethleann.Unbundler/Cethleann.Unbundler.csproj b/Cethleann.Unbundler/Cethleann.Unbundler.csproj index 81f6f14..ac0d2fa 100644 --- a/Cethleann.Unbundler/Cethleann.Unbundler.csproj +++ b/Cethleann.Unbundler/Cethleann.Unbundler.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Cethleann.XORTool/Cethleann.XORTool.csproj b/Cethleann.XORTool/Cethleann.XORTool.csproj index 180c5a3..925da35 100644 --- a/Cethleann.XORTool/Cethleann.XORTool.csproj +++ b/Cethleann.XORTool/Cethleann.XORTool.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Cethleann/Archive/RDB.cs b/Cethleann/Archive/RDB.cs index 8e62ddb..86d5c8c 100644 --- a/Cethleann/Archive/RDB.cs +++ b/Cethleann/Archive/RDB.cs @@ -1,5 +1,4 @@ using Cethleann.Compression; -using Cethleann.Compression.P5SPC; using Cethleann.KTID; using Cethleann.Structure; using Cethleann.Structure.KTID; @@ -13,6 +12,8 @@ using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; +using ScrambleRDBEncryption = Cethleann.Compression.Scramble.RDBEncryption; +using ScrambleSRSTEncryption = Cethleann.Compression.Scramble.SRSTEncryption; namespace Cethleann.Archive { @@ -36,9 +37,11 @@ public class RDB : IDisposable /// /// /// - public RDB(Span buffer, string name, string directory) + /// + public RDB(Span buffer, string name, string directory, string game) { Name = name; + Game = game; if(File.Exists(Path.Combine(directory, name + ".rdx"))) External = new RDX(File.ReadAllBytes(Path.Combine(directory, name + ".rdx")), directory); @@ -82,10 +85,15 @@ public RDB(Span buffer, string name, string directory) public string DataDirectory { get; set; } /// - /// Name of this archive + /// Name of this archive /// public string Name { get; set; } + /// + /// Name of this game + /// + public string Game { get; set; } + /// /// RDB Header /// @@ -256,15 +264,18 @@ public Memory ReadEntry(int index) var fileEntryA = fileEntry.GetValueOrDefault(); if (fileEntryA.Size == 0) return Memory.Empty; - if (entry.Flags.HasFlag(RDBFlags.External) && MemoryMarshal.Read(buffer) == 0x53525354) - { - SRSTEncryption.Decrypt(buffer); - } - else if (entry.Flags.HasFlag(RDBFlags.Encrypted)) + if (Game == "Scramble") { - RDBEncryption.Decrypt(buffer, entry.FileKTID.KTID); - - entry.Flags ^= RDBFlags.Encrypted; + // todo: check KTID Type. + if (MemoryMarshal.Read(buffer) == 0x53525354) + { + ScrambleSRSTEncryption.Decrypt(buffer); + } + else if (entry.Flags.HasFlag(RDBFlags.ZlibCompressed) && entry.Flags.HasFlag(RDBFlags.Encrypted)) + { + ScrambleRDBEncryption.Decrypt(buffer, entry.FileKTID.KTID); + entry.Flags ^= RDBFlags.Encrypted; + } } if (entry.Flags.HasFlag(RDBFlags.ZlibCompressed) || entry.Flags.HasFlag(RDBFlags.Lz4Compressed)) diff --git a/Cethleann/Cethleann.csproj b/Cethleann/Cethleann.csproj index 2cae6a9..0b6cb7b 100644 --- a/Cethleann/Cethleann.csproj +++ b/Cethleann/Cethleann.csproj @@ -1,7 +1,7 @@  - net5.0 + net7.0 x64 win10-x64;osx-x64;linux-x64 true @@ -28,7 +28,7 @@ - + PreserveNewest diff --git a/Cethleann/Compression/P5SPC/LINKDATAEncryption.cs b/Cethleann/Compression/Scramble/LINKDATAEncryption.cs similarity index 72% rename from Cethleann/Compression/P5SPC/LINKDATAEncryption.cs rename to Cethleann/Compression/Scramble/LINKDATAEncryption.cs index 118a07e..1689bdf 100644 --- a/Cethleann/Compression/P5SPC/LINKDATAEncryption.cs +++ b/Cethleann/Compression/Scramble/LINKDATAEncryption.cs @@ -1,14 +1,14 @@ using System; -namespace Cethleann.Compression.P5SPC +namespace Cethleann.Compression.Scramble { /// - /// Implements P5S PC LINKDATA file encryption/decryption. + /// Implements Scramble LINKDATA file encryption/decryption. /// - public static class LINKDATAEncryption + public static class LinkEncryption { /// - /// Encrypts a P5S PC LINKDATA file. + /// Encrypts a Scramble LINKDATA file. /// /// The data to encrypt. /// The ID of the LINKDATA file. @@ -16,7 +16,7 @@ public static void Encrypt(Span data, uint id) => Decrypt(data, id); /// - /// Decrypts a P5S PC LINKDATA file. + /// Decrypts a Scramble LINKDATA file. /// /// The data to decrypt. /// The ID of the LINKDATA file. @@ -42,7 +42,7 @@ public static void Decrypt(Span data, uint id) /// public class Mersenne { - readonly uint[] _state = new uint[4]; + readonly uint[] State = new uint[4]; /// /// Initializes a generator object using the provided seed value. @@ -59,10 +59,10 @@ public Mersenne(uint seed) /// Value to initialize with. public void Init(uint seed) { - _state[0] = 0x6C078965 * (seed ^ (seed >> 30)); + State[0] = 0x6C078965 * (seed ^ (seed >> 30)); for (int i = 1; i < 4; i++) - _state[i] = (uint) (0x6C078965 * (_state[i - 1] ^ (_state[i - 1] >> 30)) + i); + State[i] = (uint) (0x6C078965 * (State[i - 1] ^ (State[i - 1] >> 30)) + i); } /// @@ -71,13 +71,13 @@ public void Init(uint seed) /// Next generator state. public uint Next() { - var temp = _state[0] ^ (_state[0] << 11); - _state[0] = _state[1]; - _state[1] = _state[2]; - _state[2] = _state[3]; - _state[3] ^= temp ^ ((temp ^ (_state[3] >> 11)) >> 8); + var temp = State[0] ^ (State[0] << 11); + State[0] = State[1]; + State[1] = State[2]; + State[2] = State[3]; + State[3] ^= temp ^ ((temp ^ (State[3] >> 11)) >> 8); - return _state[3]; + return State[3]; } } } diff --git a/Cethleann/Compression/P5SPC/RDBEncryption.cs b/Cethleann/Compression/Scramble/RDBEncryption.cs similarity index 96% rename from Cethleann/Compression/P5SPC/RDBEncryption.cs rename to Cethleann/Compression/Scramble/RDBEncryption.cs index 4bb0365..aebba3f 100644 --- a/Cethleann/Compression/P5SPC/RDBEncryption.cs +++ b/Cethleann/Compression/Scramble/RDBEncryption.cs @@ -1,16 +1,16 @@ using System; using System.Runtime.InteropServices; -namespace Cethleann.Compression.P5SPC +namespace Cethleann.Compression.Scramble { /// - /// Implements P5S PC RDB encryption/decryption. + /// Implements Scramble RDB encryption/decryption. /// Only used on ZLib compressed data. /// public static class RDBEncryption { /// - /// Encrypts a P5S PC RDB ZLib compressed file. + /// Encrypts a Scramble RDB ZLib compressed file. /// /// The compressed data to encrypt. /// The KTID of the RDB file. @@ -18,7 +18,7 @@ public static void Encrypt(Span data, uint ktid) => Decrypt(data, ktid); /// - /// Decrypts a P5S PC RDB ZLib compressed file. + /// Decrypts a Scramble RDB ZLib compressed file. /// /// The compressed data to decrypt. /// The KTID of the RDB file. diff --git a/Cethleann/Compression/P5SPC/SRSTEncryption.cs b/Cethleann/Compression/Scramble/SRSTEncryption.cs similarity index 97% rename from Cethleann/Compression/P5SPC/SRSTEncryption.cs rename to Cethleann/Compression/Scramble/SRSTEncryption.cs index ad4dc29..0765b97 100644 --- a/Cethleann/Compression/P5SPC/SRSTEncryption.cs +++ b/Cethleann/Compression/Scramble/SRSTEncryption.cs @@ -2,15 +2,15 @@ using System.Buffers.Binary; using System.Runtime.InteropServices; -namespace Cethleann.Compression.P5SPC +namespace Cethleann.Compression.Scramble { /// - /// Implements P5S PC SRST file encryption/decryption. + /// Implements Scramble SRST file encryption/decryption. /// public static class SRSTEncryption { /// - /// Encrypts a P5S PC SRST file. + /// Encrypts a Scramble SRST file. /// The key length should be at offset 0x30 (relative to SRST header). /// The key itself should follow from offset 0x31 and on. /// If the key isn't present, no encryption is performed. @@ -21,7 +21,7 @@ public static bool Encrypt(Span data) => Crypt(data, false); /// - /// Decrypts a P5S PC SRST file. + /// Decrypts a Scramble SRST file. /// The key length should be at offset 0x30 (relative to SRST header). /// The key itself should follow from offset 0x31 and on. /// If the key isn't present, no decryption is performed. @@ -32,7 +32,7 @@ public static bool Decrypt(Span data) => Crypt(data, true); /// - /// (En/De)crypts a P5S PC SRST file. + /// (En/De)crypts a Scramble SRST file. /// /// The SRST file to decrypt. /// True to decrypt, otherwise encrypt. @@ -69,6 +69,10 @@ private static bool Crypt(Span data, bool decrypt) } } + //Blowfish encryption (ECB, CBC and CTR mode) as defined by Bruce Schneier here: http://www.schneier.com/paper-blowfish-fse.html + //Complies with test vectors found here: http://www.schneier.com/code/vectors.txt + //non-standard mode provided to be usable with the javascript crypto library found here: http://etherhack.co.uk/symmetric/blowfish/blowfish.html + //By Taylor Hornby, 1/7/1010 /// /// Implements a basic Blowfish cipher. /// Only ECB mode is supported. diff --git a/Cethleann/ManagedFS/Flayn.cs b/Cethleann/ManagedFS/Flayn.cs index c1a3185..aab833e 100644 --- a/Cethleann/ManagedFS/Flayn.cs +++ b/Cethleann/ManagedFS/Flayn.cs @@ -1,5 +1,4 @@ using Cethleann.Archive; -using Cethleann.Compression.P5SPC; using Cethleann.ManagedFS.Options; using Cethleann.ManagedFS.Options.Default; using Cethleann.Structure; @@ -9,6 +8,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using ScrambleLinkEncryption = Cethleann.Compression.Scramble.LinkEncryption; namespace Cethleann.ManagedFS { @@ -122,10 +122,10 @@ public Memory ReadEntry(int index) var buffer = data.ReadEntry(stream, localId); if (GameId == "ThreeHouses" && i > 0 && buffer.Length == 0) continue; - // for p5s pc, all non-compressed entries are encrypted + // for Scramble, all non-compressed entries are encrypted // conversly, if an entry is compressed, it can't also be encrypted - if (GameId == "P5SPC" && localId < data.Entries.Count && !data.Entries[localId].IsCompressed) - LINKDATAEncryption.Decrypt(buffer.Span, (uint) localId); + if (GameId == "Scramble" && localId < data.Entries.Count && !data.Entries[localId].IsCompressed) + ScrambleLinkEncryption.Decrypt(buffer.Span, (uint) localId); return buffer; } @@ -190,7 +190,7 @@ public string GetFilename(int index, string? ext = "bin", DataType dataType = Da id = GameId switch { "ThreeHouses" => $"{(i == 0 ? string.Empty : "DLC_")}{localId}", - "P5SPC" => $"{localId}", + "Scramble" => $"{localId}", _ => $"{linkname}_{localId}" }; prefix = GameId switch @@ -209,7 +209,7 @@ public string GetFilename(int index, string? ext = "bin", DataType dataType = Da { ext = GameId switch { - "P5SPC" => Path.GetExtension(path) ?? ext, + "Scramble" => Path.GetExtension(path) ?? ext, _ => $".{ext}" }; path = Path.Combine(Path.GetDirectoryName(path) ?? string.Empty, Path.GetFileNameWithoutExtension(path) + $"{ext}"); diff --git a/Cethleann/ManagedFS/Nyotengu.cs b/Cethleann/ManagedFS/Nyotengu.cs index 5375c42..78b20d2 100644 --- a/Cethleann/ManagedFS/Nyotengu.cs +++ b/Cethleann/ManagedFS/Nyotengu.cs @@ -82,7 +82,7 @@ public Memory ReadEntry(int index) public void AddDataFS(string path) { Logger.Success("Nyotengu", $"Loading {Path.GetFileName(path)}..."); - var rdb = new RDB(File.ReadAllBytes(path), Path.GetFileNameWithoutExtension(path), Path.GetDirectoryName(path) ?? string.Empty); + var rdb = new RDB(File.ReadAllBytes(path), Path.GetFileNameWithoutExtension(path), Path.GetDirectoryName(path) ?? string.Empty, GameId); foreach (var file in Directory.GetFiles(Path.GetDirectoryName(path) ?? "./", rdb.Name + "*.info")) rdb.NameDatabase.Union(new RDBINFO(File.ReadAllBytes(file))); EntryCount += rdb.Entries.Count; diff --git a/Cethleann/filelist-P5SPC-link.csv b/Cethleann/filelist-Scramble-link.csv similarity index 100% rename from Cethleann/filelist-P5SPC-link.csv rename to Cethleann/filelist-Scramble-link.csv diff --git a/Gust.EncFinder/Gust.EncFinder.csproj b/Gust.EncFinder/Gust.EncFinder.csproj index cec121c..0494efe 100644 --- a/Gust.EncFinder/Gust.EncFinder.csproj +++ b/Gust.EncFinder/Gust.EncFinder.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Nyotengu.AnimationGraph/Nyotengu.AnimationGraph.csproj b/Nyotengu.AnimationGraph/Nyotengu.AnimationGraph.csproj index 180c5a3..925da35 100644 --- a/Nyotengu.AnimationGraph/Nyotengu.AnimationGraph.csproj +++ b/Nyotengu.AnimationGraph/Nyotengu.AnimationGraph.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Nyotengu.Database/Nyotengu.Database.csproj b/Nyotengu.Database/Nyotengu.Database.csproj index 180c5a3..925da35 100644 --- a/Nyotengu.Database/Nyotengu.Database.csproj +++ b/Nyotengu.Database/Nyotengu.Database.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Nyotengu.Filelist/Nyotengu.Filelist.csproj b/Nyotengu.Filelist/Nyotengu.Filelist.csproj index 180c5a3..925da35 100644 --- a/Nyotengu.Filelist/Nyotengu.Filelist.csproj +++ b/Nyotengu.Filelist/Nyotengu.Filelist.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Nyotengu.Hasher/Nyotengu.Hasher.csproj b/Nyotengu.Hasher/Nyotengu.Hasher.csproj index 090d3e9..9b6359f 100644 --- a/Nyotengu.Hasher/Nyotengu.Hasher.csproj +++ b/Nyotengu.Hasher/Nyotengu.Hasher.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Nyotengu.KTID/Nyotengu.KTID.csproj b/Nyotengu.KTID/Nyotengu.KTID.csproj index 180c5a3..925da35 100644 --- a/Nyotengu.KTID/Nyotengu.KTID.csproj +++ b/Nyotengu.KTID/Nyotengu.KTID.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64 diff --git a/Yshtola.Downloader/Program.cs b/Yshtola.Downloader/Program.cs index 7fef4ff..45fdafa 100644 --- a/Yshtola.Downloader/Program.cs +++ b/Yshtola.Downloader/Program.cs @@ -7,6 +7,7 @@ using DragonLib; using DragonLib.CLI; using DragonLib.IO; +using System.Net.Http; namespace Yshtola.Downloader { @@ -65,10 +66,17 @@ private static void Main(string[] args) var (url, dest, size) = pair; Logger.Info("Yshtola", url); if (flags.Dry) return; - using var http = new WebClient(); + using var http = new HttpClient(); try { - http.DownloadFile(url, dest); + var folder = Path.GetDirectoryName(dest); + if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + + using var stream = http.GetStreamAsync(url); + using var destStream = File.OpenWrite(dest); Logger.Info("Yshtola", $"Downloaded {size} to {dest}"); } catch (Exception e) diff --git a/Yshtola.Downloader/Yshtola.Downloader.csproj b/Yshtola.Downloader/Yshtola.Downloader.csproj index 6995f6e..925da35 100644 --- a/Yshtola.Downloader/Yshtola.Downloader.csproj +++ b/Yshtola.Downloader/Yshtola.Downloader.csproj @@ -2,7 +2,7 @@ Exe - net5 + net7.0 Release;Debug x64 win10-x64;osx-x64;linux-x64