IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

décryptage blowfish ECB dans un module Apache d'une chaine cryptée avec mcrypt PHP


Sujet :

C

  1. #1
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 073
    Points : 12 119
    Points
    12 119
    Par défaut décryptage blowfish ECB dans un module Apache d'une chaine cryptée avec mcrypt PHP
    Bonjour à tous,

    J'ai un problème qui résiste à mes investigations depuis un bout de temps.

    En version courte, je n'arrive pas à décrypter, dans du code C, une chaine de caractère qui a été cryptée avec blowfish en mode ECB de mcrypt du PHP ( http://php.net/manual/fr/function.mcrypt-ecb.php syntaxe libmcrypt 2.2.x).

    Quelqu'un peut-il me donner une référence/lien où je pourrais trouver du code C qui le décrypte correctement.

    En version longue, j'ai crée un module apache implémentant de l'URL Rewriting (RewriteMap/RewriteRule), qui récupère un bout d'URL qui est le résultat du chiffrement d'un chemin via un blowfish en mode ECB mcrypt du PHP ( http://php.net/manual/fr/function.mcrypt-ecb.php syntaxe libmcrypt 2.2.x) puis d'un encodage Base64.

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    $key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
     
    $key = md5($key);
     
    $str = 'mp3/02.MP5?start=50&end=65';
     
    $blocksize = mcrypt_get_block_size('blowfish', 'ecb');
    // get block size
    $pkcs = $blocksize - (strlen($str) % $blocksize);
    // get pkcs5 pad length
    $str.= str_repeat(chr($pkcs), $pkcs);
    // append pkcs5 padding to the data// encrypt and encode
     
    $cstr = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $str, MCRYPT_MODE_ECB);
     
    $source = base64_encode($cstr);



    La récupération de la chaine cryptée et le décodage Base64 ne pose pas problème.

    Mais en utilisant la même clé que celle dans le code PHP et OPENSSL/EVP (http://linux.die.net/man/3/evp_encryptinit ) ou bf_ecb_encrypt ( http://linux.die.net/man/3/bf_ecb_encrypt) le résultat du décodage n'est pas bon.

    J'ai testé l'encodage en C avec les fonctions sœurs de celles-ci et le résultat est différent de celui engendré par PHP.

    code du déchiffrage avec EVP:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    static char * decrypt (request_rec *req, char *encryptedData)
    {
        ap_log_error (APLOG_MARK, LOG_EMERG, 0, 0,"encryptedData : %s",encryptedData);
     
        int unbaselen=0;
        unsigned char* unbase = unbase64(encryptedData,strlen(encryptedData),&unbaselen);
     
        unsigned char key[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        unsigned char iv[] = "\0\0\0\0\0\0\0\0";
        unsigned char outbuf[1024];
    EVP_CIPHER_CTX ctx;
        EVP_CIPHER_CTX_init(&ctx);
     
        int decryptedLength = 0;
        int encryptedLength = strlen(encryptedData);
        int allocateSize = encryptedLength * sizeof(char);
        int lastDecryptLength = 0;
     
        char *decryptedData = (char *) malloc (allocateSize);
        memset(decryptedData, 0x00, allocateSize);
     
        int decryptResult = EVP_DecryptInit_ex(&ctx,EVP_bf_ecb(), NULL, key, iv);
     
        if (decryptResult == 1)
        {
            decryptResult = EVP_DecryptUpdate(&ctx, decryptedData,
                &decryptedLength, encryptedData, encryptedLength);
            // Cleanup
            if (decryptResult == 1)
            {
                // Stick the final data at the end of the last
                // decrypted data.
                EVP_DecryptFinal_ex(&ctx,
                    decryptedData + decryptedLength,
                    &lastDecryptLength);
     
                decryptedLength = decryptedLength + lastDecryptLength;
                decryptedData[decryptedLength - 1] = '\0';
                ap_log_error (APLOG_MARK, LOG_EMERG, 0, 0,"Decrypted size: %d\n", decryptedLength);
                ap_log_error (APLOG_MARK, LOG_EMERG, 0, 0,"Decrypted data: \n%s\n\n", decryptedData);
            }
            else
            {
                ap_log_error (APLOG_MARK, LOG_EMERG, 0, 0,"EVP_DeccryptUpdate failure.\n");
            }
        }
        else
        {
            ap_log_error (APLOG_MARK, LOG_EMERG, 0, 0,"EVP_DecryptInit_ex failure.\n");
        }
     
        ap_log_error (APLOG_MARK, LOG_EMERG, 0, 0,"decryptedData : %s",decryptedData);
     
        EVP_CIPHER_CTX_cleanup(&ctx);
        EVP_cleanup();
    }
    code qui chiffre de déchiffre avec "BF_ecb_encrypt" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #include <openssl/blowfish.h>
    static char * test_encr_decrypt2 (request_rec *req, char *data)
    {
      ap_log_error (APLOG_MARK, LOG_EMERG, 0, 0," decrypt2 data : %s",data);
      unsigned char keydata[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
      BF_KEY *key = calloc(1, sizeof(BF_KEY));
      unsigned char *out = calloc(10240, sizeof(char));
      memset(out,0,10240);
      unsigned char *out2 = calloc(10240, sizeof(char));
      memset(out2,0,10240);
     
      /* set up a test key */
      BF_set_key(key, 39, keydata );
     
      /* test out encryption */
      BF_ecb_encrypt(data, out, key, BF_ENCRYPT);
     
    ap_log_error (APLOG_MARK, LOG_EMERG, 0, 0," decrypt2 BF_ENCRYPT : %s",out);
     
      /* test out decryption */
      BF_ecb_encrypt(out, out2, key, BF_DECRYPT); 
     
    ap_log_error (APLOG_MARK, LOG_EMERG, 0, 0," decrypt2 BF_DECRYPT : %s",out2);
    }
    En me baladant sur le NET j'ai trouvé qu'il fallait paddé la chaine à chiffrer en PHP (ligne 7 à ligne 11)

    Et j'ai cru comprendre que PHP utilisait le paramètre comme clé de chiffrement mais que les primitives OPENSSL utilisaient le paramètre comme entré d'un appel à MD5 et qu'ils se servaient du hash comme clé, j'ai donc ajouté ce calcul du hash dans PHP (ligne 3)

    Mais, même avec ces modifications, l'encodage en C et via PHP donne des résultats différents.

    Quel détail m'a-t-il échappé ?

    Cordialement,

    Paul Bacelar

  2. #2
    Membre éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    Par défaut
    Salut,

    Juste pour te dire que j'ai pas la réponse, mais que tu vas galérer .

    Blowfish accepte plusieurs tailles de clés, donc déjà tu sais pas si les tailles utilisées dans les 2 cas sont identiques. Il faut que tu connaisses la longueur des clés utilisées par mcrypt (?) et openssl (128 bits), ainsi que la méthode pour "étendre" les clés. Si tu donnes une clés de 5 bytes a openssl ou mcrypt comment chacun l’étend a sa longueur de clé utilisée (padding, hash, ...)? Par example, Openssl génère un salt qui est fourni a la fonction de dérivation de clé, donc sans le connaitre ou supprimer sa generation, tes clés seront jamais identique:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # Cle differente avec meme donnee, salt differe
    $ openssl bf-ecb -e -in /tmp/test -a -k FFFFFFFFFFFFFF -p
    salt=FF5A589AEB519C40
    key=0296BDC00DE58D5CBA228BBD7E1AACC0
    U2FsdGVkX1//Wlia61GcQKpYfdGeCbOdOqhhfvcjtKmDAd4jGvkyJg==
    $ openssl bf-ecb -e -in /tmp/test -a -k FFFFFFFFFFFFFF -p
    salt=27F505BBBD10E836
    key=3876ECF7EE82C8E927CEB9AB49945C76
    U2FsdGVkX18n9QW7vRDoNrU9A/MHkNPWq201gbb76pS1lfU5iXITow==
    # Pas de sel, cles identiques
    $ openssl bf-ecb -e -in /tmp/test -a -nosalt -k FFFFFFFFFFFFFF -p
    key=1F145F86AD62A2F212516E91C3230A30
    TcQwPsKXOKCQzAxvaKMVSgqMQBjcJxwv
    $ openssl bf-ecb -e -in /tmp/test -a -nosalt -k FFFFFFFFFFFFFF -p
    key=1F145F86AD62A2F212516E91C3230A30
    TcQwPsKXOKCQzAxvaKMVSgqMQBjcJxwv
    Ton problème sera ensuite de trouver le padding utilise pour les donnees (PKCS#7 vs autres). Pour info le padding que tu utilises dan ton code est PKCS7 et non PKCS5. PKCS5 est un mechanisme d'extension de clé et non de padding.
    Ce problème est moins gênant, car tu devrais retrouver une partie de ton texte en clair si ta clé est bonne. La fin sera le padding utilise par mcrypt, ou une exception si openssl essaie de supprimer le padding.

    ECB ne nécessite pas d'IV, tu devrais pas en avoir besoin dans ton code.

    Enfin, est-ce que ECB est bien ce que tu veux? Si ton URL doit être secrète en transit, ECB n'est sans doute pas ce que tu veux. La structure des données est préserve car chaque bloc est chiffre indépendamment:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $ echo "AAAAAAAABBBBBBBBAAAAAAAACCCCCCCC" > /tmp/test
    $ openssl bf-ecb -e -in /tmp/test -nosalt -k FFFFFFFFFFFFFF | hexdump -C
    00000000  4d c4 30 3e c2 97 38 a0  90 cc 0c 6f 68 a3 15 4a  |M.0>..8....oh..J|
    00000010  4d c4 30 3e c2 97 38 a0  aa e9 62 49 f5 be 2f 18  |M.0>..8...bI../.|
    00000020  98 8a 46 0e fe 55 96 6c                           |..F..U.l|
    00000028
    Chaque bloc de 8 byte identique te donne le même résultat, indépendamment du bloc précédent. Si quelqu'un contrôle l'URL (ce qui est sans doute le cas) et peut voir sa version chiffrée, c'est assez facile de créer une table des fragments communs utilises et de deviner n'importe quelle URL chiffrée.

    Bon courage.

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 073
    Points : 12 119
    Points
    12 119
    Par défaut
    Merci pour ces précieuses informations.

Discussions similaires

  1. [OpenOffice] OpenOffice dans le Cloud : Apache fait une démo d’un premier prototype en HTML5
    Par Gordon Fowler dans le forum OpenOffice & LibreOffice
    Réponses: 9
    Dernier message: 19/11/2012, 16h19
  2. Réponses: 4
    Dernier message: 27/11/2009, 17h08
  3. [MySQL] Comment insérer 6 lignes en une fois dans une base mysql avec du PHP ?
    Par Alexandrebox dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 10/02/2008, 14h39
  4. [Système] Ecrire dans une Gestion dns avec du php
    Par mecmec dans le forum Langage
    Réponses: 3
    Dernier message: 31/05/2007, 11h31
  5. [TStringField] inserer dans un champs NOT NULL une chaine vi
    Par kase74 dans le forum Bases de données
    Réponses: 2
    Dernier message: 16/09/2005, 14h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo