server-master/srcs/GameChannel/Cryptography/WorldDecrypter.cs
2026-02-10 18:21:30 +01:00

245 lines
No EOL
7.7 KiB
C#

// WingsEmu
//
// Developed by NosWings Team
using System;
using System.IO;
using System.Text;
namespace GameChannel.Cryptography
{
public static class WorldDecrypter
{
public static string Decrypt(in ReadOnlySpan<byte> bytesBuffer, int encryptionKey, Encoding encoding)
{
if (encryptionKey == 0)
{
return DecryptUnauthed(bytesBuffer);
}
return DecryptAuthed(bytesBuffer, encryptionKey, encoding);
}
private static string DecryptAuthed(in ReadOnlySpan<byte> str, int encryptionKey, Encoding encoding)
{
var encryptedString = new StringBuilder();
int sessionKey = encryptionKey & 0xFF;
byte sessionNumber = unchecked((byte)(encryptionKey >> 6));
sessionNumber &= 0xFF;
sessionNumber &= 3;
switch (sessionNumber)
{
case 0:
foreach (byte character in str)
{
byte firstbyte = unchecked((byte)(sessionKey + 0x40));
byte highbyte = unchecked((byte)(character - firstbyte));
encryptedString.Append((char)highbyte);
}
break;
case 1:
foreach (byte character in str)
{
byte firstbyte = unchecked((byte)(sessionKey + 0x40));
byte highbyte = unchecked((byte)(character + firstbyte));
encryptedString.Append((char)highbyte);
}
break;
case 2:
foreach (byte character in str)
{
byte firstbyte = unchecked((byte)(sessionKey + 0x40));
byte highbyte = unchecked((byte)(character - firstbyte ^ 0xC3));
encryptedString.Append((char)highbyte);
}
break;
case 3:
foreach (byte character in str)
{
byte firstbyte = unchecked((byte)(sessionKey + 0x40));
byte highbyte = unchecked((byte)(character + firstbyte ^ 0xC3));
encryptedString.Append((char)highbyte);
}
break;
default:
encryptedString.Append((char)0xF);
break;
}
string[] temp = encryptedString.ToString().Split((char)0xFF);
var save = new StringBuilder();
for (int i = 0; i < temp.Length; i++)
{
save.Append(DecryptPrivate(temp[i].AsSpan(), encoding));
if (i < temp.Length - 2)
{
save.Append((char)0xFF);
}
}
return save.ToString();
}
private static string DecryptPrivate(in ReadOnlySpan<char> str, Encoding encoding)
{
using var receiveData = new MemoryStream();
char[] table = { ' ', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\n' };
for (int count = 0; count < str.Length; count++)
{
if (str[count] <= 0x7A)
{
int len = str[count];
for (int i = 0; i < len; i++)
{
count++;
try
{
receiveData.WriteByte(unchecked((byte)(str[count] ^ 0xFF)));
}
catch
{
receiveData.WriteByte(255);
}
}
}
else
{
int len = str[count];
len &= 0x7F;
for (int i = 0; i < len; i++)
{
count++;
int highbyte;
try
{
highbyte = str[count];
}
catch
{
highbyte = 0;
}
highbyte &= 0xF0;
highbyte >>= 0x4;
int lowbyte;
try
{
lowbyte = str[count];
}
catch
{
lowbyte = 0;
}
lowbyte &= 0x0F;
if (highbyte != 0x0 && highbyte != 0xF)
{
receiveData.WriteByte(unchecked((byte)table[highbyte - 1]));
i++;
}
if (lowbyte != 0x0 && lowbyte != 0xF)
{
receiveData.WriteByte(unchecked((byte)table[lowbyte - 1]));
}
}
}
}
byte[] tmp = Encoding.Convert(encoding, Encoding.UTF8, receiveData.ToArray());
return Encoding.UTF8.GetString(tmp);
}
private static string DecryptUnauthed(in ReadOnlySpan<byte> str)
{
try
{
var encryptedStringBuilder = new StringBuilder();
for (int i = 1; i < str.Length; i++)
{
if (Convert.ToChar(str[i]) == 0xE)
{
return encryptedStringBuilder.ToString();
}
int firstbyte = Convert.ToInt32(str[i] - 0xF);
int secondbyte = firstbyte;
secondbyte &= 240;
firstbyte = Convert.ToInt32(firstbyte - secondbyte);
secondbyte >>= 4;
switch (secondbyte)
{
case 0:
case 1:
encryptedStringBuilder.Append(' ');
break;
case 2:
encryptedStringBuilder.Append('-');
break;
case 3:
encryptedStringBuilder.Append('.');
break;
default:
secondbyte += 0x2C;
encryptedStringBuilder.Append(Convert.ToChar(secondbyte));
break;
}
switch (firstbyte)
{
case 0:
encryptedStringBuilder.Append(' ');
break;
case 1:
encryptedStringBuilder.Append(' ');
break;
case 2:
encryptedStringBuilder.Append('-');
break;
case 3:
encryptedStringBuilder.Append('.');
break;
default:
firstbyte += 0x2C;
encryptedStringBuilder.Append(Convert.ToChar(firstbyte));
break;
}
}
return encryptedStringBuilder.ToString();
}
catch (OverflowException)
{
return string.Empty;
}
}
}
}