Hash 存储散列密码-base64、十六进制字符串或其他?
我正在使用.NET System.Security.Cryptography类对密码进行哈希运算。 它有一些散列算法,例如MD5、SHA1、SHA256、SHA384、SHA512 结果散列值是一个字节数组。我应该将其转换为用于存储的十六进制字符串,还是转换为.ToBase64String(),或其他格式?(我喜欢Base64,因为它比十六进制短) 顺便说一句,有这么多的散列算法可供选择,我随机选择了SHA384,但是否有一个“更好”或适合该任务 请评论 阅读前八条评论后更新:Hash 存储散列密码-base64、十六进制字符串或其他?,hash,base64,Hash,Base64,我正在使用.NET System.Security.Cryptography类对密码进行哈希运算。 它有一些散列算法,例如MD5、SHA1、SHA256、SHA384、SHA512 结果散列值是一个字节数组。我应该将其转换为用于存储的十六进制字符串,还是转换为.ToBase64String(),或其他格式?(我喜欢Base64,因为它比十六进制短) 顺便说一句,有这么多的散列算法可供选择,我随机选择了SHA384,但是否有一个“更好”或适合该任务 请评论 阅读前八条评论后更新: 根据我所做的回答
根据我所做的回答和进一步阅读,MD5和SHA1似乎或多或少是等效的(SHA1稍微安全一些)。SHA256384512以递增的顺序提供了更好的安全性 由于我不需要fort knox(这是针对一个没有URL、浏览器、Internet、内部网或外部网的内部公司系统),我将绕过“盐碱”业务——我想如果有人可以窃取密码表,他们也可以窃取其他表中的实际数据 但我会保留“盐”的概念,以备将来参考;不确定在散列之前是应该在密码的末尾添加salt还是在密码的前面添加salt,这会有所不同吗?我也在考虑使用密码本身的前几个字符作为salt,以避免额外的字段来存储它,但我想它不够长,salt应该足够长 一致认为base64转换是存储和比较的合理选择。考虑到最大密码长度为15个字符,我需要找出散列存储所需的最大数据库列长度。也许是瓦查尔(64岁)
感谢大家的贡献。您也可以将其转换为普通字节。因此,128位MD5散列值将产生128位/8位/byte=16字节长的字符串。Base64确实比十六进制短,但有一点缺点,即如果它最终出现在URL中(由于涉及的符号),则需要小心。基本上,这取决于你在哪里使用它。Hex通常有一个优点,即用肉眼更容易“读取”,但由于这实际上是无意义的数据,因此与散列无关。(如有必要,您始终可以使用在线base64解码。) 当然,这都是假设您想要一个字符串。与不透明字节数组相比,字符串很好,易于存储、传输等 顺便说一句,有这么多的散列算法可供选择,我随机选择了SHA384,但是否有一个“更好”或适合该任务
一般来说,我会避免MD5或SHA-0或SHA-1。但目前SHA-384应该足以满足您的需求。有关算法的一些讨论,请参阅。我以前看到的有趣的注意事项,如果您有一个字节数组,并且使用base64编码,则产生的一些字符可能会在URL中引起问题-但是,如果您再次使用base64编码,则这些有问题的字符往往会被删除,并且base64字符串可以在URL中使用。您可以使用双编码字符串进行比较
在散列算法方面,sha384可能是一个足够的算法,但请确保您对散列进行了加密 对于密码,我相信它们中的任何一个都能提供完美的服务。SHA 512将创建一个更高的密钥,减少“冲突”的可能性,因为它知道不同的密码可能具有相同的哈希值,但可能性非常低。回答问题的第二部分,SHA384可能有些过分。SHA1可以很好地满足您的需求,但它有一个理论上的漏洞(与能够创建一个哈希值相同的篡改文档有关,无需担心) 如果你不这么做,确保在散列密码之前先对密码进行加密,以防止更常见的黑客攻击(识别类似密码、彩虹表等)。更多信息请阅读本文
顺便说一句,我喜欢Base64,因为.NET有内置的转换例程。答案取决于您可能拥有的上下文和约束。Base64将更加紧凑,但与十六进制编码相比,生成Base64的计算成本要高一些 你应该在散列数据中添加一个盐。它是一个随机值,放在散列的pasword前面。然后将salt值与散列值一起存储,以便可以重新生成散列值 此salt的作用是防止构建常用密码到散列值的字典映射。如果有人可以得到你的散列密码文件的副本,他可以使用这个字典来查找明文密码。使用16位salt,同一明文密码有65536个不同的哈希值。措辞攻击的效率会降低。最好选择64位的salt,因为它不会在散列和验证密码方面增加太多工作 您还应该添加一个带有散列值的魔法字节序列(常量字节序列)。攻击者必须知道这个神奇的字节序列,才能生成适当的哈希值。因此,如果它只有一个哈希密码文件,他不会走得太远。他需要得到一个神奇的单词,这个单词很可能会埋在你的代码中的某个地方
关于算法,使用SHA1是非常好的,SH256将是皮带和皮带。MD5的计算成本要低得多,可以满足大多数用例。如果您的处理和存储资源可能是一个限制因素,请考虑这一点。p> 我会使用Base64。。。。哦,如果你正在哈希的是密码,别忘了给你的哈希加盐:)如果我们谈论密码,任何比SHA384小的东西都是一个安全风险,因为很容易为SHA1和其他常见哈希算法获得高质量的彩虹表。即使你的解决方案不是fort knox,你也应该勤勉地实施加盐。贝科
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; // 64-bit salt
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) {
// This generates salt.
// Rephrasing Schneier:
// "salt" is a random string of bytes that is
// combined with password bytes before being
// operated by the one-way function.
byte[] salt = new byte[saltSize];
rng.GetBytes(salt);
return salt;
}
public static bool Verify<HA>(string password, byte[] salt, byte[] passhash) where HA : HashAlgorithm {
// OMG: I don't know how to compare byte arrays in C#.
return Encode<HA>(password, salt).ToString() == new PassHash(salt, passhash).ToString();
}
}
BigInteger hexNumber = new BigInteger(hexString, 16);
// Convert it to Base 36 yields smaller string than hexString
hexNumber.toString(36);
BigInteger b36String= new BigInteger(b36String, 36);
// Convert it to Base 16 yields original hex string
hexNumber.toString(16);