如何在本地正确存储密码

我一直在MSDN上阅读这篇关于Rfc2898DeriveBytes的文章。 以下是它们提供的示例加密代码。

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(); 

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

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

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

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

如何在本地正确存储密码

只是不要这样做。 不是真的不这样做 。

……但如果你真的需要,不要自己实施。 我建议您查看ASP.NET Identity如何散列密码 。 版本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; } 

您应该将密码存储为单向散列和用于创建该密码的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不是Serializable。 其中DPAPI的重点。 有一些方法可以获取数据,但最终你必须跳出几个障碍才能完成。

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