遇到Bcrypt C#Salt问题

时间:2014-01-13 04:21:33

标签: c# bcrypt

大家好我目前正在尝试匹配使用

的PHP登录系统
define('PASSWORD_ENCRYPTION', "bcrypt"); 
define('PASSWORD_SHA512_ITERATIONS', 25000); 
define('PASSWORD_BCRYPT_COST', "13"); 

define('PASSWORD_SALT', "/8Wncr26eAmxD1l6cAF9F8"); //22 characters to be appended on first 7 characters that will be generated using PASSWORD_ info above

我的C#:

            string myPassword = this.password_txt.Text;
            string mySalt = "$2a$13$/8Wncr26eAmxD1l6cAF9F8";
            string hashed = BCrypt.HashPassword(myPassword, mySalt);

问题:我使用C#编写的哈希密码与数据库上的登录PHP哈希密码不匹配...

1 个答案:

答案 0 :(得分:6)

您的全部功能如下所示

/**
 * Hash given password.
 * @param string $password Unhashed password.
 * @return string Hashed password.
 */
 public function hashPassword($password) {
    //this salt will be used in both algorithms
    //for bcrypt it is required to look like this,
    //for sha512 it is not required but it can be used 
    $salt = "$2a$" . PASSWORD_BCRYPT_COST . "$" . PASSWORD_SALT;

    if(PASSWORD_ENCRYPTION == "bcrypt") {
        $newPassword = crypt($password, $salt);
    }
    else {
        $newPassword = $password;
        for($i=0; $i<PASSWORD_SHA512_ITERATIONS; $i++)
            $newPassword = hash('sha512',$salt.$newPassword.$salt);
    }

    return $newPassword;
 }

编辑:更多研究表明$2a$似乎是BlowFish Encryption来自研究。 (http://php.net/crypt

  

CRYPT_BLOWFISH - Blowfish用盐进行散列如下:“$ 2a $”,   “$ 2x $”或“$ 2y $”,两位数的成本参数“$”和22个字符   从字母“./0-9A-Za-z”。使用此外的字符   salt中的range将导致crypt()返回零长度字符串。   两位数的成本参数是迭代的基数2对数   计算基础的基于Blowfish的哈希算法并且必须   在04-31范围内,超出此范围的值将导致crypt()   失败。在5.3.7之前的PHP版本仅支持“$ 2a $”作为salt   前缀:PHP 5.3.7引入了新的前缀来修复安全性   Blowfish实施中的弱点。请参考»这个   有关安全修复程序的完整详细信息的文档,但总结一下,   仅针对PHP 5.3.7及更高版本的开发人员应使用“$ 2y $”   偏好“$ 2a $”。

     

必须以“$ 2”开头,可选“a”,“$”,两位数,“$”和22   基数为64位。字符串的其余部分将被忽略。存在的   可选的“a”表示之前要将NUL附加到密码中   它被用作钥匙。两位数设置成本参数。 22   基数64位编码盐。


$13$被称为cost。 (循环加密多少次)。 现在,盐本身已在base64中进行编码,您必须先将其解码,然后再使用Eksblowfish

  

Eksblowfish,(昂贵的关键时间表河豚,是一种成本   河豚块密码的可参数化和盐渍变化。)

无论如何总结一下,你必须使用这个 http://bcrypt.codeplex.com/

应该是这样的

int PASSWORD_BCRYPT_COST = 13;
string PASSWORD_SALT = "/8Wncr26eAmxD1l6cAF9F8";
string salt = "$2a$" + PASSWORD_BCRYPT_COST + "$" + PASSWORD_SALT;
string password  "test123abc";
var hash = BCrypt.HashPassword(password, salt);
textBox1.Text = hash;

密码= test123abc
textbox1的输出为:$2a$13$/8Wncr26eAmxD1l6cAF9FuVnazDlahXc73He5NB1GKNYG7v3mOOyS

C# test program screenshot

还在php http://ideone.com/8piXMq

中运行您的代码

php输出

echo hashPassword("test123abc");

php的输出是:$2a$13$/8Wncr26eAmxD1l6cAF9FuVnazDlahXc73He5NB1GKNYG7v3mOOyS

C#
$2a$13$/8Wncr26eAmxD1l6cAF9FuVnazDlahXc73He5NB1GKNYG7v3mOOyS
PHP
$2a$13$/8Wncr26eAmxD1l6cAF9FuVnazDlahXc73He5NB1GKNYG7v3mOOyS

正如您所看到的,答案都是 IDENTICAL


正如您在BCrypt HashPassword实现中所看到的,它解码了base64 salt并使用您指定的salt重新加密新密码。

/// <summary>
/// Hash a password using the OpenBSD bcrypt scheme.
/// </summary>
/// <param name="password">The password to hash.</param>
/// <param name="salt">The salt to hash with (perhaps generated
/// using <c>BCrypt.GenerateSalt</c>).</param>
/// <returns>The hashed password.</returns>
public static string HashPassword(string password, string salt) {
    if (password == null) {
        throw new ArgumentNullException("password");
    }
    if (salt == null) {
        throw new ArgumentNullException("salt");
    }

    char minor = (char)0;

    if (salt[0] != '$' || salt[1] != '2') {
        throw new ArgumentException("Invalid salt version");
    }

    int offset;
    if (salt[1] != '$') {
        minor = salt[2];
        if (minor != 'a' || salt[3] != '$') {
            throw new ArgumentException("Invalid salt revision");
        }
        offset = 4;
    } else {
        offset = 3;
    }

    // Extract number of rounds
    if (salt[offset + 2] > '$') {
        throw new ArgumentException("Missing salt rounds");
    }

    int rounds = Int32.Parse(salt.Substring(offset, 2), NumberFormatInfo.InvariantInfo);

    byte[] passwordBytes = Encoding.UTF8.GetBytes(password + (minor >= 'a' ? "\0" : String.Empty));
    byte[] saltBytes = DecodeBase64(salt.Substring(offset + 3, 22),
                                    BCRYPT_SALT_LEN);

    BCrypt bcrypt = new BCrypt();

    byte[] hashed = bcrypt.CryptRaw(passwordBytes, saltBytes, rounds);

    StringBuilder rs = new StringBuilder();

    rs.Append("$2");
    if (minor >= 'a') {
        rs.Append(minor);
    }
    rs.Append('$');
    if (rounds < 10) {
        rs.Append('0');
    }
    rs.Append(rounds);
    rs.Append('$');
    rs.Append(EncodeBase64(saltBytes, saltBytes.Length));
    rs.Append(EncodeBase64(hashed,
                           (bf_crypt_ciphertext.Length * 4) - 1));

    return rs.ToString();
}