Re: Problème de reception de packets
Nouvelle journée , nouveau probleme :/
J'ai bien réussi à contacter le serveur, récuperer le HelloGameMessage , et je suis à l'étape ou je renvoie l'IdentificationMessage (le fameux).
Cependant , même si mon id et mot de passe sont bons, je recoit le packet d'id : 20 , IdentificationFailedMessage .
Voila comment je me connecte au serveur dans mon code :
Cliquez pour révéler
Cliquez pour masquer
using BotFramework.Core.Auth;
using BotFramework.IO;
using BotFramework.Packet.Types.connection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BotFramework.Packet.Messages.connection
{
class HelloConnectMessage : IServerPacket
{
private bool _isInitialized = false;
public String _salt = "";
public List<byte> key = new List<byte>();
public ServerPacketEnum PacketType
{
get
{
return ServerPacketEnum.HelloConnectMessage;
}
}
public void Deserialize(Reader reader)
{
byte currentKey = 0;
this._salt = reader.ReadUTF();
int keycount = reader.ReadVarInt();
Console.WriteLine("Taille clé : " + keycount);
for(int i = 0; i < keycount; i++)
{
currentKey = reader.ReadByte();
this.key.Add(currentKey);
}
Console.WriteLine("salt : " + _salt + " , clé : " + this.key.ToString());
// [Envoi] IdentificationMessage
IdentificationMessage identificationMessage = new IdentificationMessage();
byte[] credentials = RSAManager.Encrypt(this.key , this._salt, "login","password");
byte[] unsigned = (byte[])(Array)credentials;
VersionExtended versionExtended = new VersionExtended();
versionExtended.initVersionExtended(2, 27, 5, 93304, 1, 0, 1, 1);
identificationMessage.Init(true, false, false, versionExtended, "fr", unsigned, 0, 0);
Writer writer = new Writer();
Program.socketInstance.Send(identificationMessage);
}
}
}
En fait c'est très sale mais je procède à l'envoi de mon packet à la fin de la déserialization du packet HelloConnectMessage .
Voici aussi le code de mon IdentificationMessage :
Cliquez pour révéler
Cliquez pour masquer
using BotFramework.IO;
using BotFramework.Packet.Types.connection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BotFramework.Packet.Messages.connection
{
public class IdentificationMessage : IClientPacket
{
public const int Id = 4;
public bool m_autoconnect;
public bool m_useCertificate;
public bool m_useLoginToken;
public VersionExtended m_version;
public string m_lang;
public byte[] m_credentials;
public short m_serverId;
public double m_sessionOptionalSalt;
public ClientPacketEnum PacketType
{
get
{
return ClientPacketEnum.IdentificationMessage;
}
}
public void Init(bool autoconnect, bool useCertificate, bool useLoginToken, VersionExtended version, string lang, byte[] credentials, short serverId, double sessionOptionalSalt)
{
m_autoconnect = autoconnect;
m_useCertificate = useCertificate;
m_useLoginToken = useLoginToken;
m_version = version;
m_lang = lang;
m_credentials = credentials;
m_serverId = serverId;
m_sessionOptionalSalt = sessionOptionalSalt;
}
public void Serialize(Writer writer)
{
byte flag = new byte();
BooleanByteWrapper.SetFlag(0, flag, m_autoconnect);
BooleanByteWrapper.SetFlag(1, flag, m_useCertificate);
BooleanByteWrapper.SetFlag(2, flag, m_useLoginToken);
writer.WriteByte(flag);
m_version.Serialize(writer);
writer.WriteString(m_lang);
writer.WriteVarInt(m_credentials.Length);
int credentialsIndex;
for (credentialsIndex = 0; (credentialsIndex < m_credentials.Length); credentialsIndex ++)
{
writer.WriteByte(m_credentials[credentialsIndex]);
}
writer.WriteShort(m_serverId);
writer.WriteDouble(m_sessionOptionalSalt);
}
}
Ainsi que le code de VersionExtended:
Cliquez pour révéler
Cliquez pour masquer
public class VersionExtended : Version , IClientPacket
{
public uint install = 0;
public uint technology = 0;
public VersionExtended initVersionExtended(uint major = 0, uint minor = 0, uint release = 0, uint revision = 0, uint patch = 0, uint buildType =0, uint install = 0, uint technology = 0)
{
base.initVersion(major, minor, release, revision, patch, buildType);
this.install = install;
this.technology = technology;
return (this);
}
new public ClientPacketEnum PacketType
{
get
{
return ClientPacketEnum.VersionExtended;
}
}
new public void Deserialize(Reader reader)
{
base.Deserialize(reader);
this.install = reader.ReadByte();
if (this.install < 0)
{
throw (new Exception((("Forbidden value (" + this.install) + ") on element of VersionExtended.install.")));
};
this.technology = reader.ReadByte();
if (this.technology < 0)
{
throw (new Exception((("Forbidden value (" + this.technology) + ") on element of VersionExtended.technology.")));
};
}
new public void Serialize(Writer writer)
{
base.Serialize(writer);
writer.WriteByte((byte)this.install);
writer.WriteByte((byte)this.technology);
}
}
En sniffant ma propre application j'ai essayé d'analyser le packet envoyé (si ca peut aider):
Cliquez pour révéler
Cliquez pour masquer
00 12 02 00 00 02 1B 05 00 01 6C 78 01 00 01 01
00 02 66 72 A6 02 2D EB FB 8C DE 2C F7 21 82 30
EC 15 51 BC D1 5E 79 7D 33 80 9E 6F 82 84 FC 39
87 07 4B 78 2B 1B 27 53 F2 94 0D 5C AA B9 51 B3
C8 FE 1A 1A F8 54 08 A7 09 DE 45 0B B4 99 8F 08
89 9C EE 66 A5 72 26 35 89 97 71 E2 87 3D F8 7F
89 60 83 B8 23 35 88 FE 38 5D 13 B0 CE 09 03 EE
03 32 77 00 E0 C2 FB 2C B5 64 1F 61 89 44 7D 99
D7 F4 2A 7C 1D DB C2 4E D6 6A 95 79 41 D7 E7 43
76 98 7F 8D 81 5F 1B 3A B9 4D 50 FF 26 D7 EC E1
3A C6 71 CE CB 72 2C 03 D4 57 13 87 5E AA FB D1
7D 53 FE A5 B1 27 79 CB 01 B2 C1 7F A2 40 CA 67
E4 73 75 22 DF 8C E7 25 89 3E D1 54 9B F7 CB CA
04 8C 72 2E 97 AA BF 31 9A 0A AE 57 FB C9 7A 7F
B1 84 5A C1 4B 9C 7D 3E 8B 9A 2C 2D 3D 6F E8 D9
C6 55 C3 E9 5E A0 13 60 CE 85 85 CE 9B 69 FD F8
24 A5 26 CC E0 36 F5 C3 17 23 2F 00 3A 80 48 BC
45 6C 3A CD 6F 80 C2 96 EF 51 A8 40 78 7C 88 10 8E
64 69 AE 47 67 BB 52 04 A4 4A 45 2B 0D 27 4D 50
D1 64 06 9B 12 53 C6 B1 BA 94 0E 00 00 00 00
Enfin j'ai utilisé la classe RSA Manager provenant de Moonlight-Angel sans modifier aucune chose, sauf peut être la clé publique
(que j'ai trouvé en cherchant mon problème sur ce même forum)
Cliquez pour révéler
Cliquez pour masquer
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Numerics;
namespace BotFramework.Core.Auth
{
public static class RSAManager
{
private const string _RSAPublicKey =
"MIIBUzANBgkqhkiG9w0BAQEFAAOCAUAAMIIBOwKCATIAq8EYkkGCUg86Bf2CHaM1z1Q2ahQgVXkx49I0igwTVCIqG86jsgNb22na1DThZ+IP7DfyBszIecVSP8nwbYPbx6Z7dwq4pnMVx/lx5lyMZUO1n/HGEkw1S06AlfXzSg58ci5DL9RJ9ZIa1oMDKtrZiNYA5C3L+7NSCVp/2H/yypWkDjzkFan65+TNRExo/2O3+MytJtQ/BXVkbYD58+iiZegddNTNGvz8WlPz2cZvPQt4x1TN+KOgJRKZH5imNAxCtRg6l1OLVxfwwUjKFgM4uAsto8vJv5DUFZQMO1Sh9gMpmzeMwXIF4fDD4O1TNiVmu3ABybt2Y4EdaQhs/ponC0SNcWbrY0stYbX+Wpk9/Hcxmo3zoduf1ZAdGM01E1g3IjQMd0gOP4v1KQtBjoHim2MCAwEAAQ==";
public static byte[] Encrypt(List<byte> key, string Salt, string UserName, string Password)
{
RSACryptoServiceProvider RSA = GetRSA();
string NewSalt = GetSalt(Salt);
byte[] DecryptedData = PublicDecrypt(key.ToArray(), RSA.ExportParameters(false));
RSACryptoServiceProvider newRSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = newRSA.ExportParameters(false);
RSAKeyInfo.Modulus = DecryptedData;
newRSA.ImportParameters(RSAKeyInfo);
List<byte> Credentials = new List<byte>();
Credentials.AddRange(Encoding.UTF8.GetBytes(NewSalt));
Credentials.Add((byte)UserName.Length);
Credentials.AddRange(Encoding.UTF8.GetBytes(UserName));
Credentials.AddRange(Encoding.UTF8.GetBytes(Password));
byte[] Encrypted = newRSA.Encrypt(Credentials.ToArray(), false);
System.Diagnostics.Debug.WriteLine("Encrypted = " + Convert.ToBase64String(Encrypted) + " - Taille : " + Encrypted.Length + "\r\n");
return Encrypted;
}
private static RSACryptoServiceProvider GetRSA()
{
RSACryptoServiceProvider RSA = DecodeX509PublicKey(Convert.FromBase64String(_RSAPublicKey));
return RSA;
}
private static string GetSalt(string Salt)
{
if (Salt.Length < 32)
{
while (Salt.Length < 32)
{
Salt += " ";
}
}
return Salt;
}
private static byte[] PublicDecrypt(byte[] Data, RSAParameters RSAParameters)
{
BigInteger Exponent = new BigInteger(RSAParameters.Exponent.Reverse().Concat(new byte[] { 0 }).ToArray());
BigInteger Modulus = new BigInteger(RSAParameters.Modulus.Reverse().Concat(new byte[] { 0 }).ToArray());
BigInteger PreparedData = new BigInteger(Data // Our data block
.Reverse() // BigInteger has another byte order
.Concat(new byte[] { 0 }) // Append 0 so we are always handling positive numbers
.ToArray() // Constructor wants an array
);
byte[] DecryptedData = BigInteger.ModPow(PreparedData, Exponent, Modulus) // The RSA operation itself
.ToByteArray() // Make bytes from BigInteger
.Reverse() // Back to "normal" byte order
.ToArray(); // Return as byte array
return DecryptedData.SkipWhile(x => x != 0).Skip(1).ToArray(); // PKCS#1 padding
}
private static RSACryptoServiceProvider DecodeX509PublicKey(byte[] X509Key)
{
// Encoded OID sequence for PKCS#1 RSAEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
byte[] Seq = new byte[15];
// --------- Set up stream to read the ASN.1 encoded SubjectPublicKeyInfo blob ------
MemoryStream MemoryStream = new MemoryStream(X509Key);
BinaryReader BinaryReader = new BinaryReader(MemoryStream); // Wrap Memory Stream with BinaryReader for easy reading
byte Byte = 0;
ushort TwoBytes = 0;
try
{
TwoBytes = BinaryReader.ReadUInt16();
if (TwoBytes == 0x8130) // Data read as little endian order (actual data order for Sequence is 30 81)
BinaryReader.ReadByte(); // Advance 1 byte
else if (TwoBytes == 0x8230)
BinaryReader.ReadInt16(); // Advance 2 bytes
else
return null;
Seq = BinaryReader.ReadBytes(15); // Read the Sequence OID
if (!CompareByteArrays(Seq, SeqOID)) // Make sure Sequence for OID is correct
return null;
TwoBytes = BinaryReader.ReadUInt16();
if (TwoBytes == 0x8103) // Data read as little endian order (actual data order for Bit String is 03 81)
BinaryReader.ReadByte(); // Advance 1 byte
else if (TwoBytes == 0x8203)
BinaryReader.ReadInt16(); // Advance 2 bytes
else
return null;
Byte = BinaryReader.ReadByte();
if (Byte != 0x00) // Expect null byte next
return null;
TwoBytes = BinaryReader.ReadUInt16();
if (TwoBytes == 0x8130) // Data read as little endian order (actual data order for Sequence is 30 81)
BinaryReader.ReadByte(); // Advance 1 byte
else if (TwoBytes == 0x8230)
BinaryReader.ReadInt16(); // Advance 2 bytes
else
return null;
TwoBytes = BinaryReader.ReadUInt16();
byte LowByte = 0x00;
byte HighByte = 0x00;
if (TwoBytes == 0x8102) // Data read as little endian order (actual data order for Integer is 02 81)
{
LowByte = BinaryReader.ReadByte(); // Read next bytes which is bytes in modulus
}
else if (TwoBytes == 0x8202)
{
HighByte = BinaryReader.ReadByte(); // Advance 2 bytes
LowByte = BinaryReader.ReadByte();
}
else
{
return null;
}
byte[] ModInt = { LowByte, HighByte, 0x00, 0x00 }; // Reverse byte order since ASN.1 key uses big endian order
int ModSize = BitConverter.ToInt32(ModInt, 0);
byte FirstByte = BinaryReader.ReadByte();
BinaryReader.BaseStream.Seek(-1, SeekOrigin.Current);
if (FirstByte == 0x00) // If first byte (highest order) of modulus is zero, don't include it
{
BinaryReader.ReadByte(); // Skip this null byte
ModSize -= 1; // Reduce modulus buffer size by 1
}
byte[] Modulus = BinaryReader.ReadBytes(ModSize); // Read the modulus bytes
if (BinaryReader.ReadByte() != 0x02) // Expect an Integer for the exponent data
return null;
int ExponentBytes = (int)BinaryReader.ReadByte(); // Should only need one byte for actual exponent data (for all useful values)
byte[] Exponent = BinaryReader.ReadBytes(ExponentBytes);
// ------- Create RSACryptoServiceProvider instance and initialize with public key -----
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = new RSAParameters()
{
Modulus = Modulus,
Exponent = Exponent
};
RSA.ImportParameters(RSAKeyInfo);
return RSA;
}
catch (Exception)
{
return null;
}
finally
{
BinaryReader.Close();
}
}
private static bool CompareByteArrays(byte[] FirstArray, byte[] SecondArray)
{
if (FirstArray.Length != SecondArray.Length)
return false;
int i = 0;
foreach (byte Byte in FirstArray)
{
if (Byte != SecondArray)
return false;
i++;
}
return true;
}
}
}
Du coup j'suis pas sur de tout de où peut venir mon problème...
J'ai plusieurs idées , et j'aimerai savoir votre avis , soit:
- Ma clé publique n'est plus bonne dans la classe RSA Manager (je ne suis pas trop sur, j'ai vu qu'on pouvait verifier en décompilant le client, et que dans le dossier
binaries il etait codé en "PEM" (je n'ai pas encore bien compris tout cela)
- Je n'envoie pas le packet au bon endroit (je ne sais pas si le fait que je l'envoie à la fin de la déserialisation de HelloConnectMessage influe, j'essaye de changer actuellement)
- Mon Writer n'est pas bon ( ou je n'utilise pas les bonnes méthodes d'ecriture dans la Serialization ) , cependant j'ai essayé de reproduire le plus fidèlement possible le code .as des packets.
- J'ai merdé autre part dans mon ecriture de packet.
Aussi , pour information , la clé que j'obtiens dans HelloConnectMessage est composée de 305 bytes (il me semble que c'est bon) , d'autant que la valeur de _salt que j'obtiens me "semble" correcte .
Voila je m'en remets à vous pour n'importe quelle piste :'(
Merci d'avance à ceux qui auront eu le courage de me lire et de me répondre :)