[英]Security risks from trimming a salt
因此,我最近為與密碼相關的方法創建了一個靜態類,並且不得不創建一個生成安全鹽的方法。
最初,我實現了RNGCryptoServiceProvider
並將n個字節提交到數組中,然后將其轉換為base64並返回了。
問題在於輸出長度,當然經過轉換后比n長( 這很有意義 )。
為了解決這個問題,我將函數更改為下面的方法,我只是想知道通過修剪base64字符串是否會增加安全風險?
/// <summary>
/// Generates a salt for use with the Hash method.
/// </summary>
/// <param name="length">The length of string to generate.</param>
/// <returns>A cryptographically secure random salt.</returns>
public static string GenerateSalt(int length)
{
// Check the length isn't too short.
if (length < MIN_LENGTH)
{
throw new ArgumentOutOfRangeException("length", "Please increase the salt length to meet the minimum acceptable value of " + MIN_LENGTH + " characters.");
}
// Calculate the number of bytes required.
// https://en.wikipedia.org/wiki/Base64#Padding
// http://stackoverflow.com/questions/17944/how-to-round-up-the-result-of-integer-division
int bytelen = ((3 * length) + 4 - 1) / 4;
// Create our empty salt array.
byte[] bytes = new byte[bytelen];
// Where we'll put our generated salt.
string salt;
// Generate a random secure salt.
using (RNGCryptoServiceProvider randcrypto = new RNGCryptoServiceProvider())
{
// Fill our array with random bytes.
randcrypto.GetBytes(bytes);
// Get a base64 string from the random byte array.
salt = GetBase64(bytes);
}
// Trim the end off only if we need to.
if (salt.Length > length)
{
// Substring is the fastest method to use.
salt = salt.Substring(0, length);
}
// Return the salt.
return salt;
}
另外,作為一個附帶問題,我快速瀏覽了一下,但實際上找不到RNGCryptoServiceProvider
的C#
實現的哈希函數實際上是什么。 有人知道嗎?
為什么鹽的長度對您如此重要? 我不認為有任何真正的安全隱患,因為鹽的唯一真正要求是它是隨機且不可猜測的。
換句話說,去吧。
編輯:這是使用Linq的另一種方法。
Random random = new Random();
int length = 25; // Whatever length you want
char[] keys = "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890!£$%^&*()".ToCharArray(); // whatever chars you want
var salt = Enumerable
.Range(1, length) // equivalent to the loop bit, for(i.. )
.Select(k => keys[random.Next(0, keys.Length - 1)]) // generate a new random char
.Aggregate("", (e, c) => e + c); // join them together into a string
這種產生鹽的方式沒有安全風險。
Salt根本不需要那種安全級別,它就在那里,因此彩虹表不能用於破解哈希/加密。 常規的Random
類足以創建鹽。
例:
/// <summary>
/// Generates a salt for use with the Hash method.
/// </summary>
/// <param name="length">The length of string to generate.</param>
/// <returns>A random salt.</returns>
public static string GenerateSalt(int length) {
// Check the length isn't too short.
if (length < MIN_LENGTH) {
throw new ArgumentOutOfRangeException("length", "Please increase the salt length to meet the minimum acceptable value of " + MIN_LENGTH + " characters.");
}
// Where we'll put our generated salt.
StringBuilder salt = new StringBuilder(length);
// Fill our string with random characters.
Random rnd = new Random();
string chars = "0123456798ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < length; i++) {
salt.Append(chars[rnd.Next(chars.Length)]);
}
// Return the salt.
return salt.ToString();
}
注意:如果函數在關閉時間上使用了不止一次,則您將使用單個Random
對象並傳遞到函數中,因為在時間上創建得太近的Random
實例將給出相同的隨機序列。
只是為了好玩,這是一種更快的方法(即使代碼看起來不太好)。 嘗試將其剪切並粘貼以查看。 在我的機器上,它的執行時間約為7.1秒,而執行時間約為7.1秒。 由於在每種情況下我都要進行一百萬次迭代,因此我認為執行時間並不那么重要!
string msg = "";
int desiredLength = 93; // Length of salt required
Stopwatch watch = new Stopwatch();
watch.Start();
for (int k=0; k<1000000; k++)
{
double guidsNeeded = Math.Ceiling(desiredLength / 36.0);
string salt = "";
for (int i=0; i<guidsNeeded; i++)
{
salt += Guid.NewGuid().ToString();
}
salt = salt.Substring(0,desiredLength);
}
msg += watch.ElapsedMilliseconds.ToString(); // 1654 ms
watch.Start();
for (int j=0; j<1000000; j++)
{
GenerateSalt(93);
}
msg += "\r\n" + watch.ElapsedMilliseconds.ToString(); // 7096 ms
這是將Guffa的代碼用於GenerateSalt
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.