C/C++ RSA Encryption des credentials

Discussion dans 'Questions / Réponses' créé par nathw96, 11 Mai 2018.

  1. nathw96

    nathw96 Membre

    Inscrit:
    14 Septembre 2013
    Messages:
    11
    J'aime reçus:
    0
    Salut à tous,
    Après de longues heures de travail, j'ai pas mal avancé sur mon projet de bot en c++. Seulement voilà, comme beaucoup, je me heurte à une difficulté, l'encryption des credentials. Tout se passe très bien pour ce qui est de la génération de ma chaine à encrypter ainsi que pour la récupération et la transformation de la clé envoyée par le serveur. Mon problème se pose au moment de générer les credentials étant donné que si je traite le même paquet plusieurs fois, j'obtiens des credentials différents (peut-être un problème de stupide mais je bloque vraiment).
    Voici ma classe, elle est très inspirée de celle de Munrek trouvée ici https://cadernis.fr/index.php?threads/résolu-serialisation-identificationmessage.1404/#post-16492 avec laquelle je rencontre le même problème

    rsa.cpp
    Code (C):
    #include "rsa.h"

    const std::string RSAD2::MPublicKey =
            "-----BEGIN PUBLIC KEY-----\nMIIBUzANBgkqhkiG9w0BAQEFAAOCAUAAMIIBOwKCATIAgucoka9J2PXcNdjcu6CuDmgteIMB+rih\n2UZJIuSoNT/0J/lEKL/W4UYbDA4U/6TDS0dkMhOpDsSCIDpO1gPG6+6JfhADRfIJItyHZflyXNUj\nWOBG4zuxc/L6wldgX24jKo+iCvlDTNUedE553lrfSU23Hwwzt3+doEfgkgAf0l4ZBez5Z/ldp9it\n2NH6/2/7spHm0Hsvt/YPrJ+EK8ly5fdLk9cvB4QIQel9SQ3JE8UQrxOAx2wrivc6P0gXp5Q6bHQo\nad1aUp81Ox77l5e8KBJXHzYhdeXaM91wnHTZNhuWmFS3snUHRCBpjDBCkZZ+CxPnKMtm2qJIi57R\nslALQVTykEZoAETKWpLBlSm92X/eXY2DdGf+a7vju9EigYbX0aXxQy2Ln2ZBWmUJyZE8B58CAwEA\nAQ==\n-----END PUBLIC KEY-----"
            ;

    RSAD2::RSAD2()
    {
        SSL_load_error_strings();
        ERR_load_BIO_strings();
        OpenSSL_add_all_algorithms();
    }

    QByteArray RSAD2::Encrypt(QByteArray helloConnectMessageKey, std::string accountName, std::string accountPassword, std::string salt) {
        QByteArray* byteList = new QByteArray();
        std::string s = AdaptSalt(salt);
        byteList->append(QString::fromStdString(s));
        char* empty = new char[32];
        for (int i =0; i<32; ++i){
            empty[i]='\0';
        }
        byteList->append(empty, 32);
        unsigned char nameLenght = accountName.length();
        byteList->append(QString(nameLenght));
        byteList->append(QString::fromStdString(accountName));
        byteList->append(QString::fromStdString(accountPassword));
        return LoginPKeyEncrypt(*byteList, transformLoginPublicKey(DecryptHelloConnectMessageKey(helloConnectMessageKey)));
    }


    bool RSAD2::CompareByteArrays(QByteArray firstArray, QByteArray secondArray) {
        if (firstArray.length() != secondArray.length()){
            return false;
        }

        for (int index = 0; index < firstArray.length(); ++index) {
            if (firstArray[index] != secondArray[index]) {
                return false;
            }
            ++index;
        }
        return true;
    }

    QByteArray RSAD2::DecryptHelloConnectMessageKey(QByteArray helloConnectMessageKey){
        std::vector<unsigned char> signature = std::vector<unsigned char>(
            helloConnectMessageKey.begin(), helloConnectMessageKey.end());

        char * DPKey =(char *) malloc(MPublicKey.size());
        strcpy(DPKey, MPublicKey.c_str());

        BIO *bp_dofus = BIO_new_mem_buf(DPKey, MPublicKey.size());
        RSA *my_rsa = PEM_read_bio_RSA_PUBKEY(bp_dofus, NULL, NULL, NULL);

        unsigned char *inputSignature, *outputSignature;
        inputSignature = (unsigned char*) malloc(5000);
        outputSignature = (unsigned char*) malloc(5000);
        inputSignature = reinterpret_cast<unsigned char*> (&signature[0]);

        int buflen = RSA_public_decrypt(signature.size(), inputSignature, outputSignature, my_rsa, RSA_PKCS1_PADDING);

        QByteArray outputSignatureArray((const char*)outputSignature, buflen);
        return outputSignatureArray;
    }


    std::string RSAD2::AdaptSalt(std::string salt) {
        if (salt.length() < 32) {
            while (salt.length() < 32) {
               salt += " ";
            }
        }
        return salt;
    }

    std::string RSAD2::transformLoginPublicKey(QByteArray key) {
        std::vector<unsigned char> lPKey = std::vector<unsigned char>(
            key.begin(), key.end());

        const std::string lPKeyStr(lPKey.begin(), lPKey.end());
        std::string lPKeyStrEnc = base64_encode(reinterpret_cast<const unsigned char*>(lPKeyStr.c_str()), lPKeyStr.length());

        std::stringstream lPKeyStrEncFor;
        for(int i=0; i!= lPKeyStrEnc.length(); i++){

            lPKeyStrEncFor << lPKeyStrEnc[i];
                if((i+1)%76==0){
                    if(i!=0) lPKeyStrEncFor << "\n";
                }
        }

        std::stringstream SlPKeyStrEnc;
        SlPKeyStrEnc << "-----BEGIN PUBLIC KEY-----" << "\n" << lPKeyStrEncFor.str() << "\n" << "-----END PUBLIC KEY-----";

        return SlPKeyStrEnc.str();
    }

    QByteArray RSAD2::LoginPKeyEncrypt(QByteArray credentialsArray, std::string LoginPublicKey) {
        std::vector<unsigned char> credentials = std::vector<unsigned char>(
            credentialsArray.begin(), credentialsArray.end());

        char * LoginPublicKeyByte = (char *) malloc(LoginPublicKey.size());
        strcpy(LoginPublicKeyByte, LoginPublicKey.c_str());

        BIO *bp_login = BIO_new_mem_buf(LoginPublicKeyByte, -1);
        RSA *my_second_rsa = PEM_read_bio_RSA_PUBKEY(bp_login, NULL, NULL, NULL);

        unsigned char *pinputCredentials, *poutputCredentials;
        pinputCredentials = (unsigned char*) malloc(5000);
        poutputCredentials = (unsigned char*) malloc(5000);
        pinputCredentials = reinterpret_cast<unsigned char*> (&credentials[0]);

        int buflen = RSA_public_encrypt(credentials.size(), pinputCredentials, poutputCredentials, my_second_rsa, RSA_PKCS1_PADDING);

        QByteArray outputCredentialsArray((const char*)poutputCredentials, buflen);
        return outputCredentialsArray;
    }
     
    Un très grand merci à ceux qui prendront le temps de m'aider :)
     
  2. Labo

    Labo Membre Actif

    Inscrit:
    16 Août 2013
    Messages:
    794
    J'aime reçus:
    57
    C'est normal d'avoir des credentials différents à chaque fois, vu qu'ils dependent de ce que le serveur envoie. C'est une mesure de sécurité pour éviter de pouvoir replay la trame.
     
  3. nathw96

    nathw96 Membre

    Inscrit:
    14 Septembre 2013
    Messages:
    11
    J'aime reçus:
    0
    Salut,
    Alors oui, tout cela je le sais sauf que pour mes tests, j’ai enregistré un paquet du serveur et je traite toujours le même donc (comme la clef générée par le client est également constante) je devrais avoir les mêmes credentials je pense :)
     
  4. astro05

    astro05 Membre

    Inscrit:
    3 Janvier 2017
    Messages:
    14
    J'aime reçus:
    8
    Il me semble que c'est également normal, j'avais fais la même chose pour mon code en Java (https://cadernis.fr/index.php?threads/classe-java-permettant-de-générer-le-credentials.2109/).
    Et j'avais également des credentials différents. Pourtant l'authentification fonctionne bien. ;)
    D'ailleurs, avec le même code et les même paramètres, a chaque relance, le credentials généré est différents.
     
    Dernière édition: 22 Mai 2018, à 15:02
  5. nathw96

    nathw96 Membre

    Inscrit:
    14 Septembre 2013
    Messages:
    11
    J'aime reçus:
    0
    Salut,
    Ceci n'est-il pas du à la pAesKey de ta classe (qui chez moi est remplacée par des 0)? Parce que sinon, il me semble que les credentials devraient être les mêmes pour le même pour le même message du serveur...
    En tout cas merci pour ta réponse, je vais me pencher un peu sur ton code pour voir si j'ai le même résultat avec :)
     
  6. astro05

    astro05 Membre

    Inscrit:
    3 Janvier 2017
    Messages:
    14
    J'aime reçus:
    8
    Il faudrait re-tester, ça fait un petit moment que je ne me suis pas penché sur ce code.
    Mais il me semble qu'avec les même paramètres de getCredentials (pAesKey y compris) tu auras un résultat différents après plusieurs relances.
    Du coup, cela ne servirait a rien de comparer le résultat de ton code avec le miens. ;)
    Le serveur te répond quoi quand tu lui envoie tes credentials ?
     
    Dernière édition: 22 Mai 2018, à 17:00
  7. nathw96

    nathw96 Membre

    Inscrit:
    14 Septembre 2013
    Messages:
    11
    J'aime reçus:
    0
    Un message de type 10 (LoginQueueStatus) ce qui me laisse penser qu’au moins l’en-tête est ok puis plus rien. D’ailleurs maintenant que j’y pense, j’avais comparé mon packet avec celui d’une version C# (qui lui arrive à se connecter) et tout à l’exception des Credentials m’avait paru correspondre

    D’ailleurs je ne comptais pas juste tester ton code mais bien le comprendre pour déceler ce qui cloche chez moi (même si mon code cpp est vraiment moche, j’ai quand même les compétences, promis ^^)
     
    Dernière édition: 22 Mai 2018, à 21:13
  8. astro05

    astro05 Membre

    Inscrit:
    3 Janvier 2017
    Messages:
    14
    J'aime reçus:
    8
    Tout a fais, le LoginQueueStatus ne veut pas dire que tu as réussis a t'authentifier. Il faut que tu reçoive un CredentialsAcknowledgementMessage pour être sur d'être bien authentifié.
    En général, quand on envoie un mauvais credentials au serveur, il répond par un message contenant ces données :
    Code (Text):
    51 01 02
    Le 2 voulant dire WRONG_CREDENTIAL.

    EDIT : Je t'invite a lire ces sujets qui m'ont beaucoup aidé a comprendre l'authentification et la génération du credentials :
    https://cadernis.fr/index.php?threads/procédure-dauthentification-et-rsa.1704/#post-19189
    https://cadernis.fr/index.php?threads/lecture-du-helloconnectmessage.2101/#post-22608

    Ces deux sujets devraient t'aider a générer un credentials manuellement dans un premier temps avec des commandes Linux.
    Après il existe une lib openssl en C++, et du coup ca ne devrait pas être compliqué de faire la même chose. ;)
     
    Dernière édition: 22 Mai 2018, à 23:54
  9. nathw96

    nathw96 Membre

    Inscrit:
    14 Septembre 2013
    Messages:
    11
    J'aime reçus:
    0
    Alors pour cette partie, j'ai un résultat différent:
    Pour ma part je reçois ce message (systématiquement)
    Code (Text):

    0029040000000000550a01022e10000000000000
     
    Qui une fois parsé m'indique que je suis à la position 0 sur 0 dans la file d'attente, pas de trace de message d'erreur (sa longueur étant de 4 et les deux nombres étant des shorts, je vois pas ou pourrait être l'info manquée)

    Pour cette partie, j'utilise déjà openSSL dans mon code ^^
    Mais merci du conseil, je vais me pencher là-dessus sérieusement quand j'aurai un peu plus de temps (et essayer de générer les credentials à la main me semble être judicieux) :)

    Encore une fois merci pour l'aide apportée, ça me fait vraiment plaisir
     

En naviguant sur ce site web, vous acceptez les Termes et Conditions d'utilisation. Tout le contenu que vous pourrez trouver sur ce site est soumis à la license Creative Commons.