如何在本地正确存储密码

时间:2015-10-26 21:11:57

标签: c# encryption

我已经在Rfc2898DeriveBytes上从MSDN上阅读了这篇文章。以下是他们提供的示例加密代码。

string pwd1 = passwordargs[0];
// Create a byte array to hold the random value. 
byte[] salt1 = new byte[8];
using (RNGCryptoServiceProvider rngCsp = ne RNGCryptoServiceProvider())
{
    // Fill the array with a random value.
    rngCsp.GetBytes(salt1);
}

//data1 can be a string or contents of a file.
string data1 = "Some test data";
//The default iteration count is 1000 so the two methods use the same iteration count.
int myIterations = 1000;
try
{
    Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1,salt1,myIterations);
    Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(pwd1, salt1);
    // Encrypt the data.
    TripleDES encAlg = TripleDES.Create();
    encAlg.Key = k1.GetBytes(16);
    MemoryStream encryptionStream = new MemoryStream();
    CryptoStream encrypt = newCryptoStream(encryptionStream, encAlg.CreateEncryptor(), CryptoStreamMode.Write);
    byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(data1);

    encrypt.Write(utfD1, 0, utfD1.Length);
    encrypt.FlushFinalBlock();
    encrypt.Close();
    byte[] edata1 = encryptionStream.ToArray();
    k1.Reset();

我的问题是,如何正确地将散列数据读/写到文本文件?

我的主要目标是做developer正在做的事情。我需要在本地存储密码。当我的应用程序提示用户输入密码时,用户将输入密码,然后我的应用程序将从文本文件中读取并验证用户输入的密码是否确实正确。我该怎么做呢?

3 个答案:

答案 0 :(得分:5)

您通常存储密码的哈希值,然后当用户输入密码时,您计算输入密码的哈希值并将其与存储的哈希值进行比较 - 也就是说,只是哈希值通常不够(从安全角度来看)并且您应该使用诸如PKBDF2(基于密码的密钥派生函数2)之类的函数。以下文章以更详细的方式介绍了所有信息以及示例代码(页面底部):http://www.codeproject.com/Articles/704865/Salted-Password-Hashing-Doing-it-Right

以下是codereview的链接,我想这与上面的文章相同。

答案 1 :(得分:5)

  

如何在本地正确存储密码

不要这样做。 No really don't do it

...但如果你真的需要,不要自己实施。我建议您查看ASP.NET Identity hashes passwords的方式。版本3目前非常稳固:

请注意,以下内容取自github.com,可能随时更改。有关最新信息,请参阅上一个链接。

private static byte[] HashPasswordV3(string password, RandomNumberGenerator rng, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested)
    {
        // Produce a version 3 (see comment above) text hash.
        byte[] salt = new byte[saltSize];
        rng.GetBytes(salt);
        byte[] subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested);

        var outputBytes = new byte[13 + salt.Length + subkey.Length];
        outputBytes[0] = 0x01; // format marker
        WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
        WriteNetworkByteOrder(outputBytes, 5, (uint)iterCount);
        WriteNetworkByteOrder(outputBytes, 9, (uint)saltSize);
        Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
        Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
        return outputBytes;
    }

答案 2 :(得分:2)

您应该将密码存储为单向哈希以及用于创建该密码的salt。这样,您绝对可以确保用户的密码永远不会被解密。切勿对此特定任务使用任何双向加密,因为您可能会将用户信息暴露给潜在的攻击者。

void Main()
{
    string phrase, salt, result;
    phrase = "test";
    result = Sha256Hash(phrase, out salt);

    Sha256Compare(phrase, result, salt);
}

public string Sha256Hash(string phrase, out string salt)
{
    salt = Create256BitSalt();
    string saltAndPwd = String.Concat(phrase, salt);
    Encoding encoder = Encoding.Default;
    SHA256Managed sha256hasher = new SHA256Managed();
    byte[] hashedDataBytes = sha256hasher.ComputeHash(encoder.GetBytes(saltAndPwd));
    string hashedPwd = Encoding.Default.GetString(hashedDataBytes);
    return hashedPwd;
}

public bool Sha256Compare(string phrase, string hash, string salt)
{
    string saltAndPwd = String.Concat(phrase, salt);
    Encoding encoder = Encoding.Default;
    SHA256Managed sha256hasher = new SHA256Managed();
    byte[] hashedDataBytes = sha256hasher.ComputeHash(encoder.GetBytes(saltAndPwd));
    string hashedPwd = Encoding.Default.GetString(hashedDataBytes);
    return string.Compare(hash, hashedPwd, false) == 0;
}

public string Create256BitSalt()
{
    int _saltSize = 32;
    byte[] ba = new byte[_saltSize];
    RNGCryptoServiceProvider.Create().GetBytes(ba);
    return Encoding.Default.GetString(ba);
}

你也可以找出获得盐的另一种方法,但我已经知道它计算了2048位的随机数据。您可以使用随机生成的长时间,但安全性会低得多。您无法使用SecureString,因为SecureString不可序列化。其中DPAPI的重点。有一些方法可以获取数据,但最终你必须跳出几个障碍才能完成。

FWIW,PBKDF2(基于密码的密钥派生函数2)与SHA256基本相同,只是速度较慢(一件好事)。就其本身而言都非常安全。如果您将PBKDF2与SHA256结合起来作为您的盐,那么您将拥有一个非常安全的系统。