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 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
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(); }
En me baladant sur le NET j'ai trouvé qu'il fallait paddé la chaine à chiffrer en PHP (ligne 7 à ligne 11)
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); }
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
Partager