Algo Besoin d'aide : génération des clés RSA

Inscrit
1 Mars 2020
Messages
18
Reactions
12
#1
Bonjour !
J'ai commencé un projet de bot dofus en C++, qui émule le comportment du client (cf. pas de MITM). J'ai donc décompilé DofusInvoker.swf et j'ai commencé à lire le code en prennant des notes.

J'ai fait un programme de test qui se connecte au serveur de d'authentification de dofus. Cependant, j'ai un problème lorsque que j'essaie de récupérer la clé publique.
Voici comment je procède pour l'instant :

1. Je récupère verifyKey (qui se trouve dans BinaryData)
Cette clé est en Base64, donc je la convertit en données hexadécimales.
Ensuite, d'après ce que je comprend du code (voir-ci dessous), cette clé contient d'abord une version 'simplifiée' de OID.RSA_ENCRYPTION, puis d'autres données.
Dans ces autres données, on retrouve alors des entiers N et E qui sont ensuite stockés dans une RsaKey, nommée readKey.

Code:
      public static function readRSAPublicKey(str:String) : RSAKey
      {
         var arr:Array = null;
         var der:ByteArray = extractBinary(RSA_PUBLIC_KEY_HEADER,RSA_PUBLIC_KEY_FOOTER,str);
         if(der == null)
         {
            return null;
         }
         var obj:* = DER.parse(der);
         if(obj is Array)
         {
            arr = obj as Array;
            if(arr[0][0].toString() != OID.RSA_ENCRYPTION)
            {
               return null;
            }
            arr[1].position = 0;
            obj = DER.parse(arr[1]);
            if(obj is Array)
            {
               arr = obj as Array;
               return new RSAKey(arr[0],arr[1]);
            }
            return null;
         }
         return null;
      }
2. Je me connecte au serveur et j'attend un HelloConnectMessage (HCMsg) . Lors de sa réception, je récupère la clé publique du serveur et le salt.
Je lis la clé en Big indan, càd que si le paquet envoyé est 10 0B, la clé lue sera 0x100B.

3. Enfin, j'émule le code de readKey.verify() (qui appelle readKey._decrypt()) :

Code:
 private function _decrypt(op:Function, src:ByteArray, dst:ByteArray, length:uint, pad:Function, padType:int) : void
      {
         var block:BigInteger = null;
         var chunk:BigInteger = null;
         var b:ByteArray = null;
         if(pad == null)
         {
            pad = this.pkcs1unpad;
         }
         if(src.position >= src.length)
         {
            src.position = 0;
         }
         var bl:uint = this.getBlockSize();
         var end:int = src.position + length;
         while(src.position < end)
         {
            block = new BigInteger(src,bl,true);
            chunk = op(block);
            b = pad(chunk,bl,padType);
            if(b == null)
            {
               throw new TLSError("Decrypt error - padding function returned null!",TLSError.decode_error);
            }
            dst.writeBytes(b);
         }
      }
Arguments :
op : fonction qui équivaut à : op(x) = x^E % N (N et E on été déterminés plus tôt grace à la verifyKey)
src : clé publique envoyée par le serveur, transformée en ByteArray
dst : ByteArray de la clé décrypté (?)
length : longueur de src
pad : initialisée à null
padType ; initialisée à 1

Etant donné que N est bien plus quand que la clé, on aura toujours qu'un seul passage de boucle.
Je récupère donc la clé du HCMsg et j'applique chunk = (block^E)%N (sachant que block contient la clé en entier).

Le problème survient à l'instruction suivante : b = pad(...)

On a pad = pkcs1unpad :

Code:
      private function pkcs1unpad(src:BigInteger, n:uint, type:uint = 2) : ByteArray
      {
         var b:ByteArray = src.toByteArray();
         var out:ByteArray = new ByteArray();
         b.position = 0;
         var i:int = 0;
         while(i < b.length && b[i] == 0)
         {
            i++;
         }
         if(b.length - i != n - 1 || b[i] != type)
         {
            trace("PKCS#1 unpad: i=" + i + ", expected b[i]==" + type + ", got b[i]=" + b[i].toString(16));
            return null;
         }
         i++;
         while(b[i] != 0)
         {
            if(++i >= b.length)
            {
               trace("PKCS#1 unpad: i=" + i + ", b[i-1]!=0 (=" + b[i - 1].toString(16) + ")");
               return null;
            }
         }
         while(++i < b.length)
         {
            out.writeByte(b[i]);
         }
         out.position = 0;
         return out;
      }
Cette fonction demande que le block calculé soit d'une certaine forme : Commence par des 0; suivis du type; suivi de valeurs jusqu'à un 0; suivi des valeurs importantes pour la clé.

Cependant, je n'obtiens pas de résultat qui correspond, et j'ai du mal à comprendre comment on pourrait avoir un résultat aussi spécifique qui provient d'un calcul de puissance et de modulo.

J'ai essayé de ne pas tenir compte de cette instruction, mais lors de la génération du IdentificationMessage, on a besoin de cipherRsa, qui appelle lui aussi la fonction readRSAPublicKey (cf. premier code) sur la clé calculée. Sauf que cette fois ci, les données n'ont pas de sens et le programme ne retrouve pas les données qu'il faut.

Je doit soit me tromper quelque part, soit avoir mal compris le fonctionnement du programme, et c'est pour cela que je vous demande votre aide.
Si vous avez d'autres solutions, je suis preneur. Par contre, je n'ai pas envie de passer à un bot MITM. Je sais que cela pourrait me faciliter la tâche mais ce n'est pas ce que je recherche.

Si je ne suis pas clair à un moment ou si vous avez besoin de plus de contexte pour m'aider, n'hésitez surtout pas à demander.

Merci d'avance !
 
Inscrit
1 Mars 2020
Messages
18
Reactions
12
#2
J'ai trouvé la solution à mon pb : je récuperais mal la clé contenue dans le HelloConnectMsg. Ca ne pouvait pas marcher !
 
Haut Bas