2013-05-24 5 views
4

그래서 저는 bcrypt를 실험하고있었습니다. 나는 아래에 나와있는 클래스를 가지고있다.이 클래스는 3 개의 함수가있다. 첫 번째는 무작위 소금을 생성하는 것이며 두 번째는 생성 된 소금을 사용하여 해시를 생성하고 두 번째는 해시 된 암호와 비교하여 제공된 암호를 확인하는 것입니다. 내가 예를 들어 '비밀번호'와 해시를 생성하는 경우bcrypt와 무작위로 생성 된 소금

<?php 
/* Bcrypt Example */ 
class bcrypt { 
    private $rounds; 
    public function __construct($rounds = 12) { 
     if(CRYPT_BLOWFISH != 1) { 
      throw new Exception("Bcrypt is not supported on this server, please see the following to learn more: http://php.net/crypt"); 
     } 
     $this->rounds = $rounds; 
    } 

    /* Gen Salt */ 
    public function genSalt() { 
     /* openssl_random_pseudo_bytes(16) Fallback */ 
     $seed = ''; 
     for($i = 0; $i < 16; $i++) { 
      $seed .= chr(mt_rand(0, 255)); 
     } 
     /* GenSalt */ 
     $salt = substr(strtr(base64_encode($seed), '+', '.'), 0, 22); 
     /* Return */ 
     return $salt; 
    } 

    /* Gen Hash */ 
    public function genHash($password) { 
     /* Explain '$2y$' . $this->rounds . '$' */ 
      /* 2a selects bcrypt algorithm */ 
      /* $this->rounds is the workload factor */ 
     /* GenHash */ 
     $hash = crypt($password, '$2y$' . $this->rounds . '$' . $this->genSalt()); 
     /* Return */ 
     return $hash; 
    } 

    /* Verify Password */ 
    public function verify($password, $existingHash) { 
     /* Hash new password with old hash */ 
     $hash = crypt($password, $existingHash); 

     /* Do Hashs match? */ 
     if($hash === $existingHash) { 
      return true; 
     } else { 
      return false; 
     } 
    } 
} 
/* Next the Usage */ 
/* Start Instance */ 
$bcrypt = new bcrypt(12); 

/* Two create a Hash you do */ 
echo 'Bcrypt Password: ' . $bcrypt->genHash('password'); 

/* Two verify a hash you do */ 
$HashFromDB = $bcrypt->genHash('password'); /* This is an example you would draw the hash from your db */ 
echo 'Verify Password: ' . $bcrypt->verify('password', $HashFromDB); 
?> 

지금, 나는 randmonly했다 해시 암호, 소금을 생성 얻을. 다음으로 'password'를 다시 입력하고 verify 함수를 사용하면 암호가 일치한다는 의미가됩니다. 잘못된 비밀번호를 입력하면 허위로 표시됩니다. 내 질문은 이것이 어떻게 가능한가? 무작위로 생성 된 소금은 어떨까요? 어떻게 그런 효과가없는거야?

+2

PHP v5.5 (곧 출시 예정)에는이 코드의 필요성을 제거하는'password_xxx()'함수 세트가 있습니다. PHP 5.5 암호 기능을 5.3 또는 5.4로 구현하는 역 호환 라이브러리도 다운로드 할 수 있습니다. 그것을 시도해 볼 수도 있습니다. 그것은 당신에게 많은 일을 덜어 줄 것입니다. https://github.com/ircmaxell/password_compat – Spudley

답변

13

처리중인 값을 잘 살펴보십시오. 될 것입니다 생성 된 임의 소금, 말 : crypt에 공급 무엇

abcdefg... 

은 다음과 같습니다

crypt($password, '$2y$10$abcdefg...') 
        | | | 
        | | +- the salt 
        | +- the cost parameter 
        +- the algorithm type 

결과는 다음과 같습니다 즉

$2y$10$abcdefg...123456789... 
| | |  | 
| | |  +- the password hash 
| | +- the salt 
| +- the cost parameter 
+- the algorithm type 

, 첫 번째 결과 해시의 일부는 crypt 함수의 원래 입력과 동일합니다. 알고리즘 타입과 파라미터, 랜덤 소금와 해시 결과가 포함됩니다.

Input: $password + $2y$10$abcdefg... 
Output:    $2y$10$abcdefg...123456789... 
        ^^^^^^^^^^^^^^^^^ 
        first part identical 

암호를 확인

, 당신 필요 다시 같은, 원래 소금. 같은 소금으로 만 같은 해시에 동일한 암호 해시가 적용됩니다. 해시가 생성 될 때와 동일한 작업을 반복 할 수있는 것처럼 그대로 crypt으로 전달할 수있는 형식으로 해시에 계속 남아 있습니다. 유효성 검증 기능에 암호 해시를 모두 공급해야하는 이유입니다 : 소금이 있어야하는 이유

crypt($passwordToCheck, '$2y$10$abcdefg...123456789...') 

crypt가와 abcdefg... 등까지 문자의 첫 번째 정의 된 번호를 받아 멀리 나머지를 던졌습니다 (그건 고정 된 수의 문자). 따라서 이전과 같은 작업을 동일 :

crypt($passwordToCheck, '$2y$10$abcdefg...') 

그리고 및 경우에만$passwordToCheck가 동일한 경우, 를 동일한 해시를 생성합니다.

+0

본인은 같은 소금이 다시 필요하다는 것을 알고 있습니다. 그리고 내가 한 지침서는 생성 된 소금을 사용자 이름과 암호와 함께 테이블에 저장하는 것을 제안합니다. 그러나 원래 생성 된 소금을 사용하지 않고 그것을 시도하고 여전히 작동합니다. 몇 번 시도해 보았지만 매번 작동합니다. –

+0

예, 소금 **은 일반 텍스트로 생성 된 해시의 일부이므로 ** 별도로 저장하지 않아도됩니다. 해시의 일부입니다. 해시의 첫 번째 부분은 'crypt'에 필요한 매개 변수와 정확히 동일하므로 단순히 '암호'로 다시 채워야합니다. – deceze

+0

bcrypt는 원래 암호 문자열에서 생성 된 해시 부분 만 확인하고 확인시에는 소금을 무시한다고 말하고 있습니까? –

관련 문제