2017-10-15 6 views
0

Je travaille sur un nouveau projet PHP qui utilise une base de données existante créée pour ASP.NET. Je ne peux pas atteindre le code source ASP, donc je ne sais pas comment les mots de passe sont hachés. Tout ce dont j'ai besoin est un moyen de comparer les connexions des utilisateurs de PHP au mot de passe stocké dans la base de données, donc les utilisateurs déjà existants (et les nouveaux registres de scripts ASP) n'ont pas besoin de deux mots de passe.Lire le mot de passe hashé ASP en PHP

Je sais qu'ils ont été hachés sous forme sha1/base64, mais les recherches m'ont amené à réaliser qu'ASP.NET utilise SqlMembershipProvider ou membershipprovider qui génère SALT, ce qui est mon problème, je suppose.

J'ai besoin d'un moyen de faire PHP vérifier le mot de passe hashé ASP.

UPDATE 1:

Ceci est un mot de passe haché à partir de la base de données, pour un utilisateur d'essai: AHmLnE/qf1Jb9ABf6uIHEomuQCN8e0Xt8Bpl8Ty4fzdicsnut6nK/Rv/ZlfJDOK9Pg==

le mot de passe est 1234

UPDATE 2:

après avoir essayé la réponse @DeadSpace ci-dessous, je me suis retrouvé avec ceci (ne fonctionne pas):

<?php 
include "SymmetricEncryption.php"; 

$hash = "AHmLnE/qf1Jb9ABf6uIHEomuQCN8e0Xt8Bpl8Ty4fzdicsnut6nK/Rv/ZlfJDOK9Pg=="; // password is : 1234 

echo "Hashed: ". $hash . "<br>"; 
$salt = substr(base64_decode($hash), 0, 16); 
//$salt = substr(base64_decode($hash), 1, 16); // C# = Buffer.BlockCopy(src, 1, dst, 0, 16); 

$hasher = new SymmetricEncryption(); 

echo "Class test: ". base64_encode($salt. $hasher->encrypt('', '1234', $salt)) . "<br>"; 



/***** another faield approach *****/ 


//Not working either :(

echo "another way: ". base64_encode($salt. pbkdf2('SHA1', '1234', $salt, 1000, 32, true)) ; 

function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false) 
{ 
    $algorithm = strtolower($algorithm); 
    if(!in_array($algorithm, hash_algos(), true)) 
     trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR); 
    if($count <= 0 || $key_length <= 0) 
     trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR); 

    if (function_exists("hash_pbkdf2")) { 
     // The output length is in NIBBLES (4-bits) if $raw_output is false! 
     if (!$raw_output) { 
      $key_length = $key_length * 2; 
     } 

     return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output); 
    } 

    $hash_length = strlen(hash($algorithm, "", true)); 
    $block_count = ceil($key_length/$hash_length); 

    $output = ""; 
    for($i = 1; $i <= $block_count; $i++) { 
     // $i encoded as 4 bytes, big endian. 
     $last = $salt . pack("N", $i); 
     // first iteration 
     $last = $xorsum = hash_hmac($algorithm, $last, $password, true); 
     // perform the other $count - 1 iterations 
     for ($j = 0; $j < $count; $j++) { 
      $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true)); 
     } 
     $output .= $xorsum; 
    } 

    if($raw_output) 
     return substr($output, 0, $key_length); 
    else 
     return bin2hex(substr($output, 0, $key_length)); 
} 

Sortie:

Hashed: AHmLnE/qf1Jb9ABf6uIHEomuQCN8e0Xt8Bpl8Ty4fzdicsnut6nK/Rv/ZlfJDOK9Pg== 
Class test: AHmLnE/qf1Jb9ABf6uIHEmNZcjhUOFMxREhQOGQrTFMzb0VpL2c9PQ== 
another way: AHmLnE/qf1Jb9ABf6uIHEp3Abm4NCdtNaQ/iXjxShfVK9SDoAiCfYJ7Pbz0UUnDZ 
+0

bien que ce soit certainement un problème.sauf si vous savez comment ils ont haché le mot de passe, il semble que votre meilleur pari est de réinitialiser tous les mots de passe de votre utilisateur et de le recréer et de sauvegarder sur le DB – zimorok

+0

De cette façon, ASP empêchera de vérifier les nouveaux mots de passe hachés! j'imagine!. – Dohab

+0

là vous l'avez, à moins que vous connaissiez la fonction hachée sur le côté ASP, le faire à partir de PHP ne sera pas possible. – zimorok

Répondre

1

Eh bien,

Aucune des fonctions PBKDF2 autour du monde travaillent pour moi, je reçois toujours le hachage mal. Les résultats de Rfc2898DeriveBytes dans php sont différents de ceux d'asp/C#. J'ai donc pensé: "La plus courte distance entre deux points est une ligne droite". J'ai fini par créer CLI dans C# qui accepte les arguments et utilise la fonction VerifyHashedPassword (string, string) de la classe PasswordHasher, puis l'exécute en php avec la fonction exec("some.exe $thehash $password", $output), et récupère la sortie $.

Cette façon de faire fonctionne comme un charme, puisque j'utilise PHP dans Windows.

1

ASP.Net est open source, de sorte que son code source est disponible here.


Voici une version simplifiée du hachage des mots de passe.

public static bool VerifyHashedPassword(string hashedPassword, string password) 
{ 
    byte[] buffer4; 
    if (hashedPassword == null) 
    { 
     return false; 
    } 
    if (password == null) 
    { 
     throw new ArgumentNullException("password"); 
    } 
    byte[] src = Convert.FromBase64String(hashedPassword); 
    if ((src.Length != 49) || (src[0] != 0)) 
    { 
     return false; 
    } 
    byte[] dst = new byte[16]; 
    /*Buffer.BlockCopy(Array src, int sourceOffset, Array destination, 
     intDestionationOffset, int count)*/ 
    Buffer.BlockCopy(src, 1, dst, 0, 16); 
    byte[] buffer3 = new byte[32]; 
    Buffer.BlockCopy(src, 17, buffer3, 0, 32); 

    using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, dst, 1000)) 
    { 
     buffer4 = bytes.GetBytes(32); 
    } 
    return CompareBytes(buffer3, buffer4); 
} 

Où CompareBytes est défini comme:

static bool CompareBytes(byte[] a1, byte[] a2) 
{ 
    if (a1.Length != a2.Length) 
     return false; 

    for (int i = 0; i < a1.Length; i++) 
     if (a1[i] != a2[i]) 
      return false; 

    return true; 
} 

Pour la mise en œuvre Rfc2898DeriveBytes en PHP, vous pouvez regarder dans João Santos de article. Je n'ai pas personnellement testé le code.

<?php 
class SymmetricEncryption { 
    private $cipher; 
    public function __construct($cipher = 'aes-256-cbc') { 
     $this->cipher = $cipher; 
    } 
    private function getKeySize() { 
     if (preg_match("/([0-9]+)/i", $this->cipher, $matches)) { 
      return $matches[1] >> 3; 
     } 
     return 0; 
    } 
    private function derived($password, $salt) { 
     $AESKeyLength = $this->getKeySize(); 
     $AESIVLength = openssl_cipher_iv_length($this->cipher); 
     $pbkdf2 = hash_pbkdf2("SHA1", $password, mb_convert_encoding($salt, 'UTF-16LE'), 1000, $AESKeyLength + $AESIVLength, TRUE); 
     $key = substr($pbkdf2, 0, $AESKeyLength); 
     $iv = substr($pbkdf2, $AESKeyLength, $AESIVLength); 
     $derived = new stdClass(); 
     $derived->key = $key; 
     $derived->iv = $iv; 
     return $derived; 
    } 
    function encrypt($message, $password, $salt) { 
     $derived = $this->derived($password, $salt); 
     $enc = openssl_encrypt(mb_convert_encoding($message, 'UTF-16', 'UTF-8'), $this->cipher, $derived->key, NULL, $derived->iv); 
     return $enc; 
    } 
    function decrypt($message, $password, $salt) { 
     $derived = $this->derived($password, $salt); 
     $dec = openssl_decrypt($message, $this->cipher, $derived->key, NULL, $derived->iv); 
     return mb_convert_encoding($dec, 'UTF-8', 'UTF-16'); 
    } 
} 
+0

J'ai essayé, pourriez-vous vérifier ma mise à jour post ci-dessus? – Dohab