2009-06-30 13 views
12

J'ai un code qui va quelque chose comme:Dois-je découper la chaîne déchiffrée après mcrypt_decrypt?

$cipher_alg = MCRYPT_RIJNDAEL_128; 
$decrypted_string = mcrypt_decrypt($cipher_alg, $key, 
$encrypted_string , MCRYPT_MODE_CBC, trim(hex2bin(trim($hexiv)))); 

Je crains que dans le processus de décodage du mcrypt_decrypt introduira un espace; à titre gratuit ou des caractères nuls à l'arrière ou à l'avant de la $decrypted_string.

Alors, est-ce que je devrais le couper?

Note: J'aurais pu exécuter le code et le découvrir. Mais comme je ne peux jamais exécuter assez d'échantillons pour prouver (ou réfuter) mon point, je veux des réponses concrètes et théoriques, probablement basées sur le fonctionnement interne de l'algorithme mcrypt_decrypt. Une autre raison que je demande est que je crois que cela va aider les autres.

Note 2: En dépit de the answer below (now deleted and only 10K users can see it), il semble que le examples here utilisez-coupe pour obtenir la chaîne correcte déchiffré.

+0

Désolé pour la désinformation, Ngu, quand j'ai utilisé mcrypt, il semble que j'ai utilisé le mode CBC. –

+0

Err ... Je n'avais pas utilisé le mode CBC ... :-( –

Répondre

18

En fait, les deux mcrypt_encrypt() et mcrypt_decrypt() ainsi que les autres en- functons/déchiffrement (comme mcrypt_generic() ou mdecrypt_generic()) faire pad le paramètre $data à une longueur de n * <<blocksize>>. Le caractère de remplissage est le caractère NUL (\x0 ou \0) tandis que le <<blocksize>> dépend des modes de chiffrement et de chiffrement de bloc utilisés. Vous devriez jeter un oeil à Block cipher modes of operation et Padding (cryptography).

Voici la sortie de mcrypt_get_block_size() pour chacun des chiffrements et modes disponibles sur ma machine. Évidemment, la fonction ne tient pas compte du fait que les modes tels que CFB, OFB et CTR ne nécessitent aucune mesure spéciale pour gérer les messages dont les longueurs ne sont pas des multiples de la taille de bloc, puisqu'ils fonctionnent tous en XORing le texte en clair avec la sortie du bloc chiffrer (citation de Wikipedia). CBC qui est utilisé dans votre exemple exige toujours que le dernier bloc soit complété avant le cryptage.

cast-128 
    cbc: 8 bytes 
    cfb: 8 bytes 
    ctr: 8 bytes 
    ecb: 8 bytes 
    ncfb: 8 bytes 
    nofb: 8 bytes 
    ofb: 8 bytes 
    stream: not supported 
gost 
    cbc: 8 bytes 
    cfb: 8 bytes 
    ctr: 8 bytes 
    ecb: 8 bytes 
    ncfb: 8 bytes 
    nofb: 8 bytes 
    ofb: 8 bytes 
    stream: not supported 
rijndael-128 
    cbc: 16 bytes 
    cfb: 16 bytes 
    ctr: 16 bytes 
    ecb: 16 bytes 
    ncfb: 16 bytes 
    nofb: 16 bytes 
    ofb: 16 bytes 
    stream: not supported 
twofish 
    cbc: 16 bytes 
    cfb: 16 bytes 
    ctr: 16 bytes 
    ecb: 16 bytes 
    ncfb: 16 bytes 
    nofb: 16 bytes 
    ofb: 16 bytes 
    stream: not supported 
arcfour 
    cbc: not supported 
    cfb: not supported 
    ctr: not supported 
    ecb: not supported 
    ncfb: not supported 
    nofb: not supported 
    ofb: not supported 
    stream: 1 bytes 
cast-256 
    cbc: 16 bytes 
    cfb: 16 bytes 
    ctr: 16 bytes 
    ecb: 16 bytes 
    ncfb: 16 bytes 
    nofb: 16 bytes 
    ofb: 16 bytes 
    stream: not supported 
loki97 
    cbc: 16 bytes 
    cfb: 16 bytes 
    ctr: 16 bytes 
    ecb: 16 bytes 
    ncfb: 16 bytes 
    nofb: 16 bytes 
    ofb: 16 bytes 
    stream: not supported 
rijndael-192 
    cbc: 24 bytes 
    cfb: 24 bytes 
    ctr: 24 bytes 
    ecb: 24 bytes 
    ncfb: 24 bytes 
    nofb: 24 bytes 
    ofb: 24 bytes 
    stream: not supported 
saferplus 
    cbc: 16 bytes 
    cfb: 16 bytes 
    ctr: 16 bytes 
    ecb: 16 bytes 
    ncfb: 16 bytes 
    nofb: 16 bytes 
    ofb: 16 bytes 
    stream: not supported 
wake 
    cbc: not supported 
    cfb: not supported 
    ctr: not supported 
    ecb: not supported 
    ncfb: not supported 
    nofb: not supported 
    ofb: not supported 
    stream: 1 bytes 
blowfish-compat 
    cbc: 8 bytes 
    cfb: 8 bytes 
    ctr: 8 bytes 
    ecb: 8 bytes 
    ncfb: 8 bytes 
    nofb: 8 bytes 
    ofb: 8 bytes 
    stream: not supported 
des 
    cbc: 8 bytes 
    cfb: 8 bytes 
    ctr: 8 bytes 
    ecb: 8 bytes 
    ncfb: 8 bytes 
    nofb: 8 bytes 
    ofb: 8 bytes 
    stream: not supported 
rijndael-256 
    cbc: 32 bytes 
    cfb: 32 bytes 
    ctr: 32 bytes 
    ecb: 32 bytes 
    ncfb: 32 bytes 
    nofb: 32 bytes 
    ofb: 32 bytes 
    stream: not supported 
serpent 
    cbc: 16 bytes 
    cfb: 16 bytes 
    ctr: 16 bytes 
    ecb: 16 bytes 
    ncfb: 16 bytes 
    nofb: 16 bytes 
    ofb: 16 bytes 
    stream: not supported 
xtea 
    cbc: 8 bytes 
    cfb: 8 bytes 
    ctr: 8 bytes 
    ecb: 8 bytes 
    ncfb: 8 bytes 
    nofb: 8 bytes 
    ofb: 8 bytes 
    stream: not supported 
blowfish 
    cbc: 8 bytes 
    cfb: 8 bytes 
    ctr: 8 bytes 
    ecb: 8 bytes 
    ncfb: 8 bytes 
    nofb: 8 bytes 
    ofb: 8 bytes 
    stream: not supported 
enigma 
    cbc: not supported 
    cfb: not supported 
    ctr: not supported 
    ecb: not supported 
    ncfb: not supported 
    nofb: not supported 
    ofb: not supported 
    stream: 1 bytes 
rc2 
    cbc: 8 bytes 
    cfb: 8 bytes 
    ctr: 8 bytes 
    ecb: 8 bytes 
    ncfb: 8 bytes 
    nofb: 8 bytes 
    ofb: 8 bytes 
    stream: not supported 
tripledes 
    cbc: 8 bytes 
    cfb: 8 bytes 
    ctr: 8 bytes 
    ecb: 8 bytes 
    ncfb: 8 bytes 
    nofb: 8 bytes 
    ofb: 8 bytes 
    stream: not supported 

conséquent, vous devez rtrim() la sortie des fonctions de décryptage pour obtenir la chaîne d'origine si votre chiffre fonctionne sur des blocs de longueur fixe:

$output = rtrim($decrypted, "\0"); 
+1

C'est la bonne solution.Il est très important d'utiliser des guillemets doubles et non des guillemets simples autour de '\ 0'! – shadowhand

+2

Btw, il est très improbable que l'utilisation de 'trim (...," \ 0 ")' vous empêcherait de déchiffrer des données, même si vous utilisez une taille de bloc non-fixe, mais cela est * possible * lorsque vous cryptez des données binaires – shadowhand

+0

stud @StefanGehrig J'ai trouvé un million d'exemples en utilisant 'trim', mais il était en train de rogner les espaces qui comptaient vraiment dans mon contexte, et ça pourrait bien aller de nouveau avec le monde.Vous savez, après 2 heures de débogage, et vous cherchez une solution et tout cela – CWSpear

8

Dans ma mise en œuvre de TripleDES, je trouve la chaîne décryptée a été rembourré avec des caractères \ 5 ou \ 6. Ce ne sont pas les caractères \ 0 ou \ 4 attendus mentionnés ci-dessus ou dans les exemples PHP.net. Pour déterminer la valeur ASCII du caractère de remplissage, utilisez la fonction ord(). ord() fonctionne sur un seul caractère, utilisez str_split() pour diviser une chaîne ou accéder directement au caractère avec la notation array - $ string [5].

résultat trim final - trim($decrypt, "\0..\32");

résultat code final -

$key  = "encryption key"; 
    $encrypt = base64_decode($encrypt); 
    $iv_size = mcrypt_get_iv_size(MCRYPT_3DES, MCRYPT_MODE_ECB); 
    $iv   = mcrypt_create_iv($iv_size, MCRYPT_RAND); 
    $decrypt = mcrypt_decrypt(MCRYPT_3DES, $key, $encrypt, MCRYPT_MODE_ECB, $iv); 
    $final  = trim($decrypt, "\0..\32"); // removes potential null padding 
+0

Il semble que dans certains cas, le rembourrage est déterminé selon [RFC 5652] (https://tools.ietf.org/html/rfc5652#page-28), où le caractère utilisé pour pad indique en fait la quantité de rembourrage Je souhaite seulement savoir quelle combinaison algo/mode s (ou les versions sous-jacentes de la bibliothèque?) le feront en utilisant simplement "\ 0"! – grossvogel

4

je devais chiffrer/déchiffrer des données binaires. Malheureusement, le trim peut casser les données binaires et couper les bits légitimes qui correspondent à un caractère nul.

Afin d'assurer la taille des données binaires est le même avant et après le cryptage, Rocket Hazmat a affiché une excellente réponse ici: How can I decrypt binary data that ended with NUL characters in PHP?

Résumé:

// PKCS7 Padding 
$blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB); 
$pad = $blocksize - (strlen($data) % $blocksize); 
$data .= str_repeat(chr($pad), $pad); 

$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_ECB); 


/* Then somewhere else in your code */ 
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_ECB); 

// PKCS7 Padding 
$strPad = ord($decrypted[strlen($decrypted)-1]); 
$newData = substr($decrypted, 0, -$strPad); 

Je ne suis pas sûr de l'utilisation de la BCE par rapport à CBC ...

+0

Ceci s'applique à CBC de la même manière. –

0

Après 24 heures de recherche, enfin cela a fonctionné pour moi:

function removePadding($decryptedText){ 
    $strPad = ord($decryptedText[strlen($decryptedText)-1]); 
    $decryptedText= substr($decryptedText, 0, -$strPad); 
    return $decryptedText; 
} 
+0

Le code de réponse ne fonctionnera pas avec un remplissage nul auquel PHP mcrypt est par défaut et c'est ce que l'OP utilise. Pour le remplissage PKCS # 7/PKCS # 5, il faut vérifier que le remplissage est valide. Envisager l'utilisation de la mauvaise clé, $ strPad serait probablement erroné, potentiellement une valeur plus grande que la longueur des données. Mais ne renvoyez pas une erreur de remplissage incorrecte, qui tend à créer un oracle de remplissage, au lieu de ne rien faire. La plupart des bibliothèques prennent en charge le remplissage PKCS # 7 et ajoutent automatiquement un remplissage sur le chiffrement et suppriment le remplissage lors du décryptage - rien de plus n'est nécessaire. – zaph

Questions connexes