即使您的解决方案不是铁桶一样安全,也应该勤奋地实施盐加密。因为许多人会在其他地方重复使用他们的密码,如果攻击者选择将破解的密码数据库用于其他目的,入侵将对您的组织外部造成额外的损害。
盐加密使字典攻击变得更加昂贵。通过决定使用什么盐大小,您可以微调您的机会。以下是Bruce Schneier的"Applied Cryptography"中的引用:
“盐并非万能药;增加盐位数并不能解决所有问题。盐只能保护密码文件免受常规字典攻击,而无法防范针对单个密码的有计划攻击。它可以保护那些在多台机器上使用相同密码的人,但并不能使选择不当的密码更好。”
以下是C#的示例。这并不难。您可以选择要使用的盐大小和哈希函数。免责声明:如果您真的关心密码完整性,请使用
bcrypt之类的东西。
using System;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
public class PassHash {
private static readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
public static readonly int DefaultSaltSize = 8;
public readonly byte[] Salt;
public readonly byte[] Passhash;
internal PassHash(byte[] salt, byte[] passhash) {
Salt = salt;
Passhash = passhash;
}
public override String ToString() {
return String.Format("{{'salt': '{0}', 'passhash': '{1}'}}",
Convert.ToBase64String(Salt),
Convert.ToBase64String(Passhash));
}
public static PassHash Encode<HA>(String password) where HA : HashAlgorithm {
return Encode<HA>(password, DefaultSaltSize);
}
public static PassHash Encode<HA>(String password, int saltSize) where HA : HashAlgorithm {
return Encode<HA>(password, GenerateSalt(saltSize));
}
private static PassHash Encode<HA>(string password, byte[] salt) where HA : HashAlgorithm {
BindingFlags publicStatic = BindingFlags.Public | BindingFlags.Static;
MethodInfo hasher_factory = typeof (HA).GetMethod("Create", publicStatic, Type.DefaultBinder, Type.EmptyTypes, null);
using (HashAlgorithm hasher = (HashAlgorithm) hasher_factory.Invoke(null, null))
{
using (MemoryStream hashInput = new MemoryStream())
{
hashInput.Write(salt, 0, salt.Length);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
hashInput.Write(passwordBytes, 0, passwordBytes.Length);
hashInput.Seek(0, SeekOrigin.Begin);
byte[] passhash = hasher.ComputeHash(hashInput);
return new PassHash(salt, passhash);
}
}
}
private static byte[] GenerateSalt(int saltSize) {
byte[] salt = new byte[saltSize];
rng.GetBytes(salt);
return salt;
}
public static bool Verify<HA>(string password, byte[] salt, byte[] passhash) where HA : HashAlgorithm {
return Encode<HA>(password, salt).ToString() == new PassHash(salt, passhash).ToString();
}
}
用法:
新用户提交其凭据。
PassHash ph = PassHash.Encode<SHA384>(new_user_password);
将ph.Salt
和ph.Passhash
存储在某个地方...稍后,当用户再次登录时,您查找具有salt和passhash的用户记录,然后执行以下操作:
PassHash.Verify<SHA384>(user_login_password, user_rec.salt, user_rec.passhash)
}