大家好我目前正在尝试匹配使用
的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哈希密码不匹配...
答案 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
还在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();
}