Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
对Bcrypt C#盐有问题_C#_Bcrypt - Fatal编程技术网

对Bcrypt C#盐有问题

对Bcrypt C#盐有问题,c#,bcrypt,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 char

大家好,我正在尝试匹配我的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#:


问题:我用C#创建的哈希密码与数据库上的登录PHP哈希密码不匹配…

您的完整函数如下所示

/**
 * 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;
 }
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

还使用php运行了您的代码

的php输出

echo hashPassword("test123abc");
php的输出为:
2a$13$/8Wncr26eAmxD1l6cAF9FuVnazDlahXc73He5NB1GKNYG7v3mOOyS

C#
$2a$13$/8WNCR26EAMXD1L6CAF9FUVNAZDLAHXC73HE5NB1GKNYG7V3OOYS

PHP
$2a$13$/8WNCR26EAMXD1L6CAF9FUVNAZDLAHXC73HE5NB1GKNYG7V3OOYS

如您所见,答案都是相同的


从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();
}
//
///使用OpenBSD bcrypt方案散列密码。
/// 
///要哈希的密码。
///要散列的盐(可能是生成的)
///使用BCrypt.GenerateSalt)。
///哈希密码。
公共静态字符串HashPassword(字符串密码、字符串salt){
如果(密码==null){
抛出新的ArgumentNullException(“密码”);
}
if(salt==null){
抛出新的异常(“salt”);
}
char minor=(char)0;
if(salt[0]!='$'| | salt[1]!='2'){
抛出新ArgumentException(“无效的salt版本”);
}
整数偏移量;
如果(salt[1]!=“$”){
小调=盐[2];
如果(小调!=“a”| salt[3]!=“$”){
抛出新的ArgumentException(“无效的salt修订”);
}
偏移量=4;
}否则{
偏移量=3;
}
//提取轮数
如果(盐[偏移量+2]>“$”){
抛出新的ArgumentException(“缺少盐回合”);
}
int rounds=Int32.Parse(salt.Substring(offset,2),NumberFormatInfo.InvariantInfo);
byte[]passwordBytes=Encoding.UTF8.GetBytes(password+(minor>='a'?“\0”:String.Empty));
字节[]saltBytes=DecodeBase64(salt.Substring(偏移量+3,22),
b crypt_SALT_LEN);
BCrypt BCrypt=新的BCrypt();
byte[]hashed=bcrypt.CryptRaw(passwordBytes、saltBytes、rounds);
StringBuilder rs=新的StringBuilder();
卢比(“$2”);
如果(次要>='a'){
卢比(小调);
}
rs.Append(“$”);
如果(轮数<10){
rs.Append('0');
}
卢比(轮);
rs.Append(“$”);
rs.Append(EncodeBase64(saltBytes,saltBytes.Length));
rs.Append(EncodeBase64)(散列,
(bf_crypt_ciphertext.Length*4)-1);
返回rs.ToString();
}

您的全部功能如下所示

/**
 * 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;
 }
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

还使用php运行了您的代码

的php输出

echo hashPassword("test123abc");
php的输出为:
2a$13$/8Wncr26eAmxD1l6cAF9FuVnazDlahXc73He5NB1GKNYG7v3mOOyS

C#
$2a$13$/8WNCR26EAMXD1L6CAF9FUVNAZDLAHXC73HE5NB1GKNYG7V3OOYS

PHP
$2a$13$/8WNCR26EAMXD1L6CAF9FUVNAZDLAHXC73HE5NB1GKNYG7V3OOYS

如您所见,答案都是相同的


从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();
}
//
///使用OpenBSD bcrypt方案散列密码。
/// 
///要哈希的密码。
///要散列的盐(可能是生成的)
///使用BCrypt.GenerateSalt)。
///哈希密码。
公共静态字符串HashPassword(字符串密码、字符串salt){
如果(密码==null){
抛出新的ArgumentNullException(“密码”);
}
if(salt==null){
抛出新的异常(“salt”);
}
char minor=(char)0;
if(salt[0]!='$'| | salt[1]!='2'){
抛出新ArgumentException(“无效的salt版本”);
}
整数偏移量;
如果(salt[1]!=“$”){
小调=盐[2];
如果(小调!=“a”| salt[3]!=“$”){
抛出新的ArgumentException(“无效的salt修订”);
}
偏移量=4;
}否则{
偏移量=3;
}
//提取轮数
如果(盐[偏移量+2]>“$”){
抛出新的ArgumentException(“缺少盐回合”);
}
int rounds=Int32.Parse(salt.Substring(offset,2),NumberFormatInfo.InvariantInfo);
byte[]passwordBytes=Encoding.UTF8.GetBytes(password+(minor>='a'?“\0”:String.Empty));
字节[]saltBytes=DecodeBase64(salt.Substring(偏移量+3,22),
b crypt_SALT_LEN);
BCrypt BCrypt=新的BCrypt();
byte[]hashed=bcrypt.CryptRaw(passwordBytes、saltBytes、rounds);
StringBuilder rs=新的StringBuilder();
卢比(“$2”);
如果(次要>='a'){
卢比(小调);
}
rs.Append(“$”);
如果(轮数<10){
rs.Append('0');
}
卢比(轮);
rs.Append(“$”);
rs.Append(EncodeBase64(saltBytes,saltBytes.Length));
rs.Append(EncodeBase64)(散列,
(bf_crypt_ciphertext.Length*4)-1);
返回rs.ToString();
}

您不应该这样做。您只需确保BCrypt.Net生成的散列可以通过PHP库进行验证,反之亦然。Aron您能给我举个例子说明如何正确实现这一点吗?您的PHP脚本在散列到数据库中时必须使用不同的
密码\u SALT
,数据库散列看起来如何?(显示示例)因为我运行了您的脚本,所以它为BCrypt提供了完全相同的结果。如果数据库中
$2a$13$
后面的22个字符与
密码\u SALT
不同,则您有不同的SALT,您现在必须使用不同的SALT