2016-09-09 2 views
2

Короче говоря, у вас есть система членства, встроенная в .NET, которую мы переносим на WordPress, и вам необходимо реплицировать шифрование PBKDF2, чтобы пользователям не нужно было переустанавливать свои пароли.Преобразование C# PBKDF2 с использованием Rfc2898DeriveBytes в PHP

Использование ноу хэшируются пароль Я был в состоянии повторить это в .NET легко, с помощью следующего кода:

static void Main(string[] args) 
{ 
    var isValid = CheckPassword("#0zEZcD7uNmv", "5SyOX+Rbclzvvit3MEM2nBRaPVo2M7ZTs7n3znXTfyW4OhwTlJLvpcUlCryblgkQ"); 
} 

public static int PBKDF2IterCount = 10000; 
public static int PBKDF2SubkeyLength = 256/8; // 256 bits 
public static int SaltSize = 128/8; // 128 bits 

private static bool CheckPassword(string Password, string ExistingHashedPassword) 
{ 
    byte[] saltAndPassword = Convert.FromBase64String(ExistingHashedPassword); 
    byte[] salt = new byte[SaltSize]; 

    Array.Copy(saltAndPassword, 0, salt, 0, SaltSize); 

    Console.WriteLine("--Salt--"); 
    Console.WriteLine(Convert.ToBase64String(salt)); 

    string hashedPassword = HashPassword(Password, salt); 

    Console.WriteLine("--HashedPassword--"); 
    Console.WriteLine(hashedPassword); 

    return hashedPassword == ExistingHashedPassword; 
} 

private static string HashPassword(string Password, byte[] salt) 
{ 
    byte[] hash = new byte[PBKDF2SubkeyLength]; 
    using (var pbkdf2 = new Rfc2898DeriveBytes(Password, salt, PBKDF2IterCount)) 
    { 
    hash = pbkdf2.GetBytes(PBKDF2SubkeyLength); 
    } 

    byte[] hashBytes = new byte[PBKDF2SubkeyLength + SaltSize]; 
    Array.Copy(salt, 0, hashBytes, 0, SaltSize); 
    Array.Copy(hash, 0, hashBytes, SaltSize, PBKDF2SubkeyLength); 

    string hashedPassword = Convert.ToBase64String(hashBytes); 
    return hashedPassword; 
} 

приложение консоли будет производить следующее:

--Salt-- 
5SyOX+Rbclzvvit3MEM2nA== 
--HashedPassword-- 
5SyOX+Rbclzvvit3MEM2nBRaPVo2M7ZTs7n3znXTfyW4OhwTlJLvpcUlCryblgkQ 
--IsValid-- 
True 

Однако на стороне PHP я не могу получить одинаковые результаты. Мой код до сих пор ниже.

$mySalt = base64_decode('5SyOX+Rbclzvvit3MEM2nA=='); 
$dev = pbkdf2('sha1', '#0zEZcD7uNmv', $mySalt, 10000, 48, true); 
$key = substr($dev, 0, 32); //Keylength: 32 
$iv = substr($dev, 32, 16); // IV-length: 16 

echo 'PHP<br/>'; 
echo 'PASS: '.base64_encode($dev).'<br/>'; 
echo 'SALT: '.base64_encode($iv).'<br/><br/>'; 

echo '.NET<br/>'; 
echo 'PASS: 5SyOX+Rbclzvvit3MEM2nBRaPVo2M7ZTs7n3znXTfyW4OhwTlJLvpcUlCryblgkQ<br/>'; 
echo 'SALT: 5SyOX+Rbclzvvit3MEM2nA==<br/><br/>'; 

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

    $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 = 1; $j < $count; $j++) { 
      $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true)); 
     } 
     $output .= $xorsum; 
    } 
    return substr($output, 0, $key_length); 
} 

И результаты:

PHP 
PASS: FFo9WjYztlOzuffOddN/Jbg6HBOUku+lxSUKvJuWCRCsYe+1Tgbb8Ob4FtxumMal 
SALT: rGHvtU4G2/Dm+BbcbpjGpQ== 

.NET 
PASS: 5SyOX+Rbclzvvit3MEM2nBRaPVo2M7ZTs7n3znXTfyW4OhwTlJLvpcUlCryblgkQ 
SALT: 5SyOX+Rbclzvvit3MEM2nA== 

Любая помощь будет оценена.

+0

вы могли бы попробовать это, возможно, http://php.net/manual/en/function.hash-pbkdf2.php – ArtisticPhoenix

+0

@ArtisticPhoenix Спасибо, переключив его для пользовательского метода, получив тот же результат, что здорово, что он упростил код, но, к сожалению, по-прежнему имеет одинаковую проблему. – philba888

+0

Ну, одна проблема заключается в том, что вы печатаете '$ iv' и маркируете его СОЛЬ. Далее я задам вопрос о strlen. Но чем труднее это увидеть, тем лучше .NET превращает строковый пароль в байты через UTF-8. Если PHP использует UCS-2 или UTF-16, то ваши двоичные ключи HMAC не совпадают. – bartonjs

ответ

2

Закончил работу с использованием библиотек https://github.com/defuse/password-hashing с некоторыми незначительными изменениями, соответствующими формату хэшей. Я работал с базой данных, которую я импортирую.

Но моя главная проблема была в этих строках, где я пытаюсь получить ключ из хэша.

$dev = pbkdf2('sha1', '#0zEZcD7uNmv', $mySalt, 10000, 48, true); 
$key = substr($dev, 0, 32); //Keylength: 32 
$iv = substr($dev, 32, 16); // IV-length: 16 

Изменение его ниже, так что она создает хэш хэш, который является 32 бита в длину и присоединение к возвращающегося хэш соли фиксированной проблемы.

$dev = pbkdf2('sha1', '#0zEZcD7uNmv', $mySalt, 10000, 32, true); 
echo 'PASS: '.base64_encode($mySalt.$dev).'<br />'; 

С выходом ниже Теперь сопрягая .NET:

PASS: 5SyOX+Rbclzvvit3MEM2nBRaPVo2M7ZTs7n3znXTfyW4OhwTlJLvpcUlCryblgkQ