2017-10-15 80 views
0

我正在使用爲ASP.NET創建的存在數據庫的新PHP項目。我無法訪問ASP源代碼,所以我不知道密碼是如何散列的。在ASP中讀取ASP哈希密碼

我只需要一種方法來比較用戶從PHP登錄到數據庫中存儲的密碼,所以現有的用戶(和新的ASP腳本寄存器)不必爲這兩個腳本創建兩個密碼。

我知道他們已經被sha1/base64形式哈希了,但研究讓我意識到ASP.NET使用SqlMembershipProvider或者membershipprovider生成SALT,這是我的問題。

我需要一種方法來使PHP驗證ASP哈希密碼。

UPDATE 1:

這是來自數據庫的哈希密碼,用於測試用戶: AHmLnE/qf1Jb9ABf6uIHEomuQCN8e0Xt8Bpl8Ty4fzdicsnut6nK/Rv/ZlfJDOK9Pg==

密碼1234

更新2:

在嘗試@DeadSpace的答案後,我結束了這個(不工作):

<?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)); 
} 

輸出:

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

那麼這肯定是一個問題。除非你知道他們如何散列密碼,似乎你最好的選擇是重置所有的用戶密碼並重新散列它並保存在數據庫中 – zimorok

+0

這樣可以防止asp驗證新的散列密碼!我猜!。 – Dohab

+0

那裏你有它,除非你知道ASP方面的散列函數,從PHP做它是不可能的。 – zimorok

回答

1

好,

無的世界各地的工作PBKDF2功能對我來說,我總是得到錯誤的哈希值。 Rfc2898DeriveBytes結果在PHP是不同於ASP/C#。

所以我想,「兩點之間的最短距離是一條直線」。

我最終在c#中創建CLI接受參數,並使用PasswordHasher Class中的VerifyHashedPassword(string,string)函數,然後在php中使用exec("some.exe $thehash $password", $output)函數執行它,並獲取$輸出。

這種方式就像一個魅力,因爲我在windows中運行php。

1

ASP.Net是開源的,所以它的源代碼可以here


這是一個散列密碼的簡化版本。

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); 
} 

凡CompareBytes被定義爲:

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; 
} 

爲了實現在PHP Rfc2898DeriveBytes你可以看看若昂·桑托斯的article。儘管我沒有親自測試代碼。

<?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

我試過了,你能查看我上面更新的帖子嗎? – Dohab