阅读ASP PHP中的散列密码

问题描述 投票:0回答:2

我的工作对用于ASP.NET创建的数据库存在一个新的PHP项目。我无法到达ASP源代码,所以我不知道密码是如何散列。

所有我需要的是一个从PHP比较用户登录到数据库中存储的密码,所以现有的用户(和新的ASP脚本寄存器)不必创建两个密码这两个脚本的方式。

我知道他们已经SHA1 / BASE64形式被散列,但研究使我认识到,ASP.NET使用两种或SqlMembershipProvider的生成盐,这是我的问题,我想的MembershipProvider。

我需要一种方法来使PHP验证的ASP哈希密码。

更新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
php asp.net hash sqlmembershipprovider
2个回答
2
投票

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,
      int DestionationOffset, 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');
    }
}

1
投票

好,

围绕由我世界工作PBKDF2功能没有,我总是得到错误的哈希值。 Rfc2898DeriveBytes结果在PHP比ASP / C#不同。

所以我想,“两点之间的最短距离是一条直线”。

我结束了在C创建CLI接受的论点,并从PasswordHasher类使用VerifyHashedPassword(字符串,字符串)函数#,然后用exec("some.exe $thehash $password", $output)功能PHP执行它,并抓住$输出。

这种方式就像一个魅力,因为我在Windows下运行PHP。

© www.soinside.com 2019 - 2024. All rights reserved.