dongxia9620 2016-01-03 07:01
浏览 92

我在MySQL表中存储密钥,令牌和密码,但是当我使用mysql_escape_real_string()时,它会改变数据

So, someone here on stackoverflow helped me when I didn't know how to insert the token into my table. I found out that I just needed to use mysqli_escape_real_string(). However, this presented another problem. In some way I think mysqli_escape_real_string() is altering the data when I try to take the key and token out and use the createFromToken() method. I'm just wondering why it won't generate the password from the method and if it has to do with added slashes. When I checked the table field I see something string with many different characters, but spread throughout are these weird symbols, like (). I'm wondering if mysqli_escape_real_string is causing this and it's making the database key and token not be like the original, thus yielding the createFromToken() method ineffective. Any advice is greatly appreciated.

<?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.
     */
    /**
    * Method to use MySQL functions
    * Beginning of added code
    */
    public function MySQL()
    {
        $query = "SELECT password_key FROM pwmkey";
        $connection = $check_connection->db_connect();
        $result = mysqli_query($check_connection,$query);
        $array = mysqli_fetch_assoc($result);
    }       


    /**
    *End of added code
    */
    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));
    }
}

?>

I created another script to test the data by putting it inside of mysqli_escape_real_string()

<?php
require_once('../Password_Encrypt_Decrypt/passwordCrypt.php');
require_once('../MySQLi/mysqliConnect.php');
// Get token and key 
/*
$query = "SELECT password_key,token,encrypted_password FROM customers WHERE customer_id = 51";
$info = mysqli_query($mysqli,$query) OR DIE (mysqli_error($mysqli));
$row = mysqli_fetch_object($info);
$password = $row->encrypted_password;
$key = $row->password_key;
$token = $row->token;
*/
// Delete the following lines
$instance = passwordCrypt::createWithNewPassword('brock');
$encodedpass = $instance->encodePassword('brock');
$token = $instance->getToken();
if($encodedpass === mysqli_real_escape_string($mysqli,$encodedpass)) { echo "Yes they're the same"; }
 else { echo "No, they aren't the same"; }
 if($token === mysqi_real_escape_string($token)) { echo "<br />Yes they're also the same"; }
 else { echo "<br />No, they're not the same"; }

/*
$instance = passwordCrypt::createFromToken($password,$token);
if($instance == NULL) { echo "Yes it's null"; } else { echo "No it is not null"; }
$decodedpassword = $instance->decodePassword($password);
print_r($decodedpassword);
*/
?>
  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 关于#python#的问题:求帮写python代码
    • ¥20 MATLAB画图图形出现上下震荡的线条
    • ¥15 LiBeAs的带隙等于0.997eV,计算阴离子的N和P
    • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
    • ¥15 来真人,不要ai!matlab有关常微分方程的问题求解决,
    • ¥15 perl MISA分析p3_in脚本出错
    • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
    • ¥15 ubuntu虚拟机打包apk错误
    • ¥199 rust编程架构设计的方案 有偿
    • ¥15 回答4f系统的像差计算