Get random seed for generating unique password

I have written a simple module which generates passwords fulfilling my complexity requirements.

Module PasswordGenerator
   Private ReadOnly _alphaChars As Char() = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToArray()
   Private ReadOnly _digitChars As Char() = "0123456789".ToArray()
   Private ReadOnly _nonAlphaNumChars As Char() = "_-.,:;!$%&/()[]=+#".ToArray()
   Private ReadOnly _allPswChars As Char() = _alphaChars.Concat(_digitChars).Concat(_nonAlphaNumChars).ToArray()

   Public Function GeneratePassword(length As Integer, minNonAlphaNum As Integer, minDigits As Integer) As String
      Return GeneratePassword(length, minNonAlphaNum, minDigits, New Random(GetSeed()))
   End Function

   Public Function GeneratePassword(length As Integer, minNonAlphaNum As Integer, minDigits As Integer, rnd As Random) As String
      Dim selectedChars As List(Of Char),
          psw As String,
          rndSelectedChar As Integer
      If length < (minNonAlphaNum + minDigits) Then Throw New ArgumentException
      selectedChars = New List(Of Char)(length)
      selectedChars.AddRange(GetRandomChars(_nonAlphaNumChars, minNonAlphaNum, rnd))
      selectedChars.AddRange(GetRandomChars(_digitChars, minDigits, rnd))
      selectedChars.AddRange(GetRandomChars(_allPswChars, (length - minNonAlphaNum - minDigits), rnd))
      psw = ""
      For i As Integer = 1 To selectedChars.Count
         rndSelectedChar = rnd.Next(0, selectedChars.Count)
         psw &= selectedChars(rndSelectedChar)
         selectedChars.RemoveAt(rndSelectedChar)
      Next
      Return psw
   End Function

   Private Function GetSeed() As Integer
      Dim guidString As String
      guidString = Guid.NewGuid().ToString("N").Substring(0, 5)
      Return Int32.Parse(guidString, Globalization.NumberStyles.HexNumber)
   End Function

   Private Function GetRandomChars(charRange As Char(), count As Integer, rnd As Random) As List(Of Char)
      Dim retVal As New List(Of Char),
          selectedPos As Integer

      If count < 1 Then Return retVal
      For i As Integer = 1 To count
         selectedPos = rnd.Next(0, charRange.Length)
         retVal.Add(charRange(selectedPos))
      Next

      Return retVal
   End Function
End Module

If I use this code without my GetSeed() function, I will get the same password many times if I generate passwords in a loop. By using the guid as random seed I can ensure not getting equal passwords, because the NewGuid function ensures not generating same guids. The system provided function to generate a guid ensures not getting same guids but is not made for generating random values in crypto environments because it is some kind of predictable (or more predictable than other functions - not predictable is not possible).

  • Would you recommend changing my code in any way?
  • Is there a better alternative for solving my problem?
  • Would a singleton random object be less predictable than using a guid as seed (this would ensure not getting same passwords too, I believe)?
Jon Skeet
people
quotationmark

Don't use Random at all for something as sensitive as this. Use RNGCryptoServiceProvider instead, which provides reasonably secure seeding.

It's not as simple an API to use as Random - you basically just get bytes, potentially guaranteed to be non-zero - but it's a more appropriate API.

people

See more on this question at Stackoverflow