diff --git a/l2-unity/Assets/Scripts/Game/Manager/GameManager.cs b/l2-unity/Assets/Scripts/Game/Manager/GameManager.cs index eb6e998ba..7fd3b684e 100644 --- a/l2-unity/Assets/Scripts/Game/Manager/GameManager.cs +++ b/l2-unity/Assets/Scripts/Game/Manager/GameManager.cs @@ -40,7 +40,6 @@ private void LoadTables() { } public void LogIn() { - LoginClient.Instance.Connect(StringUtils.GenerateRandomString()); } public void LogOut() { diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/AsynchronousClient.cs b/l2-unity/Assets/Scripts/Networking/ClientLibrary/AsynchronousClient.cs index b5c381b7a..b0cc1e3bd 100644 --- a/l2-unity/Assets/Scripts/Networking/ClientLibrary/AsynchronousClient.cs +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/AsynchronousClient.cs @@ -29,7 +29,6 @@ public class AsynchronousClient { private BlowfishEngine _blowfish; private Socket _socket; private string _ipAddress; - private string _username; private int _port; private bool _connected; private ClientPacketHandler _clientPacketHandler; @@ -37,9 +36,13 @@ public class AsynchronousClient { private DefaultClient _client; private bool _initPacket = true; - private byte[] _blowfishKey; - public byte[] BlowfishKey { get { return _blowfishKey; } set { _blowfishKey = value; } } + private RSACrypt _rsa; + public RSACrypt RSACrypt { get { return _rsa; } } + private byte[] _blowfishKey; + public byte[] BlowfishKey { get { return _blowfishKey; } set { SetBlowFishKey(value); } } + public string Account { get { return _client.Account; } } + public string Password { get { return _client.Password; } } public int Ping { get; set; } public AsynchronousClient(string ip, int port, DefaultClient client, ClientPacketHandler clientPacketHandler, ServerPacketHandler serverPacketHandler) { @@ -57,7 +60,14 @@ public AsynchronousClient(string ip, int port, DefaultClient client, ClientPacke public void SetBlowFishKey(byte[] blowfishKey) { _blowfishKey = blowfishKey; _blowfish = new BlowfishEngine(); - _blowfish.init(false, AsynchronousClient.STATIC_BLOWFISH_KEY); + _blowfish.init(false, blowfishKey); + + Debug.Log("Blowfish key set."); + } + + public void SetRSAKey(byte[] rsaKey) { + _rsa = new RSACrypt(rsaKey, true); + Debug.Log("RSA Key set."); } public bool Connect() { diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/NewCrypt.cs b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/NewCrypt.cs index 6ae9d6934..df1ac100c 100644 --- a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/NewCrypt.cs +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/NewCrypt.cs @@ -1,17 +1,13 @@ namespace L2_login { - class NewCrypt - { - public static bool verifyChecksum(byte[] raw) - { + class NewCrypt { + public static bool verifyChecksum(byte[] raw) { return verifyChecksum(raw, 0, raw.Length); } - public static bool verifyChecksum(byte[] raw, int offset, int size) - { + public static bool verifyChecksum(byte[] raw, int offset, int size) { // check if size is multiple of 4 and if there is more then only the checksum - if ((size & 3) != 0 || size <= 4) - { + if ((size & 3) != 0 || size <= 4) { return false; } @@ -20,8 +16,7 @@ public static bool verifyChecksum(byte[] raw, int offset, int size) ulong check = ulong.MaxValue; int i; - for (i = offset; i < count; i += 4) - { + for (i = offset; i < count; i += 4) { check = (ulong)raw[i] & 0xff; check |= (ulong)raw[i + 1] << 8 & 0xff00; check |= (ulong)raw[i + 2] << 0x10 & 0xff0000; @@ -38,20 +33,17 @@ public static bool verifyChecksum(byte[] raw, int offset, int size) return check == chksum; } - public static void appendChecksum(byte[] raw) - { + public static void appendChecksum(byte[] raw) { appendChecksum(raw, 0, raw.Length); } - public static void appendChecksum(byte[] raw, int offset, int size) - { + public static void appendChecksum(byte[] raw, int offset, int size) { ulong chksum = 0; int count = size - 4; ulong ecx; int i; - for (i = offset; i < count; i += 4) - { + for (i = offset; i < count; i += 4) { ecx = (ulong)raw[i] & 0xff; ecx |= (ulong)raw[i + 1] << 8 & 0xff00; ecx |= (ulong)raw[i + 2] << 0x10 & 0xff0000; @@ -78,8 +70,7 @@ public static void appendChecksum(byte[] raw, int offset, int size) * @param raw The raw bytes to be encrypted * @param key The 4 bytes (int) XOR key */ - public static void encXORPass(byte[] raw, int key) - { + public static void encXORPass(byte[] raw, int key) { encXORPass(raw, 0, raw.Length, key); } @@ -92,15 +83,13 @@ public static void encXORPass(byte[] raw, int key) * @param size Length of the data to be encrypted * @param key The 4 bytes (int) XOR key */ - public static void encXORPass(byte[] raw, int offset, int size, int key) - { + public static void encXORPass(byte[] raw, int offset, int size, int key) { int stop = size - 8; int pos = 4 + offset; int edx; int ecx = key; // Initial xor key - while (pos < stop) - { + while (pos < stop) { edx = raw[pos] & 0xFF; edx |= (raw[pos + 1] & 0xFF) << 8; edx |= (raw[pos + 2] & 0xFF) << 16; @@ -123,35 +112,46 @@ public static void encXORPass(byte[] raw, int offset, int size, int key) raw[pos++] = (byte)(ecx >> 24 & 0xFF); } - public static void decXORPass(byte[] raw, int offset, int size, int key) - { - int stop = 4 + offset; - int pos = size - 12; - int edx; - int ecx = key; // Initial xor key - while (stop <= pos) + public static bool decXORPass(byte[] packet) { + int blen = packet.Length; + + if (blen < 1 || packet == null) + return false; // TODO: Handle error or throw exception + + // Get XOR key + int xorOffset = 8; + uint xorKey = 0; + xorKey |= packet[blen - xorOffset]; + xorKey |= (uint)(packet[blen - xorOffset + 1] << 8); + xorKey |= (uint)(packet[blen - xorOffset + 2] << 16); + xorKey |= (uint)(packet[blen - xorOffset + 3] << 24); + + // Decrypt XOR encrypted portion + int offset = blen - xorOffset - 4; + uint ecx = xorKey; + uint edx = 0; + + while (offset > 2) // Adjust this condition if needed { - edx = raw[pos] & 0xFF; - edx |= (raw[pos + 1] & 0xFF) << 8; - edx |= (raw[pos + 2] & 0xFF) << 16; - edx |= (raw[pos + 3] & 0xFF) << 24; + edx = (uint)(packet[offset + 0] & 0xFF); + edx |= (uint)(packet[offset + 1] & 0xFF) << 8; + edx |= (uint)(packet[offset + 2] & 0xFF) << 16; + edx |= (uint)(packet[offset + 3] & 0xFF) << 24; edx ^= ecx; - ecx -= edx; - raw[pos] = (byte)(edx & 0xFF); - raw[pos + 1] = (byte)(edx >> 8 & 0xFF); - raw[pos + 2] = (byte)(edx >> 16 & 0xFF); - raw[pos + 3] = (byte)(edx >> 24 & 0xFF); - pos -= 4; + packet[offset + 0] = (byte)((edx) & 0xFF); + packet[offset + 1] = (byte)((edx >> 8) & 0xFF); + packet[offset + 2] = (byte)((edx >> 16) & 0xFF); + packet[offset + 3] = (byte)((edx >> 24) & 0xFF); + + offset -= 4; } - //raw[pos++] = (byte)(ecx & 0xFF); - //raw[pos++] = (byte)(ecx >> 8 & 0xFF); - //raw[pos++] = (byte)(ecx >> 16 & 0xFF); - //raw[pos++] = (byte)(ecx >> 24 & 0xFF); + + return true; } } } diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/RSACrypt.cs b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/RSACrypt.cs new file mode 100644 index 000000000..57ec7afed --- /dev/null +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/RSACrypt.cs @@ -0,0 +1,66 @@ +using System; +using System.Security.Cryptography; +using System.Numerics; +using UnityEngine; + +public class RSACrypt +{ + private RSAParameters _rsaParams; + // hardcoded modulus + private byte[] _modulus = new byte[] { 1, 0, 1 }; + + + public RSACrypt(byte[] exponent, bool needUnscramble) { + if(needUnscramble) { + UnscrambledRSAKey(exponent); + } + + InitRSACrypt(exponent); + } + + private void InitRSACrypt(byte[] exponent) { + _rsaParams = new RSAParameters { + Modulus = _modulus, + D = exponent + }; + } + + public void DecryptRSABlock(byte[] encryptedData) { + // Initialize RSA with the parameters + using (RSA rsa = RSA.Create()) { + rsa.ImportParameters(_rsaParams); + + // Decrypt the data + byte[] decryptedData = rsa.Decrypt(encryptedData, RSAEncryptionPadding.Pkcs1); + + // Convert decrypted data to string + string decryptedMessage = System.Text.Encoding.UTF8.GetString(decryptedData); + Console.WriteLine("Decrypted Message: " + decryptedMessage); + } + } + + public void UnscrambledRSAKey(byte[] rsaKey) { + Debug.Log($"Scrambled RSA: {StringUtils.ByteArrayToString(rsaKey)}"); + + // step 4 : xor last 0x40 bytes with first 0x40 bytes + for (int i = 0; i < 0x40; i++) { + rsaKey[0x40 + i] = (byte)(rsaKey[0x40 + i] ^ rsaKey[i]); + } + // step 3 : xor bytes 0x0d-0x10 with bytes 0x34-0x38 + for (int i = 0; i < 4; i++) { + rsaKey[0x0d + i] = (byte)(rsaKey[0x0d + i] ^ rsaKey[0x34 + i]); + } + // step 2 : xor first 0x40 bytes with last 0x40 bytes + for (int i = 0; i < 0x40; i++) { + rsaKey[i] = (byte)(rsaKey[i] ^ rsaKey[0x40 + i]); + } + // step 1 : 0x4d-0x50 <-> 0x00-0x04 + for (int i = 0; i < 4; i++) { + byte temp = rsaKey[0x00 + i]; + rsaKey[0x00 + i] = rsaKey[0x4d + i]; + rsaKey[0x4d + i] = temp; + } + + Debug.Log($"Unscrambled RSA: {StringUtils.ByteArrayToString(rsaKey)}"); + } +} diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/RSACrypt.cs.meta b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/RSACrypt.cs.meta new file mode 100644 index 000000000..60c99a2c3 --- /dev/null +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/RSACrypt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4991832e4a4a8ec4cb2796d81ea0ad19 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/SHACrypt.cs b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/SHACrypt.cs new file mode 100644 index 000000000..6707ba1b9 --- /dev/null +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/SHACrypt.cs @@ -0,0 +1,31 @@ +using System.Collections; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; +using UnityEngine; + +public class SHACrypt +{ + public static string ComputeSha256Hash(string rawData) { + // Create a SHA256 + using (SHA256 sha256Hash = SHA256.Create()) { + // ComputeHash - returns byte array + byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); + + // Convert byte array to a string + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < bytes.Length; i++) { + builder.Append(bytes[i].ToString("x2")); + } + return builder.ToString(); + } + } + + public static byte[] ComputeSha256HashToBytes(string rawData) { + // Create a SHA256 + using (SHA256 sha256Hash = SHA256.Create()) { + // ComputeHash - returns byte array + return sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); + } + } +} diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/SHACrypt.cs.meta b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/SHACrypt.cs.meta new file mode 100644 index 000000000..43027c391 --- /dev/null +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Crypto/SHACrypt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0893983002fb90640b7859a43908296d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Gameserver/ServerPackets/PlayerInfoPacket.cs b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Gameserver/ServerPackets/PlayerInfoPacket.cs index e9d9a2eaf..58e63f9ee 100644 --- a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Gameserver/ServerPackets/PlayerInfoPacket.cs +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Gameserver/ServerPackets/PlayerInfoPacket.cs @@ -25,7 +25,7 @@ public override void Parse() { Identity.SetPosX(ReadF()); Identity.SetPosY(ReadF()); Identity.SetPosZ(ReadF()); - Identity.Owned = Identity.Name == GameClient.Instance.Username; + Identity.Owned = Identity.Name == GameClient.Instance.Account; // Status Status.Level = ReadI(); Status.Hp = ReadI(); diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Gameserver/ServerPackets/UserInfoPacket.cs b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Gameserver/ServerPackets/UserInfoPacket.cs index 3671b1ad8..360555fe8 100644 --- a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Gameserver/ServerPackets/UserInfoPacket.cs +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Gameserver/ServerPackets/UserInfoPacket.cs @@ -25,7 +25,7 @@ public override void Parse() { Identity.SetPosX(ReadF()); Identity.SetPosY(ReadF()); Identity.SetPosZ(ReadF()); - Identity.Owned = Identity.Name == GameClient.Instance.Username; + Identity.Owned = Identity.Name == GameClient.Instance.Account; // Status Status.Level = ReadI(); Status.Hp = ReadI(); diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Loginserver/ServerPackets/InitPacket.cs b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Loginserver/ServerPackets/InitPacket.cs index 9ba67fb83..de1ea48d2 100644 --- a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Loginserver/ServerPackets/InitPacket.cs +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/Loginserver/ServerPackets/InitPacket.cs @@ -1,4 +1,6 @@ -class InitPacket : ServerPacket { +using UnityEngine; + +class InitPacket : ServerPacket { private int sessionId; private int rsaKeyLength; private byte[] publicKey; diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/ServerPacket.cs b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/ServerPacket.cs index 3bf119350..e5a5253f1 100644 --- a/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/ServerPacket.cs +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/Packet/ServerPacket.cs @@ -11,7 +11,6 @@ public abstract class ServerPacket : Packet public ServerPacket(byte[] d) : base(d) { ReadB(); - ReadB(); } protected byte ReadB() { diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/PacketHandler/LoginServer/LoginServerPacketHandler.cs b/l2-unity/Assets/Scripts/Networking/ClientLibrary/PacketHandler/LoginServer/LoginServerPacketHandler.cs index e82daa445..2447d7513 100644 --- a/l2-unity/Assets/Scripts/Networking/ClientLibrary/PacketHandler/LoginServer/LoginServerPacketHandler.cs +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/PacketHandler/LoginServer/LoginServerPacketHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Text; using System.Threading; using System.Threading.Tasks; using UnityEngine; @@ -48,9 +49,28 @@ private void OnPingReceive() { } private void OnInitReceive(byte[] data) { + Debug.Log("On init receive"); InitPacket packet = new InitPacket(data); + + byte[] rsaKey = packet.PublicKey; + byte[] blowfishKey = packet.BlowfishKey; + + _client.SetRSAKey(rsaKey); + _client.SetBlowFishKey(blowfishKey); + string account = _client.Account; + string password = _client.Password; + + account = account.ToLower(); + + byte[] accountBytes = Encoding.UTF8.GetBytes(account); + + Debug.Log(accountBytes.Length); + Debug.Log(StringUtils.ByteArrayToString(accountBytes)); + byte[] shaPass = SHACrypt.ComputeSha256HashToBytes(password); + Debug.Log(shaPass.Length); + Debug.Log(StringUtils.ByteArrayToString(shaPass)); } diff --git a/l2-unity/Assets/Scripts/Networking/ClientLibrary/PacketHandler/ServerPacketHandler.cs b/l2-unity/Assets/Scripts/Networking/ClientLibrary/PacketHandler/ServerPacketHandler.cs index a6245e516..f48eaabfc 100644 --- a/l2-unity/Assets/Scripts/Networking/ClientLibrary/PacketHandler/ServerPacketHandler.cs +++ b/l2-unity/Assets/Scripts/Networking/ClientLibrary/PacketHandler/ServerPacketHandler.cs @@ -23,7 +23,10 @@ await Task.Run(() => { data = DecryptPacket(data, blowfish); if (init) { - DecodeXOR(data); + if(!DecodeXOR(data)) { + Debug.LogError("Packet XOR could not be decoded."); + return; + } } HandlePacket(data); @@ -47,44 +50,11 @@ private byte[] DecryptPacket(byte[] data, BlowfishEngine blowfish) { } public bool DecodeXOR(byte[] packet) { - int blen = packet.Length; - - if (blen < 1 || packet == null) - return false; // TODO: Handle error or throw exception - - // Get XOR key - int xorOffset = 8; - uint xorKey = 0; - xorKey |= packet[blen - xorOffset]; - xorKey |= (uint)(packet[blen - xorOffset + 1] << 8); - xorKey |= (uint)(packet[blen - xorOffset + 2] << 16); - xorKey |= (uint)(packet[blen - xorOffset + 3] << 24); - - // Decrypt XOR encrypted portion - int offset = blen - xorOffset - 4; - uint ecx = xorKey; - uint edx = 0; - - while (offset > 2) // Adjust this condition if needed - { - edx = (uint)(packet[offset + 0] & 0xFF); - edx |= (uint)(packet[offset + 1] & 0xFF) << 8; - edx |= (uint)(packet[offset + 2] & 0xFF) << 16; - edx |= (uint)(packet[offset + 3] & 0xFF) << 24; - - edx ^= ecx; - ecx -= edx; - - packet[offset + 0] = (byte)((edx) & 0xFF); - packet[offset + 1] = (byte)((edx >> 8) & 0xFF); - packet[offset + 2] = (byte)((edx >> 16) & 0xFF); - packet[offset + 3] = (byte)((edx >> 24) & 0xFF); - - offset -= 4; + if(NewCrypt.decXORPass(packet)) { + Debug.Log("CLEAR: " + StringUtils.ByteArrayToString(packet)); + return true; } - Debug.Log("CLEAR: " + StringUtils.ByteArrayToString(packet)); - - return true; + return false; } } diff --git a/l2-unity/Assets/Scripts/Networking/DefaultClient.cs b/l2-unity/Assets/Scripts/Networking/DefaultClient.cs index bf6fd5bb8..262238412 100644 --- a/l2-unity/Assets/Scripts/Networking/DefaultClient.cs +++ b/l2-unity/Assets/Scripts/Networking/DefaultClient.cs @@ -7,14 +7,15 @@ public abstract class DefaultClient : MonoBehaviour { [SerializeField] protected string _serverIp = "127.0.0.1"; [SerializeField] protected int _serverPort = 11000; [SerializeField] protected AsynchronousClient _client; - [SerializeField] protected string _username; [SerializeField] protected int _connectionTimeoutMs = 10000; [SerializeField] protected bool _logReceivedPackets = true; [SerializeField] protected bool _logSentPackets = true; + [SerializeField] protected string _account; + [SerializeField] protected string _password; private bool _connecting = false; - - public string Username { get { return _username; } } + public string Account { get { return _account; } set { _account = value; } } + public string Password { get { return _password; } set { _password = value; } } public bool LogReceivedPackets { get { return _logReceivedPackets; } } public bool LogSentPackets { get { return _logSentPackets; } } public int ConnectionTimeoutMs { get { return _connectionTimeoutMs; } } @@ -25,13 +26,14 @@ private void Start() { } } - public async void Connect(string user) { + public async void Connect(string account, string password) { if(_connecting) { return; } _connecting = true; - _username = user; + _account = account; + _password = password; CreateAsyncClient(); diff --git a/l2-unity/Assets/Scripts/UI/LoginWindow.cs b/l2-unity/Assets/Scripts/UI/Login/LoginWindow.cs similarity index 96% rename from l2-unity/Assets/Scripts/UI/LoginWindow.cs rename to l2-unity/Assets/Scripts/UI/Login/LoginWindow.cs index f1268148d..bf513a6e4 100644 --- a/l2-unity/Assets/Scripts/UI/LoginWindow.cs +++ b/l2-unity/Assets/Scripts/UI/Login/LoginWindow.cs @@ -105,7 +105,9 @@ private Button GetButtonById(string id) { } private void LoginButtonPressed() { - LoginClient.Instance.Connect(StringUtils.GenerateRandomString()); + _userInput.value = "Shnok"; + _passwordInput.value = "1234"; + LoginClient.Instance.Connect(_userInput.value, _passwordInput.value); } private void ExitButtonPressed() { diff --git a/l2-unity/Assets/Scripts/UI/LoginWindow.cs.meta b/l2-unity/Assets/Scripts/UI/Login/LoginWindow.cs.meta similarity index 100% rename from l2-unity/Assets/Scripts/UI/LoginWindow.cs.meta rename to l2-unity/Assets/Scripts/UI/Login/LoginWindow.cs.meta