diff --git a/src/Syroot.Worms/OnlineWorms/Encodings.cs b/src/Syroot.Worms/OnlineWorms/Encodings.cs
new file mode 100644
index 0000000..80120e8
--- /dev/null
+++ b/src/Syroot.Worms/OnlineWorms/Encodings.cs
@@ -0,0 +1,22 @@
+using System.Text;
+
+namespace Syroot.Worms.OnlineWorms
+{
+ ///
+ /// Represents instances of common pages.
+ ///
+ internal static class Encodings
+ {
+ // ---- FIELDS -------------------------------------------------------------------------------------------------
+
+ internal static readonly Encoding Win949;
+
+ // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
+
+ static Encodings()
+ {
+ Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
+ Win949 = Encoding.GetEncoding(949);
+ }
+ }
+}
diff --git a/src/Syroot.Worms/OnlineWorms/LaunchConfig.cs b/src/Syroot.Worms/OnlineWorms/LaunchConfig.cs
index a65ddf3..ed83cd2 100644
--- a/src/Syroot.Worms/OnlineWorms/LaunchConfig.cs
+++ b/src/Syroot.Worms/OnlineWorms/LaunchConfig.cs
@@ -2,7 +2,6 @@
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Net;
-using System.Text;
using Syroot.BinaryData;
namespace Syroot.Worms.OnlineWorms
@@ -12,37 +11,13 @@ namespace Syroot.Worms.OnlineWorms
///
public class LaunchConfig
{
- // ---- CONSTANTS ----------------------------------------------------------------------------------------------
-
- private const int _bufferSize = 64 * sizeof(uint);
- private const string _passwordCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
// ---- FIELDS -------------------------------------------------------------------------------------------------
- private static readonly Encoding _win949Encoding;
private static readonly char[] _invalidUserNameChars = { '=', '&', ' ' };
- private static readonly byte[] _passwordDecryptShifts = new byte[]
- {
- 0x12, 0x1D, 0x07, 0x19, 0x0F, 0x1F, 0x16, 0x1B, 0x09, 0x1A, 0x03, 0x0D, 0x13, 0x0E, 0x14, 0x0B,
- 0x05, 0x02, 0x17, 0x10, 0x0A, 0x18, 0x1C, 0x11, 0x06, 0x1E, 0x00, 0x15, 0x0C, 0x08, 0x04, 0x01
- };
- private static readonly byte[] _passwordEncryptShifts = new byte[]
- {
- 0x1A, 0x1F, 0x11, 0x0A, 0x1E, 0x10, 0x18, 0x02, 0x1D, 0x08, 0x14, 0x0F, 0x1C, 0x0B, 0x0D, 0x04,
- 0x13, 0x17, 0x00, 0x0C, 0x0E, 0x1B, 0x06, 0x12, 0x15, 0x03, 0x09, 0x07, 0x16, 0x01, 0x19, 0x05
- };
private string _userName;
private string _passwordString;
- // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
-
- static LaunchConfig()
- {
- Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
- _win949Encoding = Encoding.GetEncoding(949);
- }
-
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
///
@@ -59,7 +34,7 @@ namespace Syroot.Worms.OnlineWorms
set
{
// 251 bytes is the space between "UID=" and the server IP, minus a terminating 0.
- if (_win949Encoding.GetBytes(value).Length > 251)
+ if (Encodings.Win949.GetBytes(value).Length > 251)
throw new ArgumentException("User name must not exceed 251 bytes.");
if (value.IndexOfAny(_invalidUserNameChars) != -1)
throw new ArgumentException("User name contains invalid characters.");
@@ -79,7 +54,7 @@ namespace Syroot.Worms.OnlineWorms
MemoryMappedFile mappedFile = MemoryMappedFile.CreateNew(mapName, 1266,
MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, HandleInheritability.Inheritable);
using (BinaryStream stream = new BinaryStream(mappedFile.CreateViewStream(),
- encoding: _win949Encoding, stringCoding: StringCoding.ZeroTerminated))
+ encoding: Encodings.Win949, stringCoding: StringCoding.ZeroTerminated))
{
stream.Write("Online Worms Config File");
@@ -91,7 +66,7 @@ namespace Syroot.Worms.OnlineWorms
stream.Position = 66;
stream.Write("UID=", StringCoding.Raw);
- stream.Write(_win949Encoding.GetBytes(UserName));
+ stream.Write(Encodings.Win949.GetBytes(UserName));
stream.Position = 322;
stream.Write(ServerEndPoint.Address.ToString());
@@ -118,7 +93,7 @@ namespace Syroot.Worms.OnlineWorms
if (_passwordString == null)
return null;
string[] parts = _passwordString.Split(';');
- return DecryptPassword(parts[1], UInt32.Parse(parts[2]));
+ return PasswordCrypto.Decrypt(parts[1], UInt32.Parse(parts[2]));
}
///
@@ -129,82 +104,7 @@ namespace Syroot.Worms.OnlineWorms
/// The key to encrypt with.
public void SetPassword(string password, uint key = 1000)
{
- _passwordString = $";{EncryptPassword(password, key)};{key}";
- }
-
- // ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
-
- private string EncryptPassword(string password, uint key)
- {
- using (MemoryStream inStream = new MemoryStream(new byte[_bufferSize]))
- {
- // Write input into a buffer. Required to loop over the input password end.
- inStream.WriteString(password, StringCoding.ZeroTerminated, Encoding.ASCII);
- inStream.Position = 0;
- using (MemoryStream outStream = new MemoryStream(new byte[_bufferSize]))
- {
- // Encrypt the contents character by character.
- while (inStream.Position < password.Length)
- {
- // Begin a new dword value at every 7th index.
- uint dword = CryptDword(inStream.ReadUInt32() + key, true);
- for (int j = 0; j < 7; j++)
- {
- outStream.WriteByte((byte)_passwordCharacters[(int)(dword % _passwordCharacters.Length)]);
- dword /= (uint)_passwordCharacters.Length;
- }
- }
- // Return the encrypted password as a zero-terminated ASCII string.
- outStream.Position = 0;
- return outStream.ReadString(StringCoding.ZeroTerminated, Encoding.ASCII);
- }
- }
- }
-
- private string DecryptPassword(string encryptedPassword, uint key)
- {
- using (MemoryStream inStream = new MemoryStream(new byte[_bufferSize]))
- {
- // Write input into a buffer. Required to loop over the input password end.
- inStream.WriteString(encryptedPassword, StringCoding.Raw, Encoding.ASCII);
- inStream.Position = 0;
- using (MemoryStream outStream = new MemoryStream(new byte[_bufferSize]))
- {
- // Decrypt the contents character by character.
- for (int i = 0; i < encryptedPassword.Length; i += 7)
- {
- uint dword = 0;
- for (int j = 0; j < 7; j++)
- {
- byte b = inStream.Read1Byte();
- uint op1 = (uint)Math.Pow(_passwordCharacters.Length, j);
- uint op2 = (uint)(b < '0' || b > '9' ? b - '7' : b - '0');
- dword += op1 * op2;
- }
- // Finalize a new dword value at every 7th index.
- outStream.WriteUInt32(CryptDword(dword, false) - key);
- }
- // Return the decrypted password as a zero-terminated ASCII string.
- outStream.Position = 0;
- return outStream.ReadString(StringCoding.ZeroTerminated, Encoding.ASCII);
- }
- }
- }
-
- private uint CryptDword(uint dword, bool encrypt)
- {
- // Shift least to most significant bits into the resulting value by an amount stored in a one-way array.
- byte[] shifts = encrypt ? _passwordEncryptShifts : _passwordDecryptShifts;
-
- uint result = 0;
- int shiftIndex = 0;
- while (dword > 0)
- {
- result += (dword & 1) << shifts[shiftIndex];
- shiftIndex++;
- dword >>= 1;
- }
- return result;
+ _passwordString = $";{PasswordCrypto.Encrypt(password, key)};{key}";
}
}
}
diff --git a/src/Syroot.Worms/OnlineWorms/PasswordCrypto.cs b/src/Syroot.Worms/OnlineWorms/PasswordCrypto.cs
new file mode 100644
index 0000000..046a219
--- /dev/null
+++ b/src/Syroot.Worms/OnlineWorms/PasswordCrypto.cs
@@ -0,0 +1,119 @@
+using System;
+using System.IO;
+using Syroot.BinaryData;
+
+namespace Syroot.Worms.OnlineWorms
+{
+ ///
+ /// Represents the two-way encryption and decryption used to obfuscate passwords passed to the client.
+ ///
+ public static class PasswordCrypto
+ {
+ // ---- CONSTANTS ----------------------------------------------------------------------------------------------
+
+ private const int _bufferSize = 64 * sizeof(uint);
+ private const string _encryptCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ // ---- FIELDS -------------------------------------------------------------------------------------------------
+
+ private static readonly byte[] _decryptShifts = new byte[]
+ {
+ 0x12, 0x1D, 0x07, 0x19, 0x0F, 0x1F, 0x16, 0x1B, 0x09, 0x1A, 0x03, 0x0D, 0x13, 0x0E, 0x14, 0x0B,
+ 0x05, 0x02, 0x17, 0x10, 0x0A, 0x18, 0x1C, 0x11, 0x06, 0x1E, 0x00, 0x15, 0x0C, 0x08, 0x04, 0x01
+ };
+ private static readonly byte[] _encryptShifts = new byte[]
+ {
+ 0x1A, 0x1F, 0x11, 0x0A, 0x1E, 0x10, 0x18, 0x02, 0x1D, 0x08, 0x14, 0x0F, 0x1C, 0x0B, 0x0D, 0x04,
+ 0x13, 0x17, 0x00, 0x0C, 0x0E, 0x1B, 0x06, 0x12, 0x15, 0x03, 0x09, 0x07, 0x16, 0x01, 0x19, 0x05
+ };
+
+ // ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
+
+ ///
+ /// Encrypts the given with the specified .
+ ///
+ /// The text (typically the password) to encrypt.
+ /// The value to apply to the transformation for modified outcome.
+ /// The encrypted text.
+ public static string Encrypt(string data, uint key)
+ {
+ using (MemoryStream inStream = new MemoryStream(new byte[_bufferSize]))
+ {
+ // Write input into a buffer. Required to loop over the input password end.
+ inStream.WriteString(data, StringCoding.ZeroTerminated, Encodings.Win949);
+ inStream.Position = 0;
+ using (MemoryStream outStream = new MemoryStream(new byte[_bufferSize]))
+ {
+ // Encrypt the contents character by character.
+ while (inStream.Position < data.Length)
+ {
+ // Begin a new dword value at every 7th index.
+ uint dword = TransformDword(inStream.ReadUInt32() + key, true);
+ for (int j = 0; j < 7; j++)
+ {
+ outStream.WriteByte((byte)_encryptCharacters[(int)(dword % _encryptCharacters.Length)]);
+ dword /= (uint)_encryptCharacters.Length;
+ }
+ }
+ // Return the encrypted password as a zero-terminated ASCII string.
+ outStream.Position = 0;
+ return outStream.ReadString(StringCoding.ZeroTerminated, Encodings.Win949);
+ }
+ }
+ }
+
+ ///
+ /// Decrypts the given with the specified .
+ ///
+ /// The text (typically the password) to decrypt.
+ /// The value to apply to the transformation for modified outcome.
+ /// The decrypted text.
+ public static string Decrypt(string data, uint key)
+ {
+ using (MemoryStream inStream = new MemoryStream(new byte[_bufferSize]))
+ {
+ // Write input into a buffer. Required to loop over the input password end.
+ inStream.WriteString(data, StringCoding.Raw, Encodings.Win949);
+ inStream.Position = 0;
+ using (MemoryStream outStream = new MemoryStream(new byte[_bufferSize]))
+ {
+ // Decrypt the contents character by character.
+ for (int i = 0; i < data.Length; i += 7)
+ {
+ uint dword = 0;
+ for (int j = 0; j < 7; j++)
+ {
+ byte b = inStream.Read1Byte();
+ uint op1 = (uint)Math.Pow(_encryptCharacters.Length, j);
+ uint op2 = (uint)(b < '0' || b > '9' ? b - '7' : b - '0');
+ dword += op1 * op2;
+ }
+ // Finalize a new dword value at every 7th index.
+ outStream.WriteUInt32(TransformDword(dword, false) - key);
+ }
+ // Return the decrypted password as a zero-terminated ASCII string.
+ outStream.Position = 0;
+ return outStream.ReadString(StringCoding.ZeroTerminated, Encodings.Win949);
+ }
+ }
+ }
+
+ // ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
+
+ private static uint TransformDword(uint dword, bool encrypt)
+ {
+ // Shift least to most significant bits into the resulting value by an amount stored in a one-way array.
+ byte[] shifts = encrypt ? _encryptShifts : _decryptShifts;
+
+ uint result = 0;
+ int shiftIndex = 0;
+ while (dword > 0)
+ {
+ result += (dword & 1) << shifts[shiftIndex];
+ shiftIndex++;
+ dword >>= 1;
+ }
+ return result;
+ }
+ }
+}