diff --git a/GZ.cs b/GZ.cs index acf7c15..df3ab85 100644 --- a/GZ.cs +++ b/GZ.cs @@ -1,16 +1,21 @@ -using System; -using System.Collections.Generic; +using ICSharpCode.SharpZipLib.Tar; using System.Diagnostics; using System.IO.Compression; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using static TaikoSoundEditor.TJA; namespace TaikoSoundEditor { internal class GZ { + + public static string DecompressBytes(byte[] bytes) + { + Logger.Info("GZ Decompressing bytes"); + using MemoryStream ms = new MemoryStream(bytes); + using GZipStream decompressionStream = new GZipStream(ms, CompressionMode.Decompress); + using StreamReader reader = new StreamReader(decompressionStream); + return reader.ReadToEnd(); + } + public static string DecompressString(string gzPath) { Logger.Info("GZ Decompressing string"); @@ -61,6 +66,7 @@ namespace TaikoSoundEditor File.WriteAllText(fn, content); fileName = Path.GetFullPath(fileName); + var p = new Process(); p.StartInfo.FileName = Path.GetFullPath(@"Tools\7z\7za.exe"); diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs index db4a300..e6da8a6 100644 --- a/MainForm.Designer.cs +++ b/MainForm.Designer.cs @@ -31,6 +31,11 @@ this.TabControl = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); this.panel1 = new System.Windows.Forms.Panel(); + this.groupBox12 = new System.Windows.Forms.GroupBox(); + this.FumenKeyBox = new System.Windows.Forms.TextBox(); + this.label21 = new System.Windows.Forms.Label(); + this.DatatableKeyBox = new System.Windows.Forms.TextBox(); + this.label20 = new System.Windows.Forms.Label(); this.OkButton = new System.Windows.Forms.Button(); this.groupBox2 = new System.Windows.Forms.GroupBox(); this.DirSelector = new TaikoSoundEditor.PathSelector(); @@ -128,9 +133,11 @@ this.TJASelector = new TaikoSoundEditor.PathSelector(); this.AudioFileSelector = new TaikoSoundEditor.PathSelector(); this.label10 = new System.Windows.Forms.Label(); + this.UseEncryptionBox = new System.Windows.Forms.CheckBox(); this.TabControl.SuspendLayout(); this.tabPage1.SuspendLayout(); this.panel1.SuspendLayout(); + this.groupBox12.SuspendLayout(); this.groupBox2.SuspendLayout(); this.groupBox1.SuspendLayout(); this.tabPage2.SuspendLayout(); @@ -194,18 +201,73 @@ // panel1 // this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.Controls.Add(this.groupBox12); this.panel1.Controls.Add(this.OkButton); this.panel1.Controls.Add(this.groupBox2); this.panel1.Controls.Add(this.groupBox1); - this.panel1.Location = new System.Drawing.Point(151, 62); + this.panel1.Location = new System.Drawing.Point(146, 56); this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(374, 229); + this.panel1.Size = new System.Drawing.Size(374, 344); this.panel1.TabIndex = 1; // + // groupBox12 + // + this.groupBox12.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox12.Controls.Add(this.UseEncryptionBox); + this.groupBox12.Controls.Add(this.FumenKeyBox); + this.groupBox12.Controls.Add(this.label21); + this.groupBox12.Controls.Add(this.DatatableKeyBox); + this.groupBox12.Controls.Add(this.label20); + this.groupBox12.Location = new System.Drawing.Point(3, 204); + this.groupBox12.Name = "groupBox12"; + this.groupBox12.Size = new System.Drawing.Size(368, 108); + this.groupBox12.TabIndex = 12; + this.groupBox12.TabStop = false; + this.groupBox12.Text = "AES keys"; + // + // FumenKeyBox + // + this.FumenKeyBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.FumenKeyBox.Location = new System.Drawing.Point(68, 52); + this.FumenKeyBox.Name = "FumenKeyBox"; + this.FumenKeyBox.Size = new System.Drawing.Size(294, 23); + this.FumenKeyBox.TabIndex = 13; + this.FumenKeyBox.TextChanged += new System.EventHandler(this.FumenKeyBox_TextChanged); + // + // label21 + // + this.label21.AutoSize = true; + this.label21.Location = new System.Drawing.Point(6, 55); + this.label21.Name = "label21"; + this.label21.Size = new System.Drawing.Size(44, 15); + this.label21.TabIndex = 12; + this.label21.Text = "Fumen"; + // + // DatatableKeyBox + // + this.DatatableKeyBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.DatatableKeyBox.Location = new System.Drawing.Point(68, 23); + this.DatatableKeyBox.Name = "DatatableKeyBox"; + this.DatatableKeyBox.Size = new System.Drawing.Size(294, 23); + this.DatatableKeyBox.TabIndex = 11; + this.DatatableKeyBox.TextChanged += new System.EventHandler(this.DatatableKeyBox_TextChanged); + // + // label20 + // + this.label20.AutoSize = true; + this.label20.Location = new System.Drawing.Point(6, 26); + this.label20.Name = "label20"; + this.label20.Size = new System.Drawing.Size(57, 15); + this.label20.TabIndex = 10; + this.label20.Text = "Datatable"; + // // OkButton // this.OkButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.OkButton.Location = new System.Drawing.Point(262, 203); + this.OkButton.Location = new System.Drawing.Point(262, 318); this.OkButton.Name = "OkButton"; this.OkButton.Size = new System.Drawing.Size(109, 23); this.OkButton.TabIndex = 10; @@ -1274,6 +1336,16 @@ this.label10.TabIndex = 8; this.label10.Text = "Audio file"; // + // UseEncryptionBox + // + this.UseEncryptionBox.AutoSize = true; + this.UseEncryptionBox.Location = new System.Drawing.Point(68, 83); + this.UseEncryptionBox.Name = "UseEncryptionBox"; + this.UseEncryptionBox.Size = new System.Drawing.Size(105, 19); + this.UseEncryptionBox.TabIndex = 14; + this.UseEncryptionBox.Text = "Use Encryption"; + this.UseEncryptionBox.UseVisualStyleBackColor = true; + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); @@ -1288,6 +1360,8 @@ this.TabControl.ResumeLayout(false); this.tabPage1.ResumeLayout(false); this.panel1.ResumeLayout(false); + this.groupBox12.ResumeLayout(false); + this.groupBox12.PerformLayout(); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); this.groupBox1.ResumeLayout(false); @@ -1435,5 +1509,11 @@ private ToolStripMenuItem SortByIdToolStripMenuItem; private ToolStripMenuItem NoSortToolStripMenuItem; private ToolStripMenuItem checkForUpdatesToolStripMenuItem; + private GroupBox groupBox12; + private Label label20; + private TextBox FumenKeyBox; + private Label label21; + private TextBox DatatableKeyBox; + private CheckBox UseEncryptionBox; } } \ No newline at end of file diff --git a/MainForm.RequestFiles.cs b/MainForm.RequestFiles.cs index 0f9f341..73843dd 100644 --- a/MainForm.RequestFiles.cs +++ b/MainForm.RequestFiles.cs @@ -67,33 +67,35 @@ namespace TaikoSoundEditor { Logger.Info($"Clicked 'Looks good' "); + Config.DatatableIO.IsEncrypted = UseEncryptionBox.Checked; + try - { - MusicAttributes = Json.Deserialize(GZ.DecompressString(MusicAttributePath)); + { + MusicAttributes = Config.DatatableIO.Deserialize(MusicAttributePath); } catch (Exception ex) { throw new Exception($"Failed to parse\n{MusicAttributePath}\nReason:\n{ex.InnerException}"); } try - { - MusicOrders = Json.Deserialize(GZ.DecompressString(MusicOrderPath)); + { + MusicOrders = Config.DatatableIO.Deserialize(MusicOrderPath); } catch (Exception ex) { throw new Exception($"Failed to parse\n{MusicOrderPath}\nReason:\n{ex.InnerException}"); } try - { - MusicInfos = Json.Deserialize(GZ.DecompressString(MusicInfoPath)); + { + MusicInfos = Config.DatatableIO.Deserialize(MusicInfoPath); } catch (Exception ex) { throw new Exception($"Failed to parse\n{MusicInfoPath}\nReason:\n{ex.InnerException}"); } try - { - WordList = Json.Deserialize(GZ.DecompressString(WordListPath)); + { + WordList = Config.DatatableIO.Deserialize(WordListPath); } catch (Exception ex) { diff --git a/MainForm.cs b/MainForm.cs index d30cc47..ae67a26 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -20,6 +20,9 @@ namespace TaikoSoundEditor SimpleGenreBox.DataSource = Enum.GetValues(typeof(Genre)); + DatatableKeyBox.Text = Config.IniFile.Read("DatatableKey"); + FumenKeyBox.Text = Config.IniFile.Read("FumenKey"); + LoadPreferences(); //SortByGenreToolStripMenuItem.RadioCheck = true; @@ -401,5 +404,15 @@ namespace TaikoSoundEditor //var rel = await Updates.GetLatestTja2Fumen(); }); + + private void DatatableKeyBox_TextChanged(object sender, EventArgs e) + { + Config.IniFile.Write("DatatableKey", DatatableKeyBox.Text); + } + + private void FumenKeyBox_TextChanged(object sender, EventArgs e) + { + Config.IniFile.Write("FumenKey", FumenKeyBox.Text); + } } } \ No newline at end of file diff --git a/MainForm.resx b/MainForm.resx index 938108a..509ad28 100644 --- a/MainForm.resx +++ b/MainForm.resx @@ -60,4 +60,10 @@ 17, 17 + + 17, 17 + + + 25 + \ No newline at end of file diff --git a/Program.cs b/Program.cs index 4e18201..565ea45 100644 --- a/Program.cs +++ b/Program.cs @@ -1,6 +1,8 @@ using System.Diagnostics; using System.Globalization; using System.Text; +using TaikoSoundEditor.Data; +using TaikoSoundEditor.Utils; namespace TaikoSoundEditor { @@ -15,7 +17,7 @@ namespace TaikoSoundEditor Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; - + SSL.LoadKeys(); ApplicationConfiguration.Initialize(); diff --git a/Properties/PublishProfiles/FolderProfile.pubxml.user b/Properties/PublishProfiles/FolderProfile.pubxml.user index 8b7a7b3..847777b 100644 --- a/Properties/PublishProfiles/FolderProfile.pubxml.user +++ b/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - True|2023-08-16T16:59:52.2179312Z;True|2023-07-31T20:19:48.4524724+03:00;False|2023-07-31T20:17:55.5982472+03:00;False|2023-07-31T20:17:38.1663347+03:00;True|2023-07-31T19:49:36.9770534+03:00;True|2023-07-31T19:48:14.6352025+03:00;True|2023-07-30T09:51:53.3737837+03:00;True|2023-07-30T09:20:22.7718733+03:00;True|2023-07-30T09:02:22.1384796+03:00;True|2023-07-30T08:20:21.5020489+03:00;True|2023-07-29T11:28:56.2445862+03:00;True|2023-07-29T11:05:03.3876668+03:00;True|2023-07-29T10:54:04.8963992+03:00;True|2023-07-29T10:22:03.4096107+03:00;True|2023-07-29T10:05:26.6712083+03:00;True|2023-07-28T19:30:15.3174413+03:00;True|2023-07-22T19:07:39.3718711+03:00;True|2023-07-22T19:06:41.2393088+03:00;True|2023-07-22T12:07:26.2620601+03:00;True|2023-07-22T12:06:39.9230498+03:00;True|2023-07-22T11:29:18.0153916+03:00;True|2023-07-22T08:23:07.5000923+03:00;True|2023-07-21T20:03:15.6598520+03:00;True|2023-07-21T19:41:13.2800435+03:00;True|2023-07-19T13:08:33.4726289+03:00;True|2023-07-19T12:08:17.2430335+03:00;True|2023-07-18T09:38:50.7615921+03:00;True|2023-07-18T09:25:23.0403589+03:00;True|2023-07-17T17:57:08.1469738+03:00;True|2023-07-17T11:28:41.9554245+03:00;True|2023-07-17T11:15:26.2194507+03:00; + True|2023-08-16T17:18:53.8725792Z;True|2023-08-16T19:59:52.2179312+03:00;True|2023-07-31T20:19:48.4524724+03:00;False|2023-07-31T20:17:55.5982472+03:00;False|2023-07-31T20:17:38.1663347+03:00;True|2023-07-31T19:49:36.9770534+03:00;True|2023-07-31T19:48:14.6352025+03:00;True|2023-07-30T09:51:53.3737837+03:00;True|2023-07-30T09:20:22.7718733+03:00;True|2023-07-30T09:02:22.1384796+03:00;True|2023-07-30T08:20:21.5020489+03:00;True|2023-07-29T11:28:56.2445862+03:00;True|2023-07-29T11:05:03.3876668+03:00;True|2023-07-29T10:54:04.8963992+03:00;True|2023-07-29T10:22:03.4096107+03:00;True|2023-07-29T10:05:26.6712083+03:00;True|2023-07-28T19:30:15.3174413+03:00;True|2023-07-22T19:07:39.3718711+03:00;True|2023-07-22T19:06:41.2393088+03:00;True|2023-07-22T12:07:26.2620601+03:00;True|2023-07-22T12:06:39.9230498+03:00;True|2023-07-22T11:29:18.0153916+03:00;True|2023-07-22T08:23:07.5000923+03:00;True|2023-07-21T20:03:15.6598520+03:00;True|2023-07-21T19:41:13.2800435+03:00;True|2023-07-19T13:08:33.4726289+03:00;True|2023-07-19T12:08:17.2430335+03:00;True|2023-07-18T09:38:50.7615921+03:00;True|2023-07-18T09:25:23.0403589+03:00;True|2023-07-17T17:57:08.1469738+03:00;True|2023-07-17T11:28:41.9554245+03:00;True|2023-07-17T11:15:26.2194507+03:00; \ No newline at end of file diff --git a/SSL.cs b/SSL.cs new file mode 100644 index 0000000..1999888 --- /dev/null +++ b/SSL.cs @@ -0,0 +1,90 @@ +using System.Diagnostics; +using System.Security.Cryptography; +using System.Text.RegularExpressions; +using TaikoSoundEditor.Utils; + +namespace TaikoSoundEditor +{ + internal static class SSL + { + private static byte[] GetKeyFromString(string str) + { + if (str == null) return null; + if (Regex.IsMatch(str, @"^[0-9a-fA-F]{64}$")) + { + List bytes = new List(); + for (int i = 0; i < 64; i += 2) + bytes.Add(byte.Parse($"{str[i]}{str[i + 1]}", System.Globalization.NumberStyles.HexNumber)); + return bytes.ToArray(); + } + return null; + } + + public static void LoadKeys() + { + DatatableKey = GetKeyFromString(Config.IniFile.Read("DatatableKey")); + FumenKey = GetKeyFromString(Config.IniFile.Read("FumenKey")); + } + + private static byte[] DatatableKey = null; + private static byte[] FumenKey = null; + + public static byte[] DecryptFumen(byte[] data) => Decrypt(data, ExpectKey(FumenKey, "Fumen")); + public static byte[] EncryptFumen(byte[] data) => Encrypt(data, ExpectKey(FumenKey, "Fumen")); + + public static byte[] DecryptDatatable(byte[] data) => Decrypt(data, ExpectKey(DatatableKey, "Datatable")); + public static byte[] EncryptDatatable(byte[] data) => Encrypt(data, ExpectKey(DatatableKey, "Datatable")); + + // https://gist.github.com/mhingston/a47caa21298950abc4d8422d98b7437e + public static byte[] Encrypt(byte[] bytes, byte[] key) + { + byte[] cipherData; + Aes aes = Aes.Create(); + aes.Key = key; + aes.IV = new byte[16]; + //aes.GenerateIV(); + aes.Mode = CipherMode.CBC; + ICryptoTransform cipher = aes.CreateEncryptor(aes.Key, aes.IV); + + using (MemoryStream ms = new MemoryStream()) + { + using (CryptoStream cs = new CryptoStream(ms, cipher, CryptoStreamMode.Write)) + { + cs.Write(bytes, 0, bytes.Length); + } + cipherData = ms.ToArray(); + } + + byte[] combinedData = new byte[aes.IV.Length + cipherData.Length]; + Array.Copy(aes.IV, 0, combinedData, 0, aes.IV.Length); + Array.Copy(cipherData, 0, combinedData, aes.IV.Length, cipherData.Length); + return combinedData; + } + + public static byte[] Decrypt(byte[] combinedData, byte[] key) + { + Aes aes = Aes.Create(); + aes.Key = key; + byte[] iv = new byte[aes.BlockSize / 8]; + byte[] cipherText = new byte[combinedData.Length - iv.Length]; + Array.Copy(combinedData, iv, iv.Length); + Array.Copy(combinedData, iv.Length, cipherText, 0, cipherText.Length); + aes.IV = iv; + aes.Mode = CipherMode.CBC; + ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV); + using (MemoryStream ms = new MemoryStream(cipherText)) + using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read)) + using (MemoryStream rs = new MemoryStream()) + { + cs.CopyTo(rs); + return rs.ToArray(); + } + } + + private static byte[] ExpectKey(byte[] key, string keyName) + { + //if (key != null) Debug.WriteLine(string.Join(", ", key.Select(_ => _.ToString("X2")))); + return key ?? throw new InvalidOperationException($"{keyName} key is needed for the requested operation"); + } + } +} diff --git a/TaikoSoundEditor.csproj b/TaikoSoundEditor.csproj index ec2c37b..2ccaf87 100644 --- a/TaikoSoundEditor.csproj +++ b/TaikoSoundEditor.csproj @@ -12,6 +12,7 @@ + diff --git a/Utils/Config.cs b/Utils/Config.cs index 8a70c65..7f0c1ae 100644 --- a/Utils/Config.cs +++ b/Utils/Config.cs @@ -18,6 +18,8 @@ namespace TaikoSoundEditor.Utils return ini; } + public static readonly DatatableIO DatatableIO = new DatatableIO(); + public static readonly IniFile IniFile = CreateIniFile(); public static void SetMusicOrderSortById() => IniFile.Write(MusicOrderSortProperty, MusicOrderSortValueId); diff --git a/Utils/DatatableIO.cs b/Utils/DatatableIO.cs new file mode 100644 index 0000000..204e4ed --- /dev/null +++ b/Utils/DatatableIO.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TaikoSoundEditor.Data; + +namespace TaikoSoundEditor.Utils +{ + public class DatatableIO + { + public bool IsEncrypted { get; set; } + + public T Deserialize(string path) + { + if (!IsEncrypted) + return Json.Deserialize(GZ.DecompressString(path)); + else + { + var bytes = SSL.DecryptDatatable(File.ReadAllBytes(path)); + File.WriteAllBytes("res.bin", bytes); + + return Json.Deserialize(GZ.DecompressBytes(SSL.DecryptDatatable(File.ReadAllBytes(path)))); + } + } + + } +} diff --git a/Utils/Emit.cs b/Utils/Emit.cs new file mode 100644 index 0000000..0467d23 --- /dev/null +++ b/Utils/Emit.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TaikoSoundEditor.Utils +{ + internal static class Emit + { + //public + } +}