M Core/NosSmooth.Cryptography/ClientLoginCryptography.cs => Core/NosSmooth.Cryptography/ClientLoginCryptography.cs +1 -1
@@ 20,7 20,7 @@ public class ClientLoginCryptography : ICryptography
{
try
{
- var output = new StringBuilder();
+ var output = new StringBuilder(bytes.Length);
foreach (var c in bytes)
{
output.Append(Convert.ToChar(c - 0xF));
M Core/NosSmooth.Cryptography/Extensions/StringExtensions.cs => Core/NosSmooth.Cryptography/Extensions/StringExtensions.cs +69 -0
@@ 23,6 23,75 @@ public static class StringExtensions
}
/// <summary>
+ /// Split a string without any allocation.
+ /// </summary>
+ /// <param name="str">The string to split.</param>
+ /// <param name="split">The char to split with.</param>
+ /// <returns>The split enumerator.</returns>
+ public static SplitEnumerator SplitAllocationless(this string str, char split)
+ {
+ return new SplitEnumerator(str.AsSpan(), split);
+ }
+
+ /// <summary>
+ /// An enumerator of a string split.
+ /// </summary>
+ public ref struct SplitEnumerator
+ {
+ private readonly char _split;
+ private ReadOnlySpan<char> _str;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SplitEnumerator"/> struct.
+ /// </summary>
+ /// <param name="str">The string.</param>
+ /// <param name="split">The split char.</param>
+ public SplitEnumerator(ReadOnlySpan<char> str, char split)
+ {
+ _str = str;
+ _split = split;
+ Current = default;
+ }
+
+ /// <summary>
+ /// Gets this enumerator.
+ /// </summary>
+ /// <returns>This.</returns>
+ public SplitEnumerator GetEnumerator()
+ => this;
+
+ /// <summary>
+ /// Move to next line.
+ /// </summary>
+ /// <returns>Whether move was successful.</returns>
+ public bool MoveNext()
+ {
+ var span = _str;
+ if (span.Length == 0)
+ {
+ return false;
+ }
+
+ var index = span.IndexOf(_split);
+ if (index == -1)
+ {
+ _str = ReadOnlySpan<char>.Empty;
+ Current = span;
+ return true;
+ }
+
+ Current = span.Slice(0, index);
+ _str = span.Slice(index + 1);
+ return true;
+ }
+
+ /// <summary>
+ /// Current line.
+ /// </summary>
+ public ReadOnlySpan<char> Current { get; private set; }
+ }
+
+ /// <summary>
/// An enumerator of a string lines.
/// </summary>
public ref struct LineSplitEnumerator
M Core/NosSmooth.Cryptography/ServerLoginCryptography.cs => Core/NosSmooth.Cryptography/ServerLoginCryptography.cs +5 -5
@@ 18,21 18,21 @@ public class ServerLoginCryptography : ICryptography
{
try
{
- string decryptedPacket = string.Empty;
+ StringBuilder decryptedPacket = new StringBuilder(str.Length);
foreach (byte character in str)
{
if (character > 14)
{
- decryptedPacket += Convert.ToChar((character - 15) ^ 195);
+ decryptedPacket.Append(Convert.ToChar((character - 15) ^ 195));
}
else
{
- decryptedPacket += Convert.ToChar((256 - (15 - character)) ^ 195);
+ decryptedPacket.Append(Convert.ToChar((256 - (15 - character)) ^ 195));
}
}
- return decryptedPacket;
+ return decryptedPacket.ToString();
}
catch
{
@@ 46,7 46,7 @@ public class ServerLoginCryptography : ICryptography
try
{
packet += " ";
- byte[] tmp = Encoding.Default.GetBytes(packet);
+ byte[] tmp = encoding.GetBytes(packet);
for (int i = 0; i < packet.Length; i++)
{
tmp[i] = Convert.ToByte(tmp[i] + 15);
M Core/NosSmooth.Cryptography/ServerWorldCryptography.cs => Core/NosSmooth.Cryptography/ServerWorldCryptography.cs +10 -36
@@ 5,6 5,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Text;
+using NosSmooth.Cryptography.Extensions;
namespace NosSmooth.Cryptography;
@@ 63,71 64,47 @@ public class ServerWorldCryptography : ICryptography
private static string DecryptAuthed(in ReadOnlySpan<byte> str, int encryptionKey, Encoding encoding)
{
- var encryptedString = new StringBuilder();
+ var encryptedString = new StringBuilder(str.Length);
int sessionKey = encryptionKey & 0xFF;
byte sessionNumber = unchecked((byte)(encryptionKey >> 6));
sessionNumber &= 0xFF;
sessionNumber &= 3;
+ byte firstbyte = unchecked((byte)(sessionKey + 0x40));
+
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();
+ var temp = encryptedString.ToString().SplitAllocationless((char)0xFF);
+ var save = new StringBuilder(encryptedString.Length);
- for (int i = 0; i < temp.Length; i++)
+ foreach (var packet in temp)
{
- save.Append(DecryptPrivate(temp[i].AsSpan(), encoding));
- if (i < temp.Length - 2)
- {
- save.Append((char)'\n');
- }
+ save.Append(DecryptPrivate(packet, encoding));
+ save.Append((char)'\n');
}
return save.ToString();
@@ 212,7 189,7 @@ public class ServerWorldCryptography : ICryptography
{
try
{
- var encryptedStringBuilder = new StringBuilder();
+ var encryptedStringBuilder = new StringBuilder(str.Length);
for (int i = 1; i < str.Length; i++)
{
if (Convert.ToChar(str[i]) == 0xE)
@@ 250,9 227,6 @@ public class ServerWorldCryptography : ICryptography
switch (firstbyte)
{
case 0:
- encryptedStringBuilder.Append(' ');
- break;
-
case 1:
encryptedStringBuilder.Append(' ');
break;