From a7db16475a3f5ab6bb7a68d66340eb683e258f10 Mon Sep 17 00:00:00 2001 From: walon Date: Sun, 11 May 2025 10:37:42 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=20Encryptor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Editor/Data/RvaDataAllocator.cs | 6 +- Editor/Emit/DefaultMetadataImporter.cs | 4 +- .../EncryptVirtualMachineSimulator.cs | 257 ------------------ .../EncryptionVirtualMachineSimulator.cs | 60 ++++ Editor/Encryption/IVirtualMachineCreator.cs | 7 + .../Encryption/RandomVirtualMachineCreator.cs | 62 +++++ Editor/Encryption/VirtualMachine.cs | 16 ++ Editor/Obfuscator.cs | 2 +- Editor/Settings/EncryptionVMSettings.cs | 19 ++ Editor/Settings/ObfuzSettings.cs | 3 + Editor/Settings/ObfuzSettingsProvider.cs | 6 + Editor/Settings/SymbolObfusSettings.cs | 2 +- Runtime/DefaultEncryptor.cs | 102 ------- Runtime/EncryptionService.cs | 6 +- Runtime/EncryptorBase.cs | 215 +++++++++++++++ Runtime/IEncryptor.cs | 8 +- Runtime/NullEncryptor.cs | 90 ++++++ 17 files changed, 491 insertions(+), 374 deletions(-) delete mode 100644 Editor/Encryption/EncryptVirtualMachineSimulator.cs create mode 100644 Editor/Encryption/EncryptionVirtualMachineSimulator.cs create mode 100644 Editor/Encryption/IVirtualMachineCreator.cs create mode 100644 Editor/Encryption/RandomVirtualMachineCreator.cs create mode 100644 Editor/Encryption/VirtualMachine.cs create mode 100644 Editor/Settings/EncryptionVMSettings.cs delete mode 100644 Runtime/DefaultEncryptor.cs create mode 100644 Runtime/EncryptorBase.cs create mode 100644 Runtime/NullEncryptor.cs diff --git a/Editor/Data/RvaDataAllocator.cs b/Editor/Data/RvaDataAllocator.cs index 79d82a1..1445938 100644 --- a/Editor/Data/RvaDataAllocator.cs +++ b/Editor/Data/RvaDataAllocator.cs @@ -38,7 +38,7 @@ namespace Obfuz.Data { public FieldDef holderDataField; public FieldDef runtimeValueField; - public long encryptionOps; + public int encryptionOps; public uint size; public List bytes; public int salt; @@ -134,7 +134,7 @@ namespace Obfuz.Data runtimeValueField = runtimeValueField, size = dataHolderType.ClassSize, bytes = new List((int)dataHolderType.ClassSize), - encryptionOps = _random.NextLong(), + encryptionOps = _random.NextInt(), salt = _random.NextInt(), }; _rvaFields.Add(newRvaField); @@ -252,7 +252,7 @@ namespace Obfuz.Data ins.Add(Instruction.Create(OpCodes.Call, importer.InitializedArrayMethod)); // EncryptionService.DecryptBlock(array, field.encryptionOps, field.salt); - ins.Add(Instruction.Create(OpCodes.Ldc_I8, field.encryptionOps)); + ins.Add(Instruction.CreateLdcI4(field.encryptionOps)); ins.Add(Instruction.Create(OpCodes.Ldc_I4, field.salt)); ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptBlock)); diff --git a/Editor/Emit/DefaultMetadataImporter.cs b/Editor/Emit/DefaultMetadataImporter.cs index 11a171d..325f7eb 100644 --- a/Editor/Emit/DefaultMetadataImporter.cs +++ b/Editor/Emit/DefaultMetadataImporter.cs @@ -26,9 +26,9 @@ namespace Obfuz.Emit Assert.IsNotNull(_initializeArray); Type encryptionService = typeof(EncryptionService); - _encryptBlock = mod.Import(encryptionService.GetMethod("EncryptBlock", new[] { typeof(byte[]), typeof(long), typeof(int) })); + _encryptBlock = mod.Import(encryptionService.GetMethod("EncryptBlock", new[] { typeof(byte[]), typeof(int), typeof(int) })); Assert.IsNotNull(_encryptBlock); - _decryptBlock = mod.Import(encryptionService.GetMethod("DecryptBlock", new[] { typeof(byte[]), typeof(long), typeof(int) })); + _decryptBlock = mod.Import(encryptionService.GetMethod("DecryptBlock", new[] { typeof(byte[]), typeof(int), typeof(int) })); Assert.IsNotNull(_decryptBlock); _encryptInt = mod.Import(encryptionService.GetMethod("Encrypt", new[] { typeof(int), typeof(int), typeof(int) })); Assert.IsNotNull(_encryptInt); diff --git a/Editor/Encryption/EncryptVirtualMachineSimulator.cs b/Editor/Encryption/EncryptVirtualMachineSimulator.cs deleted file mode 100644 index 80f9736..0000000 --- a/Editor/Encryption/EncryptVirtualMachineSimulator.cs +++ /dev/null @@ -1,257 +0,0 @@ -using Obfuz.Utils; -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Runtime.CompilerServices; -using System.Text; -using Unity.Collections.LowLevel.Unsafe; -using UnityEngine.Assertions; -using UnityEngine.UIElements; - -namespace Obfuz.Encryption -{ - public class VirtualMachine - { - public const int SecretKeyLength = 1024; - - public readonly int vmSeed; - public readonly EncryptOpCode[] opCodes; - - public VirtualMachine(int vmSeed, EncryptOpCode[] opCodes) - { - this.vmSeed = vmSeed; - this.opCodes = opCodes; - } - } - - public interface IVirtualMachineCreator - { - VirtualMachine CreateVirtualMachine(int opCodeCount, int vmSeed); - } - - public class RandomVirtualMachineCreator : IVirtualMachineCreator - { - private readonly int[] _debugSecretKey; - - public RandomVirtualMachineCreator() - { - _debugSecretKey = new int[VirtualMachine.SecretKeyLength]; - for (int i = 0; i < _debugSecretKey.Length; i++) - { - _debugSecretKey[i] = i; - } - } - - private IEncryptInstruction CreateRandomInstruction(IRandom random, int secretKeyLength) - { - switch (random.NextInt(3)) - { - case 0: - return new AddInstruction(random.NextInt(), random.NextInt(secretKeyLength)); - case 1: - return new XorInstruction(random.NextInt(), random.NextInt(secretKeyLength)); - case 2: - return new BitRotateInstruction(random.NextInt(32), random.NextInt(secretKeyLength)); - default: - throw new System.Exception("Invalid instruction type"); - } - } - - private EncryptOpCode CreateEncryptOpCode(ushort code, IRandom r, int opCodeCount) - { - Assert.IsTrue(code < opCodeCount); - var insts = new IEncryptInstruction[opCodeCount]; - for (int i = 0; i < insts.Length; i++) - { - IEncryptInstruction inst = CreateRandomInstruction(r, VirtualMachine.SecretKeyLength); - Assert.AreEqual(1234, inst.Decrypt(inst.Encrypt(1234, _debugSecretKey, i), _debugSecretKey, i)); - insts[i] = CreateRandomInstruction(r, opCodeCount); - } - var function = new EncryptFunction(insts); - Assert.AreEqual(1234, function.Decrypt(function.Encrypt(1234, _debugSecretKey, code), _debugSecretKey, code)); - return new EncryptOpCode(code, function); - } - - public VirtualMachine CreateVirtualMachine(int opCodeCount, int vmSeed) - { - Assert.IsTrue(opCodeCount > 0); - Assert.AreEqual(0, opCodeCount ^ (opCodeCount - 1)); - IRandom r = new RandomWithKey(new byte[] {1,2,3,4,5,6}, vmSeed); - var opCodes = new EncryptOpCode[opCodeCount]; - for (int i = 0; i < opCodes.Length; i++) - { - opCodes[i] = CreateEncryptOpCode((ushort)i, r, opCodeCount); - } - return new VirtualMachine(vmSeed, opCodes); - } - } - - public class EncryptVirtualMachineSimulator - { - private readonly EncryptOpCode[] _opCodes; - private readonly int[] _secretKey; - - public EncryptVirtualMachineSimulator(EncryptOpCode[] opCodes, int[] secretKey) - { - _opCodes = opCodes; - // should be power of 2 - Assert.AreEqual(0, opCodes.Length ^ (opCodes.Length - 1)); - _secretKey = secretKey; - } - - private List DecodeOps(int ops) - { - var codes = new List(); - while (ops > 0) - { - var code = (ushort)(ops % _opCodes.Length); - codes.Add(code); - ops >>= 16; - } - return codes; - } - - public int Encrypt(int value, int ops, int salt) - { - var codes = DecodeOps(ops); - foreach (var code in codes) - { - var opCode = _opCodes[code]; - value = opCode.Encrypt(value, _secretKey, salt); - } - return value; - } - - public int Decrypt(int value, int ops, int salt) - { - var codes = DecodeOps(ops); - for (int i = codes.Count - 1; i >= 0; i--) - { - var opCode = _opCodes[codes[i]]; - value = opCode.Decrypt(value, _secretKey, salt); - } - return value; - } - - public long Encrypt(long value, int ops, int salt) - { - int low = (int)(value & 0xFFFFFFFF); - int high = (int)((value >> 32) & 0xFFFFFFFF); - var codes = DecodeOps(ops); - - // TODO we should encrypt high with encLow - int encLow = Encrypt(low, ops, salt); - int encHigh = Encrypt(high, ops, salt); - - return ((long)encHigh << 32) | (long)(uint)(encLow); - } - - public long Decrypt(long value, int ops, int salt) - { - int low = (int)(value & 0xFFFFFFFF); - int high = (int)((value >> 32) & 0xFFFFFFFF); - var codes = DecodeOps(ops); - - // TODO we should encrypt high with encLow - int decLow = Decrypt(low, ops, salt); - int decHigh = Decrypt(high, ops, salt); - - return ((long)decHigh << 32) | (long)(uint)(decLow); - } - - public float Encrypt(float value, int ops, int salt) - { - int intValue = UnsafeUtility.As(ref value); - int encValue = Encrypt(intValue, ops, salt); - return UnsafeUtility.As(ref encValue); - } - - public float Decrypt(float value, int ops, int salt) - { - int intValue = UnsafeUtility.As(ref value); - int decValue = Decrypt(intValue, ops, salt); - return UnsafeUtility.As(ref decValue); - } - - public double Encrypt(double value, int ops, int salt) - { - long longValue = UnsafeUtility.As(ref value); - long encValue = Encrypt(longValue, ops, salt); - return UnsafeUtility.As(ref encValue); - } - - public double Decrypt(double value, int ops, int salt) - { - long longValue = UnsafeUtility.As(ref value); - long decValue = Decrypt(longValue, ops, salt); - return UnsafeUtility.As(ref decValue); - } - - public unsafe byte[] Encrypt(byte[] bytes, int offset, int length, int ops, int salt) - { - if (length == 0) - { - return Array.Empty(); - } - // align size to 4 - int align4Length = (length + 3) & ~3; - byte[] encInts = new byte[align4Length]; - Buffer.BlockCopy(bytes, offset, encInts, 0, length); - - int intLength = align4Length >> 2; - fixed (byte* intArr = &bytes[0]) - { - for (int i = 0; i < intLength; i++) - { - int* ele = (int*)intArr + i; - *ele = Encrypt(*ele, ops, salt); - } - } - return encInts; - } - - public unsafe byte[] Decrypt(byte[] value, int offset, int length, int ops, int salt) - { - if (length == 0) - { - return Array.Empty(); - } - int align4Length = (length + 3) & ~3; - int intLength = align4Length >> 2; - byte[] decInts = new byte[align4Length]; - fixed (byte* intArr = &decInts[0]) - { - for (int i = 0; i < intLength; i++) - { - int* ele = (int*)intArr + i; - *ele = Decrypt(*ele, ops, salt); - } - } - return decInts; - } - - public byte[] Encrypt(byte[] bytes, int ops, int salt) - { - return Encrypt(bytes, 0, bytes.Length, ops, salt); - } - - public byte[] Encrypt(string value, int ops, int salt) - { - if (value.Length == 0) - { - return Array.Empty(); - } - byte[] bytes = System.Text.Encoding.UTF8.GetBytes(value); - return Encrypt(bytes, 0, bytes.Length, ops, salt); - } - - public string DecryptString(byte[] value, int offset, int length, int ops, int salt) - { - if (length == 0) - { - return string.Empty; - } - return System.Text.Encoding.UTF8.GetString(Decrypt(value, offset, length, ops, salt)); - } - } -} diff --git a/Editor/Encryption/EncryptionVirtualMachineSimulator.cs b/Editor/Encryption/EncryptionVirtualMachineSimulator.cs new file mode 100644 index 0000000..8161a3c --- /dev/null +++ b/Editor/Encryption/EncryptionVirtualMachineSimulator.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; +using System.Text; +using Unity.Collections.LowLevel.Unsafe; +using UnityEngine.Assertions; +using UnityEngine.UIElements; + +namespace Obfuz.Encryption +{ + + public class EncryptionVirtualMachineSimulator : EncryptorBase + { + private readonly EncryptOpCode[] _opCodes; + private readonly int[] _secretKey; + + public EncryptionVirtualMachineSimulator(EncryptOpCode[] opCodes, int[] secretKey) + { + _opCodes = opCodes; + // should be power of 2 + Assert.AreEqual(0, opCodes.Length ^ (opCodes.Length - 1)); + _secretKey = secretKey; + } + + private List DecodeOps(int ops) + { + var codes = new List(); + while (ops > 0) + { + var code = (ushort)(ops % _opCodes.Length); + codes.Add(code); + ops >>= 16; + } + return codes; + } + + public override int Encrypt(int value, int ops, int salt) + { + var codes = DecodeOps(ops); + foreach (var code in codes) + { + var opCode = _opCodes[code]; + value = opCode.Encrypt(value, _secretKey, salt); + } + return value; + } + + public override int Decrypt(int value, int ops, int salt) + { + var codes = DecodeOps(ops); + for (int i = codes.Count - 1; i >= 0; i--) + { + var opCode = _opCodes[codes[i]]; + value = opCode.Decrypt(value, _secretKey, salt); + } + return value; + } + } +} diff --git a/Editor/Encryption/IVirtualMachineCreator.cs b/Editor/Encryption/IVirtualMachineCreator.cs new file mode 100644 index 0000000..e1098a5 --- /dev/null +++ b/Editor/Encryption/IVirtualMachineCreator.cs @@ -0,0 +1,7 @@ +namespace Obfuz.Encryption +{ + public interface IVirtualMachineCreator + { + VirtualMachine CreateVirtualMachine(int opCodeCount, int vmSeed); + } +} diff --git a/Editor/Encryption/RandomVirtualMachineCreator.cs b/Editor/Encryption/RandomVirtualMachineCreator.cs new file mode 100644 index 0000000..0b33cbb --- /dev/null +++ b/Editor/Encryption/RandomVirtualMachineCreator.cs @@ -0,0 +1,62 @@ +using Obfuz.Utils; +using UnityEngine.Assertions; + +namespace Obfuz.Encryption +{ + public class RandomVirtualMachineCreator : IVirtualMachineCreator + { + private readonly int[] _debugSecretKey; + + public RandomVirtualMachineCreator() + { + _debugSecretKey = new int[VirtualMachine.SecretKeyLength]; + for (int i = 0; i < _debugSecretKey.Length; i++) + { + _debugSecretKey[i] = i; + } + } + + private IEncryptInstruction CreateRandomInstruction(IRandom random, int secretKeyLength) + { + switch (random.NextInt(3)) + { + case 0: + return new AddInstruction(random.NextInt(), random.NextInt(secretKeyLength)); + case 1: + return new XorInstruction(random.NextInt(), random.NextInt(secretKeyLength)); + case 2: + return new BitRotateInstruction(random.NextInt(32), random.NextInt(secretKeyLength)); + default: + throw new System.Exception("Invalid instruction type"); + } + } + + private EncryptOpCode CreateEncryptOpCode(ushort code, IRandom r, int opCodeCount) + { + Assert.IsTrue(code < opCodeCount); + var insts = new IEncryptInstruction[opCodeCount]; + for (int i = 0; i < insts.Length; i++) + { + IEncryptInstruction inst = CreateRandomInstruction(r, VirtualMachine.SecretKeyLength); + Assert.AreEqual(1234, inst.Decrypt(inst.Encrypt(1234, _debugSecretKey, i), _debugSecretKey, i)); + insts[i] = CreateRandomInstruction(r, opCodeCount); + } + var function = new EncryptFunction(insts); + Assert.AreEqual(1234, function.Decrypt(function.Encrypt(1234, _debugSecretKey, code), _debugSecretKey, code)); + return new EncryptOpCode(code, function); + } + + public VirtualMachine CreateVirtualMachine(int opCodeCount, int vmSeed) + { + Assert.IsTrue(opCodeCount > 0); + Assert.AreEqual(0, opCodeCount ^ (opCodeCount - 1)); + IRandom r = new RandomWithKey(new byte[] {1,2,3,4,5,6}, vmSeed); + var opCodes = new EncryptOpCode[opCodeCount]; + for (int i = 0; i < opCodes.Length; i++) + { + opCodes[i] = CreateEncryptOpCode((ushort)i, r, opCodeCount); + } + return new VirtualMachine(vmSeed, opCodes); + } + } +} diff --git a/Editor/Encryption/VirtualMachine.cs b/Editor/Encryption/VirtualMachine.cs new file mode 100644 index 0000000..8d4c543 --- /dev/null +++ b/Editor/Encryption/VirtualMachine.cs @@ -0,0 +1,16 @@ +namespace Obfuz.Encryption +{ + public class VirtualMachine + { + public const int SecretKeyLength = 1024; + + public readonly int vmSeed; + public readonly EncryptOpCode[] opCodes; + + public VirtualMachine(int vmSeed, EncryptOpCode[] opCodes) + { + this.vmSeed = vmSeed; + this.opCodes = opCodes; + } + } +} diff --git a/Editor/Obfuscator.cs b/Editor/Obfuscator.cs index ef2ac26..c788ca5 100644 --- a/Editor/Obfuscator.cs +++ b/Editor/Obfuscator.cs @@ -68,7 +68,7 @@ namespace Obfuz var random = new RandomWithKey(_secretKey, _globalRandomSeed); - var encryptor = new DefaultEncryptor(_secretKey); + var encryptor = new NullEncryptor(_secretKey); var rvaDataAllocator = new RvaDataAllocator(random, encryptor); var constFieldAllocator = new ConstFieldAllocator(encryptor, random, rvaDataAllocator); _ctx = new ObfuscationPassContext diff --git a/Editor/Settings/EncryptionVMSettings.cs b/Editor/Settings/EncryptionVMSettings.cs new file mode 100644 index 0000000..992d576 --- /dev/null +++ b/Editor/Settings/EncryptionVMSettings.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace Obfuz.Settings +{ + [Serializable] + public class EncryptionVMSettings + { + [Tooltip("secret key for generating encryption virtual machine source code")] + public string codeGenerationSecretKey = "Obfuz"; + + [Tooltip("encryption virtual machine source code output dir")] + public string codeOutputDir = "Assets/Obfuz"; + } +} diff --git a/Editor/Settings/ObfuzSettings.cs b/Editor/Settings/ObfuzSettings.cs index 2683011..3b0114a 100644 --- a/Editor/Settings/ObfuzSettings.cs +++ b/Editor/Settings/ObfuzSettings.cs @@ -32,6 +32,9 @@ namespace Obfuz.Settings [Tooltip("global random seed")] public int globalRandomSeed = 0; + [Tooltip("encryption virtual machine settings")] + public EncryptionVMSettings encryptionVMSettings; + [Tooltip("symbol obfuscation settings")] public SymbolObfusSettings symbolObfusSettings; diff --git a/Editor/Settings/ObfuzSettingsProvider.cs b/Editor/Settings/ObfuzSettingsProvider.cs index b5311b0..39dac82 100644 --- a/Editor/Settings/ObfuzSettingsProvider.cs +++ b/Editor/Settings/ObfuzSettingsProvider.cs @@ -36,6 +36,8 @@ namespace Obfuz.Settings private SerializedProperty _enabledObfuscationPasses; private SerializedProperty _secretKey; private SerializedProperty _globalRandomSeed; + + private SerializedProperty _encryptionVMSettings; private SerializedProperty _symbolObfusSettings; private SerializedProperty _constEncryptSettings; @@ -71,6 +73,8 @@ namespace Obfuz.Settings _secretKey = _serializedObject.FindProperty("secretKey"); _globalRandomSeed = _serializedObject.FindProperty("globalRandomSeed"); + _encryptionVMSettings = _serializedObject.FindProperty("encryptionVMSettings"); + _symbolObfusSettings = _serializedObject.FindProperty("symbolObfusSettings"); _constEncryptSettings = _serializedObject.FindProperty("constEncryptSettings"); _fieldEncryptSettings = _serializedObject.FindProperty("fieldEncryptSettings"); @@ -95,6 +99,8 @@ namespace Obfuz.Settings EditorGUILayout.PropertyField(_secretKey); EditorGUILayout.PropertyField(_globalRandomSeed); + EditorGUILayout.PropertyField(_encryptionVMSettings); + EditorGUILayout.PropertyField(_symbolObfusSettings); EditorGUILayout.PropertyField(_constEncryptSettings); EditorGUILayout.PropertyField(_fieldEncryptSettings); diff --git a/Editor/Settings/SymbolObfusSettings.cs b/Editor/Settings/SymbolObfusSettings.cs index f3db0b7..e905904 100644 --- a/Editor/Settings/SymbolObfusSettings.cs +++ b/Editor/Settings/SymbolObfusSettings.cs @@ -15,7 +15,7 @@ namespace Obfuz.Settings [Tooltip("prefix for obfuscated name to avoid name confliction with original name")] public string obfuscatedNamePrefix = "$"; - [Tooltip("obfuscate same namespace to same name")] + [Tooltip("obfuscate same namespace to one name")] public bool useConsistentNamespaceObfuscation = true; [Tooltip("path of mapping.xml")] diff --git a/Runtime/DefaultEncryptor.cs b/Runtime/DefaultEncryptor.cs deleted file mode 100644 index ba12c95..0000000 --- a/Runtime/DefaultEncryptor.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Obfuz -{ - public class DefaultEncryptor : IEncryptor - { - private readonly byte[] _key; - - public DefaultEncryptor(byte[] key) - { - _key = key; - } - - public void EncryptBlock(byte[] data, long ops, int salt) - { - for (int i = 0; i < data.Length; i++) - { - data[i] ^= (byte)(_key[i % _key.Length] ^ salt); - } - } - - public void DecryptBlock(byte[] data, long ops, int salt) - { - for (int i = 0; i < data.Length; i++) - { - data[i] ^= (byte)(_key[i % _key.Length] ^ salt); - } - } - - public int Encrypt(int value, int opts, int salt) - { - return value; - } - - public int Decrypt(int value, int opts, int salt) - { - return value; - } - - public long Encrypt(long value, int opts, int salt) - { - return value; - } - - public long Decrypt(long value, int opts, int salt) - { - return value; - } - - public float Encrypt(float value, int opts, int salt) - { - return value; - } - - public float Decrypt(float value, int opts, int salt) - { - return value; - } - - public double Encrypt(double value, int opts, int salt) - { - return value; - } - - public double Decrypt(double value, int opts, int salt) - { - return value; - } - - public byte[] Encrypt(byte[] value, int offset, int length, int opts, int salt) - { - int align4Length = (length + 3) & ~3; - var encryptedBytes = new byte[align4Length]; - Buffer.BlockCopy(value, offset, encryptedBytes, 0, length); - return encryptedBytes; - } - - public byte[] Decrypt(byte[] value, int offset, int length, int ops, int salt) - { - byte[] byteArr = new byte[length]; - Buffer.BlockCopy(value, 0, byteArr, 0, length); - return byteArr; - } - - public byte[] Encrypt(string value, int ops, int salt) - { - byte[] bytes = Encoding.UTF8.GetBytes(value); - return Encrypt(bytes, 0, bytes.Length, ops, salt); - } - - public string DecryptString(byte[] value, int offset, int length, int ops, int salt) - { - byte[] bytes = new byte[length]; - Buffer.BlockCopy(value, 0, bytes, 0, length); - return Encoding.UTF8.GetString(bytes); - } - } -} diff --git a/Runtime/EncryptionService.cs b/Runtime/EncryptionService.cs index e29e7ab..4a35a34 100644 --- a/Runtime/EncryptionService.cs +++ b/Runtime/EncryptionService.cs @@ -8,14 +8,14 @@ namespace Obfuz { public static class EncryptionService { - private static readonly IEncryptor _encryptor = new DefaultEncryptor(new byte[] { 0x1A, 0x2B, 0x3C, 0x4D }); + private static readonly IEncryptor _encryptor = new NullEncryptor(new byte[] { 0x1A, 0x2B, 0x3C, 0x4D }); - public static void EncryptBlock(byte[] data, long ops, int salt) + public static void EncryptBlock(byte[] data, int ops, int salt) { _encryptor.EncryptBlock(data, ops, salt); } - public static void DecryptBlock(byte[] data, long ops, int salt) + public static void DecryptBlock(byte[] data, int ops, int salt) { _encryptor.DecryptBlock(data, ops, salt); } diff --git a/Runtime/EncryptorBase.cs b/Runtime/EncryptorBase.cs new file mode 100644 index 0000000..360b27f --- /dev/null +++ b/Runtime/EncryptorBase.cs @@ -0,0 +1,215 @@ +using System; +using System.Text; +using Unity.Collections.LowLevel.Unsafe; + +namespace Obfuz +{ + public abstract class EncryptorBase : IEncryptor + { + public abstract int Encrypt(int value, int opts, int salt); + public abstract int Decrypt(int value, int opts, int salt); + + public virtual long Encrypt(long value, int opts, int salt) + { + int low = (int)value; + int high = (int)(value >> 32); + int encryptedLow = Encrypt(low, opts, salt); + int encryptedHigh = Encrypt(high, opts, salt); + return ((long)encryptedHigh << 32) | (uint)encryptedLow; + } + + public virtual long Decrypt(long value, int opts, int salt) + { + int low = (int)value; + int high = (int)(value >> 32); + int decryptedLow = Decrypt(low, opts, salt); + int decryptedHigh = Decrypt(high, opts, salt); + return ((long)decryptedHigh << 32) | (uint)decryptedLow; + } + + public virtual float Encrypt(float value, int opts, int salt) + { + ref int intValue = ref UnsafeUtility.As(ref value); + intValue = Encrypt(intValue, opts, salt); + return value; + } + + public virtual float Decrypt(float value, int opts, int salt) + { + ref int intValue = ref UnsafeUtility.As(ref value); + intValue = Decrypt(intValue, opts, salt); + return value; + } + + public virtual double Encrypt(double value, int opts, int salt) + { + ref long longValue = ref UnsafeUtility.As(ref value); + longValue = Encrypt(longValue, opts, salt); + return value; + } + + public virtual double Decrypt(double value, int opts, int salt) + { + ref long longValue = ref UnsafeUtility.As(ref value); + longValue = Decrypt(longValue, opts, salt); + return value; + } + + public virtual unsafe byte[] Encrypt(byte[] value, int offset, int length, int ops, int salt) + { + if (length == 0) + { + return Array.Empty(); + } + + var encryptedBytes = new byte[length]; + int intArrLength = length >> 2; + + // align to 4 + if ((offset & 0x3) != 0) + { + Buffer.BlockCopy(value, offset, encryptedBytes, 0, length); + + // encrypt int + + fixed (byte* dstBytePtr = &encryptedBytes[0]) + { + int* dstIntPtr = (int*)dstBytePtr; + + for (int i = 0; i < intArrLength; i++) + { + dstIntPtr[i] = Encrypt(dstIntPtr[i], ops, salt); + } + } + for (int i = intArrLength * 4; i < length; i++) + { + encryptedBytes[i] = (byte)(encryptedBytes[i] ^ salt); + } + } + else + { + // encrypt int + fixed (byte* srcBytePtr = &value[offset]) + { + fixed (byte* dstBytePtr = &encryptedBytes[0]) + { + int* srcIntPtr = (int*)srcBytePtr; + int* dstIntPtr = (int*)dstBytePtr; + + for (int i = 0; i < intArrLength; i++) + { + dstIntPtr[i] = Encrypt(srcIntPtr[i], ops, salt); + } + } + } + for (int i = intArrLength * 4; i < length; i++) + { + encryptedBytes[i] = (byte)(value[offset + i] ^ salt); + } + } + return encryptedBytes; + } + + public unsafe virtual byte[] Decrypt(byte[] value, int offset, int length, int ops, int salt) + { + var decryptedBytes = new byte[length]; + int intArrLength = length >> 2; + + // align to 4 + if ((offset & 0x3) != 0) + { + Buffer.BlockCopy(value, offset, decryptedBytes, 0, length); + + // encrypt int + + fixed (byte* dstBytePtr = &decryptedBytes[0]) + { + int* dstIntPtr = (int*)dstBytePtr; + + for (int i = 0; i < intArrLength; i++) + { + dstIntPtr[i] = Decrypt(dstIntPtr[i], ops, salt); + } + } + for (int i = intArrLength * 4; i < length; i++) + { + decryptedBytes[i] = (byte)(decryptedBytes[i] ^ salt); + } + } + else + { + // encrypt int + fixed (byte* srcBytePtr = &value[offset]) + { + fixed (byte* dstBytePtr = &decryptedBytes[0]) + { + int* srcIntPtr = (int*)srcBytePtr; + int* dstIntPtr = (int*)dstBytePtr; + + for (int i = 0; i < intArrLength; i++) + { + dstIntPtr[i] = Decrypt(srcIntPtr[i], ops, salt); + } + } + } + for (int i = intArrLength * 4; i < length; i++) + { + decryptedBytes[i] = (byte)(value[offset + i] ^ salt); + } + } + return decryptedBytes; + } + + public virtual byte[] Encrypt(string value, int ops, int salt) + { + byte[] bytes = Encoding.UTF8.GetBytes(value); + return Encrypt(bytes, 0, bytes.Length, ops, salt); + } + + public virtual string DecryptString(byte[] value, int offset, int length, int ops, int salt) + { + byte[] bytes = Decrypt(value, offset, length, ops, salt); + return Encoding.UTF8.GetString(bytes); + } + + public virtual unsafe void EncryptBlock(byte[] data, int ops, int salt) + { + int length = data.Length; + int intArrLength = length >> 2; + + fixed (byte* dstBytePtr = &data[0]) + { + int* dstIntPtr = (int*)dstBytePtr; + + for (int i = 0; i < intArrLength; i++) + { + dstIntPtr[i] = Encrypt(dstIntPtr[i], ops, salt); + } + } + for (int i = intArrLength * 4; i < length; i++) + { + data[i] = (byte)(data[i] ^ salt); + } + } + + public virtual unsafe void DecryptBlock(byte[] data, int ops, int salt) + { + int length = data.Length; + int intArrLength = length >> 2; + + fixed (byte* dstBytePtr = &data[0]) + { + int* dstIntPtr = (int*)dstBytePtr; + + for (int i = 0; i < intArrLength; i++) + { + dstIntPtr[i] = Decrypt(dstIntPtr[i], ops, salt); + } + } + for (int i = intArrLength * 4; i < length; i++) + { + data[i] = (byte)(data[i] ^ salt); + } + } + } +} diff --git a/Runtime/IEncryptor.cs b/Runtime/IEncryptor.cs index 06af582..6c6d9ca 100644 --- a/Runtime/IEncryptor.cs +++ b/Runtime/IEncryptor.cs @@ -1,15 +1,13 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; namespace Obfuz { public interface IEncryptor { - void EncryptBlock(byte[] data, long ops, int salt); - void DecryptBlock(byte[] data, long ops, int salt); + void EncryptBlock(byte[] data, int ops, int salt); + void DecryptBlock(byte[] data, int ops, int salt); int Encrypt(int value, int opts, int salt); int Decrypt(int value, int opts, int salt); diff --git a/Runtime/NullEncryptor.cs b/Runtime/NullEncryptor.cs new file mode 100644 index 0000000..7643dcf --- /dev/null +++ b/Runtime/NullEncryptor.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Obfuz +{ + public class NullEncryptor : EncryptorBase + { + private readonly byte[] _key; + + public NullEncryptor(byte[] key) + { + _key = key; + } + + public override int Encrypt(int value, int opts, int salt) + { + return value; + } + + public override int Decrypt(int value, int opts, int salt) + { + return value; + } + + public override long Encrypt(long value, int opts, int salt) + { + return value; + } + + public override long Decrypt(long value, int opts, int salt) + { + return value; + } + + public override float Encrypt(float value, int opts, int salt) + { + return value; + } + + public override float Decrypt(float value, int opts, int salt) + { + return value; + } + + public override double Encrypt(double value, int opts, int salt) + { + return value; + } + + public override double Decrypt(double value, int opts, int salt) + { + return value; + } + + public override byte[] Encrypt(byte[] value, int offset, int length, int opts, int salt) + { + if (length == 0) + { + return Array.Empty(); + } + var encryptedBytes = new byte[length]; + Buffer.BlockCopy(value, offset, encryptedBytes, 0, length); + return encryptedBytes; + } + + public override byte[] Decrypt(byte[] value, int offset, int length, int ops, int salt) + { + if (length == 0) + { + return Array.Empty(); + } + byte[] byteArr = new byte[length]; + Buffer.BlockCopy(value, 0, byteArr, 0, length); + return byteArr; + } + + public override byte[] Encrypt(string value, int ops, int salt) + { + return Encoding.UTF8.GetBytes(value); + } + + public override string DecryptString(byte[] value, int offset, int length, int ops, int salt) + { + return Encoding.UTF8.GetString(value, offset, length); + } + } +}