Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ms-access/4.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
Hash 存储散列密码-base64、十六进制字符串或其他?_Hash_Base64 - Fatal编程技术网

Hash 存储散列密码-base64、十六进制字符串或其他?

Hash 存储散列密码-base64、十六进制字符串或其他?,hash,base64,Hash,Base64,我正在使用.NET System.Security.Cryptography类对密码进行哈希运算。 它有一些散列算法,例如MD5、SHA1、SHA256、SHA384、SHA512 结果散列值是一个字节数组。我应该将其转换为用于存储的十六进制字符串,还是转换为.ToBase64String(),或其他格式?(我喜欢Base64,因为它比十六进制短) 顺便说一句,有这么多的散列算法可供选择,我随机选择了SHA384,但是否有一个“更好”或适合该任务 请评论 阅读前八条评论后更新: 根据我所做的回答

我正在使用.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);