소스 검색

Add convert command; add encryption utils

ghorsington 5 년 전
부모
커밋
8ed4a94f67

+ 3 - 0
ArcToolkitCLI/ArcToolkitCLI.csproj

@@ -52,6 +52,9 @@
     </Reference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Commands\ConvertCommand.cs" />
+    <Compile Include="Commands\Converters\IConverterCommand.cs" />
+    <Compile Include="Commands\Converters\NeiConverter.cs" />
     <Compile Include="Commands\DecryptCommand.cs" />
     <Compile Include="Commands\ExtractCommand.cs" />
     <Compile Include="Commands\ICommand.cs" />

+ 24 - 0
ArcToolkitCLI/Commands/ConvertCommand.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using ArcToolkitCLI.Commands.Converters;
+using CommandLine;
+
+namespace ArcToolkitCLI.Commands
+{
+    [Verb("convert", HelpText = "Convert between common data types")]
+    public class ConvertCommand : ICommand
+    {
+        [Value(0, Default = new string[0])]
+        public IEnumerable<string> SubArgs { get; set; }
+
+        public int Run()
+        {
+            var commandTypes = typeof(ConvertCommand).Assembly.GetTypes()
+                .Where(t => !t.IsInterface && !t.IsAbstract && typeof(IConverterCommand).IsAssignableFrom(t)).ToArray();
+
+            return Parser.Default.ParseArguments(SubArgs, commandTypes)
+                .MapResult((object t) => ((IConverterCommand)t).Run(), errs => 1);
+        }
+    }
+}

+ 13 - 0
ArcToolkitCLI/Commands/Converters/IConverterCommand.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ArcToolkitCLI.Commands.Converters
+{
+    interface IConverterCommand
+    {
+        int Run();
+    }
+}

+ 55 - 0
ArcToolkitCLI/Commands/Converters/NeiConverter.cs

@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using ArcToolkitCLI.Commands.Options;
+using ArcToolkitCLI.Util;
+using CommandLine;
+
+namespace ArcToolkitCLI.Commands.Converters
+{
+    [Verb("nei", HelpText = "Convert NEI files into CSV and back")]
+    class NeiConverter : IConverterCommand, IInputOptions, IOutputOptions
+    {
+        public int Run()
+        {
+            var files = Glob.EnumerateFiles(Input);
+
+            if (!files.Any())
+            {
+                Console.WriteLine("No files specified. Run `convert help nei` for help.");
+                return 0;
+            }
+
+            foreach (var file in files)
+            {
+                switch (file.Extension.ToLowerInvariant())
+                {
+                    case "nei":
+                        ToCSV(file.FullName);
+                        break;
+                    case "csv":
+                        ToNei(file.FullName);
+                        break;
+                    default:
+                        Console.WriteLine($"File {file.FullName} is neither .nei nor .csv file. Skipping...");
+                        break;
+                }
+            }
+
+            return 0;
+        }
+
+        void ToNei(string filePath)
+        {
+
+        }
+
+        void ToCSV(string filePath)
+        {
+
+        }
+
+        public IEnumerable<string> Input { get; set; }
+        public string Output { get; set; }
+    }
+}

+ 1 - 1
ArcToolkitCLI/Commands/Options/IInputOptions.cs

@@ -5,7 +5,7 @@ namespace ArcToolkitCLI.Commands.Options
 {
     internal interface IInputOptions
     {
-        [Value(0, MetaName = "input", HelpText = "Input ARC files")]
+        [Value(0, MetaName = "input", HelpText = "Input file(s)")]
         IEnumerable<string> Input { get; set; }
     }
 }

+ 71 - 0
ArcToolkitCLI/Util/Encryption.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
+using System.Security.Cryptography;
 using ArcToolkitCLI.Commands.Options;
 
 namespace ArcToolkitCLI.Util
@@ -42,5 +43,75 @@ namespace ArcToolkitCLI.Util
 
             return 0;
         }
+
+        public static byte[] GenerateIV(byte[] ivSeed)
+        {
+            uint[] seed = { 0x075BCD15, 0x159A55E5, 0x1F123BB5, BitConverter.ToUInt32(ivSeed, 1) ^ 0xBFBFBFBF };
+
+            for (int i = 0; i < 4; i++)
+            {
+                uint n = seed[0] ^ (seed[0] << 11);
+                seed[0] = seed[1];
+                seed[1] = seed[2];
+                seed[2] = seed[3];
+                seed[3] = n ^ seed[3] ^ ((n ^ (seed[3] >> 11)) >> 8);
+            }
+
+            var output = new byte[16];
+
+            Buffer.BlockCopy(seed, 0, output, 0, 16);
+
+            return output;
+        }
+
+        public static byte[] DecryptBytes(byte[] encryptedBytes, byte[] key)
+        {
+            var ivSeed = new byte[5];
+            Array.Copy(encryptedBytes, encryptedBytes.Length - 5, ivSeed, 0, 5);
+
+            byte[] iv = GenerateIV(ivSeed);
+
+            using (var rijndael = new RijndaelManaged())
+            {
+                rijndael.Padding = PaddingMode.None;
+
+                using (ICryptoTransform decryptor = rijndael.CreateDecryptor(key, iv))
+                using (var mem = new MemoryStream(encryptedBytes, 0, encryptedBytes.Length - 5))
+                using (var stream = new CryptoStream(mem, decryptor, CryptoStreamMode.Read))
+                {
+                    var output = new byte[encryptedBytes.Length - 5];
+
+                    stream.Read(output, 0, output.Length);
+
+                    return output;
+                }
+            }
+        }
+
+        public static byte[] EncryptBytes(byte[] data, byte[] key, byte[] ivSeed, byte[] extraData = null)
+        {
+            if(extraData?.Length > 255)
+                throw new ArgumentException("Extra data cannot be larger than 255 bytes!", nameof(extraData));
+
+            byte[] iv = GenerateIV(ivSeed);
+
+            using (var rijndael = new RijndaelManaged())
+            {
+                rijndael.Padding = PaddingMode.None;
+
+                using (ICryptoTransform encryptor = rijndael.CreateEncryptor(key, iv))
+                using (var mem = new MemoryStream())
+                {
+                    using (var stream = new CryptoStream(mem, encryptor, CryptoStreamMode.Write))
+                        stream.Write(data, 0, data.Length);
+
+                    byte extraLength = (byte) (extraData?.Length ?? 0);
+                    mem.Write(new []{ (byte)(extraLength ^ ivSeed[0])}, 0, 1);
+                    mem.Write(ivSeed, 0, ivSeed.Length);
+
+                    return mem.ToArray();
+                }
+            }
+        }
     }
 }