2015-01-01 83 views
2

只需要在Codeigniter中使用PHPass來散列密碼。我從phpass網站下載zip文件,提取內容,並將PasswordHash.php文件複製到我的庫文件夾中。在Codeigniter中使用PHPass散列密碼

然後我裝在我的控制器庫,並試圖以哈希密碼,但它給了以下錯誤

Missing argument 1 for PasswordHash::PasswordHash(), called in ... 
Missing argument 2 for PasswordHash::PasswordHash(), called in ... 
Undefined variable: iteration_count_log2 ... 
Undefined variable: portable_hashes ... 

請在下面檢查我的控制器代碼,並幫助我找到的錯誤:

$this->load->library('PasswordHash'); 
$password = $this->input->post('password'); 
$hash = $this->passwordhash->HashPassword($password); 
+0

請提供更多信息 –

+0

請註明您需要哪種類型的信息的。我提供了我使用的代碼和框架以及我得到的錯誤。 – EducateYourself

+0

爲什麼不使用md5()函數將密碼轉換爲散列,而不是像這樣? –

回答

8

以下是我如何做到的。首先創建它作爲幫手。

<?php (defined('BASEPATH')) OR exit('No direct script access allowed'); 
# 
# Portable PHP password hashing framework. 
# 
# Version 0.3/genuine. 
# 
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in 
# the public domain. Revised in subsequent years, still public domain. 
# 
# There's absolutely no warranty. 
# 
# The homepage URL for this framework is: 
# 
# http://www.openwall.com/phpass/ 
# 
# Please be sure to update the Version line if you edit this file in any way. 
# It is suggested that you leave the main version number intact, but indicate 
# your project name (after the slash) and add your own revision information. 
# 
# Please do not change the "private" password hashing method implemented in 
# here, thereby making your hashes incompatible. However, if you must, please 
# change the hash type identifier (the "$P$") to something different. 
# 
# Obviously, since this code is in the public domain, the above are not 
# requirements (there can be none), but merely suggestions. 
# 
class PasswordHash { 
    var $itoa64; 
    var $iteration_count_log2; 
    var $portable_hashes; 
    var $random_state; 

    function PasswordHash($iteration_count_log2, $portable_hashes) 
    { 
     $this->itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 

     if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) 
      $iteration_count_log2 = 8; 
     $this->iteration_count_log2 = $iteration_count_log2; 

     $this->portable_hashes = $portable_hashes; 

     $this->random_state = microtime(); 
     if (function_exists('getmypid')) 
      $this->random_state .= getmypid(); 
    } 

    function get_random_bytes($count) 
    { 
     $output = ''; 
     if (is_readable('/dev/urandom') && 
      ($fh = @fopen('/dev/urandom', 'rb'))) { 
      $output = fread($fh, $count); 
      fclose($fh); 
     } 

     if (strlen($output) < $count) { 
      $output = ''; 
      for ($i = 0; $i < $count; $i += 16) { 
       $this->random_state = 
        md5(microtime() . $this->random_state); 
       $output .= 
        pack('H*', md5($this->random_state)); 
      } 
      $output = substr($output, 0, $count); 
     } 

     return $output; 
    } 

    function encode64($input, $count) 
    { 
     $output = ''; 
     $i = 0; 
     do { 
      $value = ord($input[$i++]); 
      $output .= $this->itoa64[$value & 0x3f]; 
      if ($i < $count) 
       $value |= ord($input[$i]) << 8; 
      $output .= $this->itoa64[($value >> 6) & 0x3f]; 
      if ($i++ >= $count) 
       break; 
      if ($i < $count) 
       $value |= ord($input[$i]) << 16; 
      $output .= $this->itoa64[($value >> 12) & 0x3f]; 
      if ($i++ >= $count) 
       break; 
      $output .= $this->itoa64[($value >> 18) & 0x3f]; 
     } while ($i < $count); 

     return $output; 
    } 

    function gensalt_private($input) 
    { 
     $output = '$P$'; 
     $output .= $this->itoa64[min($this->iteration_count_log2 + 
      ((PHP_VERSION >= '5') ? 5 : 3), 30)]; 
     $output .= $this->encode64($input, 6); 

     return $output; 
    } 

    function crypt_private($password, $setting) 
    { 
     $output = '*0'; 
     if (substr($setting, 0, 2) == $output) 
      $output = '*1'; 

     $id = substr($setting, 0, 3); 
     # We use "$P$", phpBB3 uses "$H$" for the same thing 
     if ($id != '$P$' && $id != '$H$') 
      return $output; 

     $count_log2 = strpos($this->itoa64, $setting[3]); 
     if ($count_log2 < 7 || $count_log2 > 30) 
      return $output; 

     $count = 1 << $count_log2; 

     $salt = substr($setting, 4, 8); 
     if (strlen($salt) != 8) 
      return $output; 

     # We're kind of forced to use MD5 here since it's the only 
     # cryptographic primitive available in all versions of PHP 
     # currently in use. To implement our own low-level crypto 
     # in PHP would result in much worse performance and 
     # consequently in lower iteration counts and hashes that are 
     # quicker to crack (by non-PHP code). 
     if (PHP_VERSION >= '5') { 
      $hash = md5($salt . $password, TRUE); 
      do { 
       $hash = md5($hash . $password, TRUE); 
      } while (--$count); 
     } else { 
      $hash = pack('H*', md5($salt . $password)); 
      do { 
       $hash = pack('H*', md5($hash . $password)); 
      } while (--$count); 
     } 

     $output = substr($setting, 0, 12); 
     $output .= $this->encode64($hash, 16); 

     return $output; 
    } 

    function gensalt_extended($input) 
    { 
     $count_log2 = min($this->iteration_count_log2 + 8, 24); 
     # This should be odd to not reveal weak DES keys, and the 
     # maximum valid value is (2**24 - 1) which is odd anyway. 
     $count = (1 << $count_log2) - 1; 

     $output = '_'; 
     $output .= $this->itoa64[$count & 0x3f]; 
     $output .= $this->itoa64[($count >> 6) & 0x3f]; 
     $output .= $this->itoa64[($count >> 12) & 0x3f]; 
     $output .= $this->itoa64[($count >> 18) & 0x3f]; 

     $output .= $this->encode64($input, 3); 

     return $output; 
    } 

    function gensalt_blowfish($input) 
    { 
     # This one needs to use a different order of characters and a 
     # different encoding scheme from the one in encode64() above. 
     # We care because the last character in our encoded string will 
     # only represent 2 bits. While two known implementations of 
     # bcrypt will happily accept and correct a salt string which 
     # has the 4 unused bits set to non-zero, we do not want to take 
     # chances and we also do not want to waste an additional byte 
     # of entropy. 
     $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 

     $output = '$2a$'; 
     $output .= chr(ord('0') + $this->iteration_count_log2/10); 
     $output .= chr(ord('0') + $this->iteration_count_log2 % 10); 
     $output .= '$'; 

     $i = 0; 
     do { 
      $c1 = ord($input[$i++]); 
      $output .= $itoa64[$c1 >> 2]; 
      $c1 = ($c1 & 0x03) << 4; 
      if ($i >= 16) { 
       $output .= $itoa64[$c1]; 
       break; 
      } 

      $c2 = ord($input[$i++]); 
      $c1 |= $c2 >> 4; 
      $output .= $itoa64[$c1]; 
      $c1 = ($c2 & 0x0f) << 2; 

      $c2 = ord($input[$i++]); 
      $c1 |= $c2 >> 6; 
      $output .= $itoa64[$c1]; 
      $output .= $itoa64[$c2 & 0x3f]; 
     } while (1); 

     return $output; 
    } 

    function HashPassword($password) 
    { 
     $random = ''; 

     if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) { 
      $random = $this->get_random_bytes(16); 
      $hash = 
       crypt($password, $this->gensalt_blowfish($random)); 
      if (strlen($hash) == 60) 
       return $hash; 
     } 

     if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) { 
      if (strlen($random) < 3) 
       $random = $this->get_random_bytes(3); 
      $hash = 
       crypt($password, $this->gensalt_extended($random)); 
      if (strlen($hash) == 20) 
       return $hash; 
     } 

     if (strlen($random) < 6) 
      $random = $this->get_random_bytes(6); 
     $hash = 
      $this->crypt_private($password, 
      $this->gensalt_private($random)); 
     if (strlen($hash) == 34) 
      return $hash; 

     # Returning '*' on error is safe here, but would _not_ be safe 
     # in a crypt(3)-like function used _both_ for generating new 
     # hashes and for validating passwords against existing hashes. 
     return '*'; 
    } 

    function CheckPassword($password, $stored_hash) 
    { 
     $hash = $this->crypt_private($password, $stored_hash); 
     if ($hash[0] == '*') 
      $hash = crypt($password, $stored_hash); 

     return $hash == $stored_hash; 
    } 
} 

/* End of file phpass_helper.php */ 
/* Location: ./application/helpers/phpass_helper.php */ 

使用phpass幫手,加載幫手,實例化,調用HashPassword功能:

$this->load->helper('phpass'); 
    $hasher = new PasswordHash(PHPASS_HASH_STRENGTH, PHPASS_HASH_PORTABLE); 
    $hash_password = $hasher->HashPassword($password); 
在配置

/constants.php添加以下代碼:

/* 
|-------------------------------------------------------------------------- 
| Portable PHP password hashing framework 
|-------------------------------------------------------------------------- 
| 
| http://www.openwall.com/phpass/ 
| 
*/ 
define('PHPASS_HASH_STRENGTH', 8); 
define('PHPASS_HASH_PORTABLE', FALSE); 

你現在也應該明白爲什麼你會得到關於缺少參數1和2的錯誤。 當你實例化PasswordHash類時,你需要向它提供兩個參數。 您也可以創建phpass作爲CodeIgniter庫文件。只需將函數PasswordHash更改爲__constructor,並在調用庫時提供兩個參數。我會留給你弄清楚。

+0

非常感謝:)據我所知,phpass使用鹽,但不需要在數據庫中存儲鹽。我需要的只是存儲哈希密碼,對吧?如果是的話,你能告訴我應該使用哪個長度的varchar來存儲哈希密碼。 – EducateYourself

+0

我也發現了一個奇怪的事實,即每次同一個單詞的散列版本可能會有所不同。那麼我如何組織登錄驗證? – EducateYourself

+0

看來驗證應該使用以下行$ hasher-> CheckPassword($ password,$ hash) – EducateYourself

3

如果您運行PHP 5.5或更高版本,我強烈建議使用PHP的內置password hashing functions。恕我直言,這些消除了任何第三方/自己寫的哈斯的需要。

作爲額外的好處,您可以在指定特定算法或PHP更改默認算法時輕鬆切換哈希算法。假設你可以使用PHP的默認值(隨機醃製,CRYPT_BLOWFISH,算法成本爲10),下面的代碼讓你瞭解它是如何工作的。

要在你的數據庫中創建存儲的哈希你使用的

password_hash($newPassword, PASSWORD_DEFAULT); 

的結果,當您檢查了密碼,則立即檢查,如果你需要老調重彈的口令,象這樣:

if (password_verify($userInput, $storedHash)) { 
    // The password provided by the user in $userInput 
    // matches the hash we stored (in a database) $storedHash 

    if(password_needs_rehash($storedHash, PASSWORD_DEFAULT)) { 
     $newHash = password_hash($userInput, PASSWORD_DEFAULT); 

     // store new hash in database here 
    } 

    // your what-to-do-on-login-code here 

} else { 

    // your what-to-do-on-login-failure-code here 

} 

不錯,乾淨,對吧?

+0

感謝您的回答。當我開始使用php 5.5或更高版本時,我將使用您的答案。其實,我使用codeigniter,因爲我知道它不支持php 5.5。 – EducateYourself

+0

@EducateYourself使用適用於較低PHP版本的兼容性庫https://github.com/ircmaxell/password_compat – PeeHaa

0

我們開始在你的笨項目整合PHPass之前,從這個鏈接下載PHPass: http://carlofontanos.com/wp-content/uploads/2014/12/phppass.rar

進入的application/config/autoload.php然後找到代碼:

$autoload['libraries'] = array(); 

然後加入phpass庫,以便在每次訪問CodeIgniter時自動加載。

$autoload['libraries'] = array('phppass/passwordhash'); 

如果你不想自動加載PHPass那麼你可以構建庫在模型或控制器這樣的:

$this->load->library('phppass/passwordhash'); 

PasswordHash類添加鹽的密碼,並與8道的哈希它MD5。默認情況下使用MD5,因爲它在所有平臺上均受支持。

要生成一個密碼,比較密碼,請繼續閱讀鏈接: http://carlofontanos.com/using-phpass-library-in-codeigniter/