mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-04-09 19:00:06 +03:00
Move password encryption algorithm to separate class.
This commit is contained in:
parent
9720cf1a02
commit
220597e65e
22
src/Syroot.Worms/OnlineWorms/Encodings.cs
Normal file
22
src/Syroot.Worms/OnlineWorms/Encodings.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Syroot.Worms.OnlineWorms
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents instances of common <see cref="Encoding"/> pages.
|
||||||
|
/// </summary>
|
||||||
|
internal static class Encodings
|
||||||
|
{
|
||||||
|
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
internal static readonly Encoding Win949;
|
||||||
|
|
||||||
|
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static Encodings()
|
||||||
|
{
|
||||||
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
|
Win949 = Encoding.GetEncoding(949);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.MemoryMappedFiles;
|
using System.IO.MemoryMappedFiles;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
|
||||||
using Syroot.BinaryData;
|
using Syroot.BinaryData;
|
||||||
|
|
||||||
namespace Syroot.Worms.OnlineWorms
|
namespace Syroot.Worms.OnlineWorms
|
||||||
@ -12,37 +11,13 @@ namespace Syroot.Worms.OnlineWorms
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class LaunchConfig
|
public class LaunchConfig
|
||||||
{
|
{
|
||||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
private const int _bufferSize = 64 * sizeof(uint);
|
|
||||||
private const string _passwordCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
||||||
|
|
||||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
private static readonly Encoding _win949Encoding;
|
|
||||||
private static readonly char[] _invalidUserNameChars = { '=', '&', ' ' };
|
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 _userName;
|
||||||
private string _passwordString;
|
private string _passwordString;
|
||||||
|
|
||||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static LaunchConfig()
|
|
||||||
{
|
|
||||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
|
||||||
_win949Encoding = Encoding.GetEncoding(949);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -59,7 +34,7 @@ namespace Syroot.Worms.OnlineWorms
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
// 251 bytes is the space between "UID=" and the server IP, minus a terminating 0.
|
// 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.");
|
throw new ArgumentException("User name must not exceed 251 bytes.");
|
||||||
if (value.IndexOfAny(_invalidUserNameChars) != -1)
|
if (value.IndexOfAny(_invalidUserNameChars) != -1)
|
||||||
throw new ArgumentException("User name contains invalid characters.");
|
throw new ArgumentException("User name contains invalid characters.");
|
||||||
@ -79,7 +54,7 @@ namespace Syroot.Worms.OnlineWorms
|
|||||||
MemoryMappedFile mappedFile = MemoryMappedFile.CreateNew(mapName, 1266,
|
MemoryMappedFile mappedFile = MemoryMappedFile.CreateNew(mapName, 1266,
|
||||||
MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, HandleInheritability.Inheritable);
|
MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, HandleInheritability.Inheritable);
|
||||||
using (BinaryStream stream = new BinaryStream(mappedFile.CreateViewStream(),
|
using (BinaryStream stream = new BinaryStream(mappedFile.CreateViewStream(),
|
||||||
encoding: _win949Encoding, stringCoding: StringCoding.ZeroTerminated))
|
encoding: Encodings.Win949, stringCoding: StringCoding.ZeroTerminated))
|
||||||
{
|
{
|
||||||
stream.Write("Online Worms Config File");
|
stream.Write("Online Worms Config File");
|
||||||
|
|
||||||
@ -91,7 +66,7 @@ namespace Syroot.Worms.OnlineWorms
|
|||||||
|
|
||||||
stream.Position = 66;
|
stream.Position = 66;
|
||||||
stream.Write("UID=", StringCoding.Raw);
|
stream.Write("UID=", StringCoding.Raw);
|
||||||
stream.Write(_win949Encoding.GetBytes(UserName));
|
stream.Write(Encodings.Win949.GetBytes(UserName));
|
||||||
|
|
||||||
stream.Position = 322;
|
stream.Position = 322;
|
||||||
stream.Write(ServerEndPoint.Address.ToString());
|
stream.Write(ServerEndPoint.Address.ToString());
|
||||||
@ -118,7 +93,7 @@ namespace Syroot.Worms.OnlineWorms
|
|||||||
if (_passwordString == null)
|
if (_passwordString == null)
|
||||||
return null;
|
return null;
|
||||||
string[] parts = _passwordString.Split(';');
|
string[] parts = _passwordString.Split(';');
|
||||||
return DecryptPassword(parts[1], UInt32.Parse(parts[2]));
|
return PasswordCrypto.Decrypt(parts[1], UInt32.Parse(parts[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -129,82 +104,7 @@ namespace Syroot.Worms.OnlineWorms
|
|||||||
/// <param name="key">The key to encrypt with.</param>
|
/// <param name="key">The key to encrypt with.</param>
|
||||||
public void SetPassword(string password, uint key = 1000)
|
public void SetPassword(string password, uint key = 1000)
|
||||||
{
|
{
|
||||||
_passwordString = $";{EncryptPassword(password, key)};{key}";
|
_passwordString = $";{PasswordCrypto.Encrypt(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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
119
src/Syroot.Worms/OnlineWorms/PasswordCrypto.cs
Normal file
119
src/Syroot.Worms/OnlineWorms/PasswordCrypto.cs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Syroot.BinaryData;
|
||||||
|
|
||||||
|
namespace Syroot.Worms.OnlineWorms
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the two-way encryption and decryption used to obfuscate passwords passed to the client.
|
||||||
|
/// </summary>
|
||||||
|
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) ---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encrypts the given <paramref name="data"/> with the specified <paramref name="key"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The text (typically the password) to encrypt.</param>
|
||||||
|
/// <param name="key">The value to apply to the transformation for modified outcome.</param>
|
||||||
|
/// <returns>The encrypted text.</returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrypts the given <paramref name="data"/> with the specified <paramref name="key"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The text (typically the password) to decrypt.</param>
|
||||||
|
/// <param name="key">The value to apply to the transformation for modified outcome.</param>
|
||||||
|
/// <returns>The decrypted text.</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user