2016-01-05 2 views
-7

У меня был кто-то для ввода этого кода для меня, но я не знаю, как его хранить в базе данных MySQL и иметь возможность расшифровать его. То, что я ошибочно делал изначально, пыталось сохранить пароль, а затем сравнить его с другим экземпляром. Когда я понял, что делаю, я был потрясен тем, что было не так. Я подумал о сохранении экземпляра, но это будет угрозой безопасности, потому что любой, у кого есть доступ к базе данных, может вызвать $ instance-> decodePassword ($ password). Я предполагаю, что сценарий не был разработан для использования с MySQL, а парень, которого я заплатил, чтобы ввести скрипт, не отвечает. Что мне делать? Любая помощь будет принята с благодарностью.Кто-нибудь знает, как интегрировать этот код с MySQL

<?php 

/** 
* Password protection class. 
*/ 
class PasswordCrypt { 
    /* Number of rounds to use for PBKDF2 for new setups. 
    * May be tweaked up or down because the number of rounds is encoded with the data 
    */ 
    const DEFAULT_PBKDF2_ROUNDS = 10000; 

    /* Definition: 
    * Output data = 1 || IV || HMAC_SHA256(K, PROTECT_AES_256_CBC(K, IV, data)) || AES_256_CBC(K, IV, data) 
    */ 
    const PROTECT_AES_256_CBC_HMACSHA1 = 1; 

    /* Definition: 
    * Uses the PBKDF2 derivation algorithm. The key is encrypted with a protection algorithm.. 
    * Output data = 1 || SALT || Rounds (4-byte-integer) || 'Protected' key) 
    */ 
    const TOKEN_PBKDF2_SHA256_AES_256_CBC = 1; 

    /* Token which is effectively the key encrypted with the password */ 
    private $token; 

    /* Key used to perform encryption/decryption */ 
    private $key; 

    /* Private constructor that takes the token and key. 
    * 
    * The token is kept around for storage purposes whereas the key is the main 
    * important piece. 
    */ 
    protected function __construct($token, $key) { 
     $this->token = $token; 
     $this->key = $key; 
    } 

    /** 
    * Create a new instance using a given password. 
    * 
    * @param $password text string from user 
    */ 
    public static function createWithNewPassword($password) { 
     /* Generate the new random key to use */ 
     $key = PasswordCrypt::generateRandomKey(); 

     /* Generate the token to store */ 
     $token = PasswordCrypt::encodeProtectedToken($password, $key); 

     /* Setup the instance */ 
     return new PasswordCrypt($token, $key); 
    } 


    /** 
    * Create a new instance given input token and password. 
    * 
    * @param $password password associated with the given $token 
    * @param $token token for the given user 
    * 
    * @return null if decoding fails, else value instance that can decrypt/encrypt passwords/etc. 
    */ 
    public static function createFromToken($password, $token) { 
     $key = PasswordCrypt::decodeProtectedToken($password, $token); 
     if (!$key) { 
      return null; 
     } 

     return new PasswordCrypt($token, $key); 
    } 

    /** 
    * Create a new instance using session data. 
    */ 
    public static function createWithSession() { 
     $token = $_SESSION['__pc_token']; 
     $sessionKey = $_SESSION['__pc_key']; 

     $cookieData = $_COOKIE['__pc_cookie']; 
     if (!$token || !$sessionKey || !$cookieData) { 
      return null; 
     } 
     $cookieData = PasswordCrypt::base64url_decode($cookieData); 
     $key = PasswordCrypt::decryptData($sessionKey, $cookieData); 

     return new PasswordCrypt($token, $key); 
    } 

    /** 
    * Utility function to check if the PHP session state has what is needed for 
    * session-based construction. 
    */ 
    public static function hasSessionData() { 
     return $_SESSION['__pc_token'] 
      && $_SESSION['__pc_key'] 
      && $_COOKIE['__pc_cookie']; 
    } 

    /** 
    * Clear the session state from PHP to prevent re-use (ex: useful for logout) 
    */ 
    public static function clearSessionData() { 
     unset($_SESSION['__pc_token']); 
     unset($_SESSION['__pc_key']); 
     PasswordCrypt::setSessionCookie('__pc_cookie', ''); 
    } 

    /* Utility function to store data in the session and set a cookie to decrypt */ 
    public function storeSessionKey() { 
     $sessionKey = PasswordCrypt::generateRandomKey(); 
     $cookieData = PasswordCrypt::encryptData($sessionKey, $this->key); 

     $_SESSION['__pc_token'] = $this->token; 
     $_SESSION['__pc_key'] = $sessionKey; 
     PasswordCrypt::setSessionCookie('__pc_cookie', PasswordCrypt::base64url_encode($cookieData)); 
    } 

    /** 
    * Utility method to set a session cookie - tweak as appropriate for proper cookie settings for the site. 
    */ 
    private static function setSessionCookie($name, $value) { 
     /* Store for session only and assume total path... */ 
     $secure = false; 
     if ($_SERVER["HTTPS"]) { 
      $secure = TRUE; 
     } 
     setcookie($name, $value, 0, "", "", $secure, TRUE); 
    } 

    /** 
    * Method to decode passwords previously encoded. 
    * 
    * @param $ciphertext raw binary string representing the encrypted password. 
    * 
    * @return decoded password string as passed in to encodePassword. 
    * null may be returned if the data is corrupt, uses a format not supported by 
    * this version, or does not match the key. 
    */ 


    public function decodePassword($ciphertext) { 
    /* Changed first parameter in decryptData from $this->key to $InsideOutsideKey */ 
     return PasswordCrypt::decryptData($this->key,$ciphertext); 
    } 

    /** 
    * Method to encode passwords to later be decoded using decodePassword. 
    * 
    * @param $password text representing the data to protect - may be raw binary. 
    * 
    * @return encrypted password data in raw binary form. null will be returned if 
    * something is critically wrong with the setup - not likely. 
    */ 
    public function encodePassword($password) { 
     return PasswordCrypt::encryptData($this->key, $password); 
    } 

    /** 
    * Method to create a new token protected with a new password. 
    * Useful for when the user wants to change their password. 
    * 
    * @param $password new password to encode against. 
    * 
    * @return token to later be decoded using the provided password. 
    */ 
    public function encodeToken($password) { 
     return PasswordCrypt::encodeProtectedToken($password, $this->key); 
    } 

    /** 
    * Method to get the current token as protected by the initial password input. 
    * 
    * @return token to later be decoded using the initial password at creation. 
    */ 
    public function getToken() { 
     return $this->token; 
    } 
    /** 
    *Method to get a random key used by AES-256 
    */ 
    public function getKey() { 
     return $this->key; 
    } 
    /** 
    * Utility method to generate a random key as required by AES-256 
    */ 
    private static function generateRandomKey() { 
     /* Since using AES 256 CBC - we need 256 bits */ 
     return openssl_random_pseudo_bytes(256/8); 
    } 

    /* Generate the protected token data */ 
    private static function encodeProtectedToken($password, $key) { 
     $implementation = PasswordCrypt::TOKEN_PBKDF2_SHA256_AES_256_CBC; 
     switch ($implementation) { 
     case PasswordCrypt::TOKEN_PBKDF2_SHA256_AES_256_CBC: 
      /* Generate fresh salt to prevent rainbow table attacks */ 
      $salt = openssl_random_pseudo_bytes(16); 
      /* Use the defaults configured */ 
      $iterations = PasswordCrypt::DEFAULT_PBKDF2_ROUNDS; 
      /* Derive the key using PBKDF2 with SHA256 per the token key generation scheme */ 
      $passwordDerivedKey = PasswordCrypt::pbkdf2("SHA256", $password, $salt, $iterations, 256/8, true); 
      /* Encrypt the 'real' key data using the password-based key */ 
      $data = PasswordCrypt::encryptData($passwordDerivedKey, $key); 
      return pack("Ca16La*", $implementation, $salt, $iterations, $data); 
     default: 
      return null; 
     } 
    } 

    /* Decode the protected token data */ 
    private static function decodeProtectedToken($password, $tokenData) { 
     list(,$implementation) = unpack("C", $tokenData); 
     switch ($implementation) { 
     case PasswordCrypt::TOKEN_PBKDF2_SHA256_AES_256_CBC: 
      /* Extract the salt encoded in the protection data */ 
      $salt = substr($tokenData, 1, 16); 
      /* Extract the number of iterations used for this data */ 
      list(,$iterations) = unpack("L", substr($tokenData, 1 + 16, 4)); 
      /* Extract the encrypted key data */ 
      $encrypted = substr($tokenData, 1 + 16 + 4); 
      /* Derive the key using PBKDF2 with SHA256 per the token key generation scheme */ 
      $passwordDerivedKey = PasswordCrypt::pbkdf2("SHA256", $password, $salt, $iterations, 256/8, true); 
      /* Decrypt the key data using the derived key */ 
      return PasswordCrypt::decryptData($passwordDerivedKey, $encrypted); 
     default: 
      return null; 
     } 
    } 

    /* Protect data using a given input key */ 
    private static function encryptData($key, $plaintext) { 
     $implementation = PasswordCrypt::PROTECT_AES_256_CBC_HMACSHA1; 
     switch ($implementation) { 
     case PasswordCrypt::PROTECT_AES_256_CBC_HMACSHA1: 
      /* Some PHP versions to not have OPENSSL_RAW_DATA option and instead use a boolean for raw, so handle it */ 
      $options = defined("OPENSSL_RAW_DATA") ? OPENSSL_RAW_DATA : true; 
      /* 16-byte IV */ 
      $iv = openssl_random_pseudo_bytes(16); 

      /* Encrypt the data first */ 
      $encrypted = openssl_encrypt($plaintext, "aes-256-cbc", bin2hex($key), $options, $iv); 
      /* Generate an HMAC over the data to make sure final output matches */ 
      $hmac = hash_hmac("sha1", $encrypted, $key, TRUE); 
      /* HMAC should be 160 bits long - 20 bytes */ 
      return pack("Ca16a20A*", $implementation, $iv, $hmac, $encrypted); 
     default: 
      return null; 
     } 
    } 

    /* Decoded protected data with a given key */ 
    private static function decryptData($key, $ciphertext) { 
     list(,$implementation) = unpack("C", $ciphertext); 
     switch ($implementation) { 
     case PasswordCrypt::PROTECT_AES_256_CBC_HMACSHA1: 
      $iv = substr($ciphertext, 1, 16); 
      $included_hmac = substr($ciphertext, 1 + 16, 20); 
      $encrypted = substr($ciphertext, 1 + 16 + 20); 
      /* Verify the HMAC */ 
      $hmac = hash_hmac("sha1", $encrypted, $key, TRUE); 
      if ($hmac != $included_hmac) { 
       /* HMAC did not match, bad key or corrupt data */ 
       return null; 
      } 
      /* Some PHP versions to not have OPENSSL_RAW_DATA option and instead use a boolean for raw, so handle it */ 
      $options = defined("OPENSSL_RAW_DATA") ? OPENSSL_RAW_DATA : true; 
      $decrypted = openssl_decrypt($encrypted, "aes-256-cbc", bin2hex($key), $options, $iv); 
      return $decrypted; 
     default: 
      return null; 
     } 
    } 

    /* 
    * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt 
    * $algorithm - The hash algorithm to use. Recommended: SHA256 
    * $password - The password. 
    * $salt - A salt that is unique to the password. 
    * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000. 
    * $key_length - The length of the derived key in bytes. 
    * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise. 
    * Returns: A $key_length-byte key derived from the password and salt. 
    * 
    * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt 
    * 
    * This implementation of PBKDF2 was originally created by https://defuse.ca 
    * With improvements by http://www.variations-of-shadow.com 
    */ 
    private static 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 we have a version of PHP with the native hash_pbkdf2 - use that! */ 
     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 = 1; $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)); 
     } 
    } 
    private static function base64url_encode($data) { 
     return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); 
    } 

    private static function base64url_decode($data) { 
     return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); 
    } 
} 

?> 
+2

Если вы просто делаете логин, посмотрите, есть ли у вашего php функция password_hash(). Если да, посмотрите, как его использовать и его спутник password_verify(). – Rasclatt

+0

Если нет, существует библиотека github, которая совместима, bcrypt password hash lib – Rasclatt

ответ

0

Добавление этого сработало для меня. Теперь я могу создать новый экземпляр из токена, извлеченного из базы данных. Я удивлен, что никто из вас не подумал об этом.

/**** 
    Beginning of added mysqli method 
    *****/ 
    public static function createWithNewMysqli($fetched_token,$fetched_key) 
    { 
     return new PasswordCrypt($fetched_token, $fetched_key); 
    } 
    /**** 
    End of added mysqli method 

    ****/