dongzong1866 2014-11-29 03:31
浏览 54
已采纳

使用mcrypt编码bcrypt字符串

Using PHP, I've created the following set of functions witch ultimately takes a string (password) and applies a bcrypt encryption to it. Furthermore, it generates a key to use with mcrypt then applies that to the bcrypt string (along with base64 to simplify the string) to then insert into a database for storage.
From this when decoding I decrypt the mcrypt encryption applied to the hash and then use password_verify() to then validate it.

However, I am not able to get password_verify() to validate the hash if it has been run through the mcrypt process, even though after it has been decoded the two strings (one from the encode function and one from the decode) are IDENTICAL.

The encode function looks like this:

function passwordEncode($string) {
    $hash = password_hash($string, PASSWORD_BCRYPT, ['cost' => 12]);

    $key = generateKey();

    $encrypt = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key."******", $hash, MCRYPT_MODE_ECB));

    return [$encrypt, $key, $hash];
}

This would return:

[0] ENCRYPT: lTzVGcAY1jkuawebFG/9ZI4O5f/+4hjZHRewstOBAAJwQlYydLJ+B+2QHg9A16qjCUe7FHfTacPzmvH+xnT4rQ==
[1] KEY: 122593420654793b0ee4efc932
[2] HASH: $2y$10$k/4gM1jMIMxnmfBMgrML6enMgqIvnZp2EzPU.G64P3Bb3MDrwJj8e

The HASH index is only for debugging purposes to provide an output hash that has not been run through the mcrypt process

The decode function looks like this:

function passwordDecode($string, $key) {
    $decrypt = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key."******", base64_decode($string), MCRYPT_MODE_ECB);

    return $decrypt;
}

This would return:

DECRYPT: $2y$10$k/4gM1jMIMxnmfBMgrML6enMgqIvnZp2EzPU.G64P3Bb3MDrwJj8e

Using the raw hash that hasn't been run through mcrypt returns Verified

$encode = passwordEncode("password");
if(password_verify("password", $encode[2])) {
    echo 'Verified';
} else {
    echo 'Not verified';
}

However using the hash run through mcrypt encryption and decryption returns Not verified

$encode = passwordEncode("password");
if(password_verify("password", passwordDecode($encode[0], $encode[1]))) {
    echo 'Verified';
} else {
    echo 'Not verified';
}

After spending hours essentially grinding my forehead against a cheese grater, I still haven't been able to figure out what mcrypt is doing to the string to unverify it. I've made an attempt at searching for invisible characters (keyword attempt) but other than that I'm out of ideas as to what the cause is.


Edit: also, this returns not verified

$encode = passwordEncode("password");
if($encode[2]==passwordDecode($encode[0], $encode[1])) {
    echo 'Verified';
} else {
    echo 'Not verified';
}

So something's being done to the string...I just don't know what

  • 写回答

1条回答 默认 最新

  • doujia7779 2014-11-29 14:50
    关注

    For some stupid reason PHP includes the \0 valued characters that are used as zero padding by mcrypt in the decrypted plaintext. Even more stupid, those seem to be included in the base64 decoding performed by password_verify as well, which make it fail without explicit reason. This kind of stupidity makes PHP one of the worst environments to use for security related functions.

    So without further ado, the rewritten functions that perform rtrim, in a piece of code that can be run on it's own. Requires either PHP 5.5 or password_compat :

    <?php
    
    # uncomment for PHP 5.3/5.4
    # require "lib/password.php";
    
    function generateKey() {
        $fp = @fopen('/dev/urandom','rb');
        if ($fp !== FALSE) {
            $key = @fread($fp, 16);
            @fclose($fp);
            return $key;
        }
        return null;
    }
    
    function hashPassword($password) {
        $hash = password_hash($password, PASSWORD_BCRYPT, array('cost' => 12));
        return $hash;
    }
    
    function encryptHash($key, $hash) {
        # encrypt using unsafe ECB mode and without AES
        $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $hash, MCRYPT_MODE_ECB);
        $encoded = base64_encode($encrypted);
        return $encoded;
    }
    
    function decryptHash($key, $ciphertext) {
        $decoded = base64_decode($ciphertext);
        $decryptedHash = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_ECB);
        # remove stupid zero padding
        $decryptedHash = rtrim($decryptedHash, "\0");
        return $decryptedHash;
    }
    
    $hash = hashPassword("password");
    
    if(password_verify("password", $hash)) {
        echo 'Verified' . PHP_EOL;
    } else {
        echo 'Not verified' . PHP_EOL;
    }
    
    $key = generateKey();
    $encrypted = encryptHash($key, $hash);
    $decrypted = decryptHash($key, $encrypted);
    
    if(password_verify('password', $decrypted)) {
        echo 'Verified' . PHP_EOL;
    } else {
        echo 'Not verified' . PHP_EOL;
    }
    ?>
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算
  • ¥15 java如何提取出pdf里的文字?