dongshenyu4638 2013-02-17 14:50
浏览 112
已采纳

根据PHP中的SSHA256哈希验证密码

For authentification with Dovecot, I use SSHA256 hashes but I have no clue how to validate a given password against the existing hash. The following PHP functions (found them in the web) are used to create the SSHA256 hash:

function ssha256($pw) {
        $salt = make_salt();
        return "{SSHA256}" . base64_encode( hash('sha256', $pw . $salt, true ) . $salt );
}

function make_salt() {
        $len   = 4;
        $bytes = array();
        for ($i = 0; $i < $len; $i++ ) {
                $bytes[] = rand(1,255);
        }
        $salt_str = '';
        foreach ($bytes as $b) {
                $salt_str .= pack('C', $b);
        }
        return $salt_str;
}

Example output: {SSHA256}lGq49JTKmBC49AUrk7wLyQVmeZ7cGl/V13A9QbY4RVKchckL

Do I have to extract the salt, but how? I totally lost the way for solving the problem, has anyone a hint for this?

Thanks to everyone for helping!

Oh and sorry, I have to use SSHA256, because Dovecot 1.2.15 supports only those schemes: CRYPT MD5 MD5-CRYPT SHA SHA1 SHA256 SMD5 SSHA SSHA256 PLAIN CLEARTEXT CRAM-MD5 HMAC-MD5 DIGEST-MD5 PLAIN-MD4 PLAIN-MD5 LDAP-MD5 LANMAN NTLM OTP SKEY RPA

  • 写回答

2条回答 默认 最新

  • dpd3982 2013-02-17 15:00
    关注

    You should not be using the SHA family for password hashing. They are fast and designed for hashing files at speed. You need pashword hashing to be expensive. Use bcrypt, PHPass or just use this class, which I rolled myself (but not until you learn to pick holes in it):

    class PassHash {
        public static function rand_str($length) {
            $total = $length % 2;
            $output = "";
            if ($total !== 0) {
                $count = floor($length / 2);
                $output .= ".";
            } else $count = $length / 2;
    
            $bytes = openssl_random_pseudo_bytes($count);
            $output .= bin2hex($bytes);
    
            // warning: prepending with a dot if the length is odd.
            // this can be very dangerous. no clue why you'd want your
            // bcrypt salt to do this, but /shrug
    
            return $output;
        }
        // 2y is an exploit fix, and an improvement over 2a. Only available in 5.4.0+
        public static function hash($input) {
            return crypt($input, "$2y$13$" . self::rand_str(22));
    
        }
    
        // legacy support, add exception handling and fall back to <= 5.3.0
        public static function hash_weak($input) {
            return crypt($input, "$2a$13$" . self::rand_str(22));
        }
    
        public static function compare($input, $hash) {
            return (crypt($input, $hash) === $hash);
        }
    }
    

    You have to hash the plaintext given and compare that hash against one you have stored. The salts are stored in the hashes, and should be random. If you like, add a pepper. You should also make the workrate variable, so that you can change the workrate at any moment when needed and still have your system work.


    If, like you say, you have no way of implementing this, you can unpack the hash as follows:

    function unpack_hash($hash) {
            $hash = base64_decode($hash);
            $split = str_split($hash, 64);
            return array("salt" => $split[1], "hash" => $split[0]);
    

    This is because SHA256 is 256 bits, or 64 hex characters. You can just always assume the first 64 chars are the hash

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?