duanke6249 2016-01-05 03:00
浏览 58

有谁知道如何将此代码与MySQL集成

I had someone type this code for me but I don't know how to store it in the MySQL database and be able to decrypt it. What I was mistakenly doing initially, was trying to store the password and then compare it to a different instance. When I realized what I was doing I was shocked at what was wrong. I thought about storing the instance but that would be a security risk, because anyone with access to the database could call $instance->decodePassword($password). I guess the script wasn't really designed to be used with MySQL and the guy I paid to type the script isn't responding. What should I do? Any help would be 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.
     */


    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));
    }
}

?>
  • 写回答

1条回答 默认 最新

  • dse3168 2016-01-06 07:58
    关注

    Adding this worked for me. Now I can create a new instance from the token retrieved from the database. I'm surprised none of you guys thought of this.

    /****
        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
    
        ****/
    
    评论

报告相同问题?

悬赏问题

  • ¥30 这是哪个作者做的宝宝起名网站
  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!