From 3e36db92abd6019147109141c637d27b462f9fbd Mon Sep 17 00:00:00 2001 From: Rutherther Date: Mon, 13 Feb 2023 18:18:49 +0100 Subject: [PATCH] feat(crypto): make less allocations where possible --- .../ClientLoginCryptography.cs | 2 +- .../Extensions/StringExtensions.cs | 69 +++++++++++++++++++ .../ServerLoginCryptography.cs | 10 +-- .../ServerWorldCryptography.cs | 46 +++---------- 4 files changed, 85 insertions(+), 42 deletions(-) diff --git a/Core/NosSmooth.Cryptography/ClientLoginCryptography.cs b/Core/NosSmooth.Cryptography/ClientLoginCryptography.cs index 60892f364cfb318c34d9b2423fd676ea678073b9..023f96347833df98ca701a60904f2518d6e46156 100644 --- a/Core/NosSmooth.Cryptography/ClientLoginCryptography.cs +++ b/Core/NosSmooth.Cryptography/ClientLoginCryptography.cs @@ -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)); diff --git a/Core/NosSmooth.Cryptography/Extensions/StringExtensions.cs b/Core/NosSmooth.Cryptography/Extensions/StringExtensions.cs index fae6431fe883c0346853dae6ad0810150eee5f18..2a0c4a71917de937c271fef27d2fd3da4afa438e 100644 --- a/Core/NosSmooth.Cryptography/Extensions/StringExtensions.cs +++ b/Core/NosSmooth.Cryptography/Extensions/StringExtensions.cs @@ -22,6 +22,75 @@ public static class StringExtensions return new LineSplitEnumerator(str.AsSpan()); } + /// + /// Split a string without any allocation. + /// + /// The string to split. + /// The char to split with. + /// The split enumerator. + public static SplitEnumerator SplitAllocationless(this string str, char split) + { + return new SplitEnumerator(str.AsSpan(), split); + } + + /// + /// An enumerator of a string split. + /// + public ref struct SplitEnumerator + { + private readonly char _split; + private ReadOnlySpan _str; + + /// + /// Initializes a new instance of the struct. + /// + /// The string. + /// The split char. + public SplitEnumerator(ReadOnlySpan str, char split) + { + _str = str; + _split = split; + Current = default; + } + + /// + /// Gets this enumerator. + /// + /// This. + public SplitEnumerator GetEnumerator() + => this; + + /// + /// Move to next line. + /// + /// Whether move was successful. + public bool MoveNext() + { + var span = _str; + if (span.Length == 0) + { + return false; + } + + var index = span.IndexOf(_split); + if (index == -1) + { + _str = ReadOnlySpan.Empty; + Current = span; + return true; + } + + Current = span.Slice(0, index); + _str = span.Slice(index + 1); + return true; + } + + /// + /// Current line. + /// + public ReadOnlySpan Current { get; private set; } + } + /// /// An enumerator of a string lines. /// diff --git a/Core/NosSmooth.Cryptography/ServerLoginCryptography.cs b/Core/NosSmooth.Cryptography/ServerLoginCryptography.cs index 7c42a3b15370c0144c225a7c8f57ac61d976b3c5..d79aecf8c1ccd7d921c942747de87f9c3856e024 100644 --- a/Core/NosSmooth.Cryptography/ServerLoginCryptography.cs +++ b/Core/NosSmooth.Cryptography/ServerLoginCryptography.cs @@ -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); diff --git a/Core/NosSmooth.Cryptography/ServerWorldCryptography.cs b/Core/NosSmooth.Cryptography/ServerWorldCryptography.cs index b0409249a2c41b7b65a41263004efde6933966cc..a965e337041f7d419710c1fc6838aefd17e479bf 100644 --- a/Core/NosSmooth.Cryptography/ServerWorldCryptography.cs +++ b/Core/NosSmooth.Cryptography/ServerWorldCryptography.cs @@ -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 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;