Java Authentification sur Dofus par socket.

A

Anonymous

Invité
#1
Bonjour tout le monde,

Je suis nouveau sur le forum.
Je viens la programmation d'un bot socket D2 grâce a des informations que j'ai trouvé sur ce site.

Je pense avoir compris le système de récupération des messages envoyé par le serveur dofus.
Pour le moment, mon code réceptionne le message 3 pour récupérer le public key et le salt UTF-8 afin d'envoyer le message 4.

Je voulais qu'on me confirme que mon code fonctionne bien, le voici :
Code:
import java.net.InetAddress;
import java.io.IOException;
import java.net.UnknownHostException;
import java.net.Socket;
import java.io.*;
import java.net.*;
/*
	COMPILATION:
		javac ./socket.java && java socket
*/

public class socket {

	private static String IP = "213.248.126.40";
	private static int port = 443;
	private static String salt;
	private static byte[] publicKeyInBytes;
	private static String privateKey =	"MIIBUzANBgkqhkiG9w0BAQEFAAOCAUAAMIIBOwKCATIAqpzRrvO3We7EMi9cWYqdfb3rbdinTay+" + 
																			"hxQ6t3dOiJLY4NITxyeIuy97yZYOojOlXS2SuJ4cCHjCeLCQO1FwOz+nynQWcBWecz2QdbHD2Kz7" + 
																			"mNLd2qtZyEDO76rd7LaDOxRvgs9DsH9sfnCuKLKbd725xTLc7wRfJzOH9v9rTTYVXssXe7JUpTx8" + 
																			"nV8yKnTiq3WpzBeZT4C3ZCR18GBBCh3NmSTbze9i2KipgZnOwBvhskVlweuqZ1KNIKsQgipBFuyw" + 
																			"w68RGNYaAKofMVVio4amrGpCT5MM852jpHsgJJfOUHu6md1CnvdwDPbo/PKQUI0RLb0ezE5gsPma" + 
																			"s39QBw+DiaibUkk1aCkBxTOFqpIbjfLM2/4qA6GPcWUJxP3vmGoeCTMBLNEiPfLqVm86QzUCAwEA" + 
																			"AQ==";

	public static void interpreteMessage(short idMessage, byte[] datas){
		switch (idMessage){
 			case 1:
    		System.out.println("	Message (Hexadecimal/integer): " + bytesToString(datas, "%X", true));
   		 	break;
			case 3:
				int sizeSalt = bytesToInt(0, 2, datas);
				byte[] saltInBytes = subTabBytes(2, sizeSalt, datas);
				try{
					salt = new String(saltInBytes, "UTF-8");
				}
				catch(UnsupportedEncodingException e){
					e.printStackTrace();
				}
				int sizePublicKey = bytesToInt(sizeSalt+2, 2, datas);
				publicKeyInBytes = subTabBytes(sizeSalt+4, sizePublicKey, datas);
				
	    		System.out.println("	Taille du salt: " + sizeSalt);
	    		System.out.println("	Salt (Hexadecimal/integer): " + bytesToString(saltInBytes, "%X", true));
	    		System.out.println("	Salt (UTF-8): " + salt);
	    		System.out.println("	Taille de la public key: " + sizePublicKey);
	    		System.out.println("	Public key (Hexadecimal/integer): " + bytesToString(publicKeyInBytes, "%X", true));
				break; 
		}
	}

	public static int bytesToInt(int posStart, int nbBytes, byte[] datas){
		int result = 0;
		for(int i=posStart; i < nbBytes + posStart; i++){
			if(i < nbBytes + posStart - 1)
				result += datas[i] * 256;
			else
				result += datas[i];
		}
		return result;
	}
	
	public static byte[] subTabBytes(int indexStart, int length, byte[] datas){
		byte[] result = new byte[length];
		for(int i=0; i < length; i++)
			result[i] = datas[i+indexStart];
		return result;		
	}

	public static void readPaquet(byte[] datas, int pos) {
		ByteArrayInputStream datasIS = new ByteArrayInputStream(datas);
		short idMessage = (short)((datas[pos] * 256 + datas[pos+1]) >> 2);
		short lengthType = (short)((datas[pos] * 256 + datas[pos+1]) & 3);
		int posLenght = pos+2, posDatasMessage = lengthType+posLenght;
		int length = bytesToInt(posLenght, lengthType, datas);
		byte[] subDatas = subTabBytes(posDatasMessage, length, datas);

		System.out.println("TYPE MESSAGE: " + idMessage);
		System.out.println("	lengthType: " + lengthType);
		System.out.println("	Taille du message: " + length);

		interpreteMessage(idMessage, subDatas);
		System.out.println("");

		if(length+posDatasMessage < datas.length)
			readPaquet(datas, length+posDatasMessage);
	}

	public static String bytesToString(byte[] bytes, String format, boolean spacer) {
		StringBuilder sb = new StringBuilder(bytes.length*2);
		for (byte b : bytes) {
			sb.append(String.format(format, b));
			if(spacer)
				sb.append(" ");
		}
		return sb.toString();
	}
	
	public static void main(String[] zero) {
		Socket socket;

		try {
		socket = new Socket(IP, port);
			while(!socket.isClosed())
			{
				InputStream data = socket.getInputStream();
				int available = data.available();
				byte[] b = new byte[available];
				int readCount = available;
			
				if(readCount > 0){
					data.read(b, 0, readCount);
					readPaquet(b, 0);
				}
			}
			socket.close();

		} catch (UnknownHostException e) {
			e.printStackTrace();
		}	catch (IOException e) {
			e.printStackTrace();
		}
	}
}
Voici les paquet que je réceptionne avec Wireshark :


Et voici ce que mon application Java récupère pour ce même paquet :


En théorie sa devrait être bon.
Maintenant j'ai :
  • Une public key récupéré dans le message 3Un Salt en UTF-8
  • Une autre clé fixé en dur dans mon code que j'ai trouvé sur ce forum

D’après ce que j'ai compris en lisant plusieurs messages sur ce forum, je devrais maintenant être capable d'envoyer le message 4 au serveur pour m'authentifier. Le problème est que je ne vois pas trop comment faire.

J'ai encore un peu de mal a lire les sources Dofus.

J'ai lus ce tuto : -débuter-dans-le-développement-socket-d2-(complet).162/]viewtopic.php?f=6&t=394
Mais il semble ne plus être d’actualité.

Merci d'avance pour votre aide,
 

4R7Y

Contributeur
Inscrit
6 Mars 2011
Messages
213
Reactions
0
#2
Bonsoir !
Envoyer un message au serveur n'est pas bien difficile, il te suffit de traduire (pour toi en java) le paquet (ou la fonction qui écrit le paquet) à envoyer.
Ensuite, tu écris les informations du paquet à l'aide de la classe traduite dans ton flux de sortie puis tu envoies, à l'aide de ton socket, vers le serveur d#fus !

Si ça peut t'aider, voilà une classe permettant d'envoyer un message réseau (un petit chat que j'avais programmé en java)

Code:
import java.io.PrintWriter;
import java.util.Scanner;


public class Emission implements Runnable {

	private PrintWriter out;
	private String message = null;
	private Scanner sc = null;
	
	public Emission(PrintWriter out) {
		this.out = out;
	}

	
    @Override
	public void run() {
		
		  sc = new Scanner(System.in);
		  
		  while(true){
			    System.out.println("Votre message :");
				message = sc.nextLine();
				out.println(message);
			    out.flush();
			  }
	}
}

Petite suggestion dans ton code, rajoute du threading ! Un thread qui écoute les messages venant du serveur et un thread qui sert à envoyer des messages vers le serveur
(En java tu peux le faire de 2 manières, je préfère utiliser l'implémentation de l'interface Runnable)

Bon courage !
 
A

Anonymous

Invité
#3
Oui, pour le moment mon code est loin d'être terminé, je sais qu'il faut que je rajoute des thread (entre autre pour pouvoir gérer plusieurs clients), pour l'instant, je cherche juste a faire une connexion au serveur.
Je sais envoyer des données avec un socket Java.
Mais c'est pour fabriquer le paquet 4 que je ne comprend pas trop.
J'ai toutes les données nécessaires il me semble.

Je pense avoir compris comment fabriquer le credential.

Je n'ai pas bien compris la partie cryptage des données.
En gros je reçois une public key par le serveur, mais cette public key est crypté et il me faut la private key static pour la lire ?
Puis il y a aussi une histoire de format X509.
 

Kyu

Staff
Membre du personnel
Inscrit
4 Octobre 2009
Messages
327
Reactions
8
#4
Sépare ton fichier en 3 classes.

La classe principale qui ne contiendra que la méthode main(String[] args).
Une classe ClientFactory qui contiendra tout ce qui concerne le réseau implémentant l'interface Runnable.
Dans le constructeur de cette classe tu instancie un Thread comme ceci :
Code:
Thread thread = new Thread(this)
thread.start();
Tu override la méthode run() de l'interface Runnable et tu t'en sert pour la réception des données.
Au lieu de tout mettre en static utilise le strategy pattern singleton si tu ne veux qu'une seule instance cliente et éviter des NPE.
Pour finir, fais une classe static Utils contenant les méthodes de formatage comme bytesToInt ou BytesToString.

Avec ça on devrait y voir plus clair.
 
A

Anonymous

Invité
#5
Je sais qu'il faut que je réorganise mes sources en suivant un modèle objet.
Je le ferrai. Ce code je l'ai vraiment écris très rapidement pour voir si j'avais compris le protocole D2.
Une fois que j'aurais bien tout compris de manière théorique, je ferrai peut être un projet plus complet et mieux organisé. ;)
Je voulais surtout qu'on m'aide pour envoyer le paquet 4.
Surtout sur la partie cryptage.
 

Kyu

Staff
Membre du personnel
Inscrit
4 Octobre 2009
Messages
327
Reactions
8
#6
Oui mais pour nous, c'est difficile de lire ce que tu écrit et ça ne donne pas envie d'aider.
Nous avons tous nos propre projets en tête, des contextes ancrè, et pour lire ton code, il faut se mettre dans le contexte également.
Et avec ce genre de formatage, cela nous prend plus de ressource mentale pour remettre ton code en ordre et le comprendre.
 
A

Anonymous

Invité
#7
Oublis le code.

Admettons que j'ai :
Le salt, la public key du serveur, et la private key static.
Je dois faire comment ensuite ?

Ce que j'ai compris, c'est qu'il faut que je décrypte la public key envoyé par le serveur avec la private key statique et que je me serve de la public key pour envoyer mon credential au serveur ?

En revanche j'ai pas bien compris pour le format X509.

Je réorganiserai mon code quand j'aurais le temps ;)
 

ToOnS

Membre Actif
Inscrit
8 Avril 2009
Messages
974
Reactions
0
#8
pour la reception n'oublis pas de gerer le cas ou un message arrive sur plusieurs paquets
 
A

Anonymous

Invité
#9
Oui je sais comment le gérer. :)

Pour décoder le format X509, il faut d'abord que je décrypte la public key avec la private key, et ensuite que je decode du format X509 la public key obtenus ?
Pour ensuite crypter mon credential ?
 
Haut Bas