@@ -13,33 +13,60 @@ protected RandomStringGenerator()
1313 }
1414
1515 /// <summary>
16- /// Creates a string with a cryptographically strong random sequence of characters.
16+ /// Creates a string with a cryptographically strong random sequence of 32 bytes (256 bits) converted to Base64.
17+ /// </summary>
18+ /// <param name="bytes">The generated cryptographically strong random sequence of bytes.</param>
19+ /// <returns>The generated cryptographically strong Base64 string.</returns>
20+ public static string GetBase64String ( out byte [ ] bytes )
21+ {
22+ return GetBase64String ( 256 / 8 , out bytes ) ;
23+ }
24+ /// <summary>
25+ /// Creates a string with a cryptographically strong random sequence of bytes converted to Base64.
26+ /// </summary>
27+ /// <param name="count">The number of bytes of random values to created.</param>
28+ /// <param name="bytes">The generated cryptographically strong random sequence of bytes.</param>
29+ /// <returns>The generated cryptographically strong Base64 string.</returns>
30+ public static string GetBase64String ( int count , out byte [ ] bytes )
31+ {
32+ bytes = RandomNumberGenerator . GetBytes ( count ) ;
33+ return Convert . ToBase64String ( bytes ) ;
34+ }
35+
36+ /// <summary>
37+ /// Creates a string with a cryptographically strong random sequence of characters. The characters will be selected randomly in the following string:
38+ /// <br />!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
1739 /// </summary>
1840 /// <param name="count">The number of characters of random values to create. Defaults to 32 characters (256 bits).</param>
1941 /// <returns>A string populated with cryptographically strong random characters.</returns>
2042 public static string GetString ( int count = 256 / 8 )
2143 {
22- while ( true )
44+ return GetString ( "!\" #$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\ ]^_`abcdefghijklmnopqrstuvwxyz{|}~" , count ) ;
45+ }
46+ /// <summary>
47+ /// Creates a string with a cryptographically strong random sequence of characters from the specified list of characters.
48+ /// </summary>
49+ /// <param name="characters">The list of characters to pick from.</param>
50+ /// <param name="count">The number of characters of random values to create. Defaults to 32 characters (256 bits).</param>
51+ /// <returns>A string populated with cryptographically strong random characters.</returns>
52+ /// <exception cref="ArgumentException">The list of characters contains more than 256 characters.</exception>
53+ public static string GetString ( string characters , int count = 256 / 8 )
54+ {
55+ const int MaximumLength = byte . MaxValue + 1 ;
56+ if ( characters . Length > MaximumLength )
2357 {
24- /* In the ASCII table, there are 94 characters between 33 '!' and 126 '~' (126 - 33 + 1 = 94).
25- * Since there are a total of 256 possibilities, by dividing per 94 and adding a 10% margin we
26- * generate just a little more bytes than required, obtaining the factor 3. */
27- byte [ ] bytes = RandomNumberGenerator . GetBytes ( count * 3 ) ;
58+ throw new ArgumentException ( $ "A maximum of { MaximumLength } characters must be provided.", nameof ( characters ) ) ;
59+ }
2860
29- List < byte > secret = new ( capacity : count ) ;
30- for ( int i = 0 ; i < bytes . Length ; i ++ )
31- {
32- byte @byte = bytes [ i ] ;
33- if ( @byte >= 33 && @byte <= 126 )
34- {
35- secret . Add ( @byte ) ;
61+ char [ ] s = new char [ count ] ;
3662
37- if ( secret . Count == count )
38- {
39- return Encoding . ASCII . GetString ( secret . ToArray ( ) ) ;
40- }
41- }
42- }
63+ byte [ ] bytes = RandomNumberGenerator . GetBytes ( s . Length ) ;
64+ for ( int i = 0 ; i < bytes . Length ; i ++ )
65+ {
66+ // NOTE(fpion): pick a character from the specified list using the randomly generated bytes and assign it to the generated password.
67+ s [ i ] = characters [ bytes [ i ] % characters . Length ] ;
4368 }
69+
70+ return new string ( s ) ;
4471 }
4572}
0 commit comments