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