History

GSF.Core: 1) Fixed an issue with the cryptographically strong random number generator where there was a 1 in 4 billion chance it would generate the maximum number in the specified range of numbers. 2) Modified CollectionExtensions.Scramble() overloads to allow scrambling of arrays. 3) Added the PasswordGenerator class to allow customized random password generation.

GSF.Security: Updated SecurityProviderUtility.GeneratePassword to use the PasswordGenerator class. GSF.InstallerActions: Added a custom action to generate a random password.

StephenCWills committed 11 years ago

Commit ebbecae1 parent cf7845b8 files · +379 −80Browse files

Unified · Split

8 files
  1. Source/Libraries/GSF.Core/Collections/CollectionExtensions.cs +3 −3
  2. Source/Libraries/GSF.Core/GSF.Core.csproj +2 −0
  3. Source/Libraries/GSF.Core/Security/Cryptography/CharacterGroup.cs +115 −0
  4. Source/Libraries/GSF.Core/Security/Cryptography/PasswordGenerator.cs +195 −0
  5. Source/Libraries/GSF.Core/Security/Cryptography/Random.cs +38 −38
  6. Source/Libraries/GSF.InstallerActions/CustomActions.cs +23 −0
  7. Source/Libraries/GSF.InstallerActions/GSF.InstallerActions.csproj +1 −0
  8. Source/Libraries/GSF.Security/SecurityProviderUtility.cs +2 −39
Source/Libraries/GSF.Core/Collections/CollectionExtensions.cs+3−3
@@ -790,7 +790,7 @@ namespace GSF.Collections · 789 unmodified lines
790790 /// <remarks>This function uses a cryptographically strong random number generator to perform the scramble.</remarks>
791791 public static void Scramble<TSource>(this IList<TSource> source)
792792 {
793− if (source.IsReadOnly)
793+ if (source.IsReadOnly && !(source is TSource[]))
794794 throw new ArgumentException("Cannot modify items in a read only list");
795795
796796 int x, y;
@@ -821,7 +821,7 @@ namespace GSF.Collections · 24 unmodified lines
821821 /// <remarks>This function uses the <see cref="System.Random"/> generator to perform the scramble using a sequence that is repeatable.</remarks>
822822 public static void Scramble<TSource>(this IList<TSource> source, int seed)
823823 {
824− if (source.IsReadOnly)
824+ if (source.IsReadOnly && !(source is TSource[]))
825825 throw new ArgumentException("Cannot modify items in a read only list");
826826
827827 System.Random random = new System.Random(seed);
@@ -852,7 +852,7 @@ namespace GSF.Collections · 24 unmodified lines
852852 /// <remarks>This function uses the <see cref="System.Random"/> generator to perform the unscramble using a sequence that is repeatable.</remarks>
853853 public static void Unscramble<TSource>(this IList<TSource> source, int seed)
854854 {
855− if (source.IsReadOnly)
855+ if (source.IsReadOnly && !(source is TSource[]))
856856 throw new ArgumentException("Cannot modify items in a read only list");
857857
858858 System.Random random = new System.Random(seed);
Source/Libraries/GSF.Core/GSF.Core.csproj+2−0
@@ -361,7 +361,9 @@ · 360 unmodified lines
361361 <Compile Include="ReusableObjectPool.cs" />
362362 <Compile Include="Scheduling\NamespaceDoc.cs" />
363363 <Compile Include="Searching\AsyncSearcher.cs" />
364+ <Compile Include="Security\Cryptography\CharacterGroup.cs" />
364365 <Compile Include="Security\Cryptography\NamespaceDoc.cs" />
366+ <Compile Include="Security\Cryptography\PasswordGenerator.cs" />
365367 <Compile Include="Security\Cryptography\Random.cs" />
366368 <Compile Include="Reflection\AssemblyExtensions.cs" />
367369 <Compile Include="Reflection\AssemblyInfo.cs" />
Source/Libraries/GSF.Core/Security/Cryptography/CharacterGroup.cs+115−0
@@ -0,0 +1,115 @@
1+//******************************************************************************************************
2+// CharacterGroup.cs - Gbtc
3+//
4+// Copyright © 2015, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://opensource.org/licenses/MIT
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 10/27/2015 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+using System;
25+
26+namespace GSF.Security.Cryptography
27+{
28+ /// <summary>
29+ /// Defines a group of characters that can
30+ /// appear in an automatically generated password.
31+ /// </summary>
32+ public class CharacterGroup
33+ {
34+ #region [ Members ]
35+
36+ // Fields
37+ private string m_characters;
38+ private int m_minOccurrence;
39+
40+ #endregion
41+
42+ #region [ Constructors ]
43+
44+ /// <summary>
45+ /// Creates a new instance of the <see cref="CharacterGroup"/> class.
46+ /// </summary>
47+ public CharacterGroup()
48+ : this(" ")
49+ {
50+ }
51+
52+ /// <summary>
53+ /// Creates a new instance of the <see cref="CharacterGroup"/> class.
54+ /// </summary>
55+ /// <param name="characters">String representing the characters in the character group.</param>
56+ public CharacterGroup(string characters)
57+ : this(characters, 0)
58+ {
59+ }
60+
61+ /// <summary>
62+ /// Creates a new instance of the <see cref="CharacterGroup"/> class.
63+ /// </summary>
64+ /// <param name="characters">String representing the characters in the character group.</param>
65+ /// <param name="minOccurrence">The minimum number of occurrences of this character group in the password.</param>
66+ public CharacterGroup(string characters, int minOccurrence)
67+ {
68+ Characters = characters;
69+ MinOccurrence = minOccurrence;
70+ }
71+
72+ #endregion
73+
74+ #region [ Properties ]
75+
76+ /// <summary>
77+ /// The collection of characters in the character group.
78+ /// </summary>
79+ public string Characters
80+ {
81+ get
82+ {
83+ return m_characters;
84+ }
85+ set
86+ {
87+ if (string.IsNullOrEmpty(value))
88+ throw new ArgumentException("Character group must have at least one character.", nameof(value));
89+
90+ m_characters = value;
91+ }
92+ }
93+
94+ /// <summary>
95+ /// The minimum number of occurrences of any of the
96+ /// characters in this character group in the password.
97+ /// </summary>
98+ public int MinOccurrence
99+ {
100+ get
101+ {
102+ return m_minOccurrence;
103+ }
104+ set
105+ {
106+ if (value < 0)
107+ throw new ArgumentOutOfRangeException(nameof(value));
108+
109+ m_minOccurrence = value;
110+ }
111+ }
112+
113+ #endregion
114+ }
115+}
Source/Libraries/GSF.Core/Security/Cryptography/PasswordGenerator.cs+195−0
@@ -0,0 +1,195 @@
1+//******************************************************************************************************
2+// PasswordGenerator.cs - Gbtc
3+//
4+// Copyright © 2015, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://opensource.org/licenses/MIT
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 10/27/2015 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+using System;
25+using System.Collections.Generic;
26+using System.Linq;
27+using GSF.Collections;
28+
29+namespace GSF.Security.Cryptography
30+{
31+ /// <summary>
32+ /// Generates random passwords.
33+ /// </summary>
34+ public class PasswordGenerator
35+ {
36+ #region [ Members ]
37+
38+ // Fields
39+ private List<CharacterGroup> m_characterGroups;
40+
41+ #endregion
42+
43+ #region [ Constructors ]
44+
45+ /// <summary>
46+ /// Creates a new instance of the <see cref="PasswordGenerator"/> class.
47+ /// </summary>
48+ public PasswordGenerator()
49+ : this(DefaultCharacterGroups)
50+ {
51+ }
52+
53+ /// <summary>
54+ /// Creates a new instance of the <see cref="PasswordGenerator"/> class.
55+ /// </summary>
56+ /// <param name="characterGroups">The list of character groups used to generate passwords.</param>
57+ public PasswordGenerator(IEnumerable<CharacterGroup> characterGroups)
58+ {
59+ m_characterGroups = new List<CharacterGroup>(characterGroups);
60+ }
61+
62+ #endregion
63+
64+ #region [ Properties ]
65+
66+ /// <summary>
67+ /// Gets the collection of character groups used by this <see cref="PasswordGenerator"/>.
68+ /// </summary>
69+ public List<CharacterGroup> CharacterGroups
70+ {
71+ get
72+ {
73+ return m_characterGroups;
74+ }
75+ }
76+
77+ /// <summary>
78+ /// Gets a string representing the total collection
79+ /// of characters across all character groups.
80+ /// </summary>
81+ public string AllCharacters
82+ {
83+ get
84+ {
85+ return new string(m_characterGroups
86+ .SelectMany(characterGroup => characterGroup.Characters)
87+ .ToArray());
88+ }
89+ }
90+
91+ /// <summary>
92+ /// Gets the absolute minimum length of password that can be
93+ /// generated by the <see cref="PasswordGenerator"/> based
94+ /// on the minimum occurrence of each character group.
95+ /// </summary>
96+ public int MinLength
97+ {
98+ get
99+ {
100+ return m_characterGroups.Sum(characterGroup => characterGroup.MinOccurrence);
101+ }
102+ }
103+
104+ #endregion
105+
106+ #region [ Methods ]
107+
108+ /// <summary>
109+ /// Generates a random password with 8 characters or
110+ /// <see cref="MinLength"/> if it is greater than 8 characters.
111+ /// </summary>
112+ /// <returns>A randomly generated password.</returns>
113+ public string GeneratePassword()
114+ {
115+ return GeneratePassword(Math.Max(8, MinLength));
116+ }
117+
118+ /// <summary>
119+ /// Generates a password with length between the given
120+ /// <paramref name="minLength"/> and <paramref name="maxLength"/>.
121+ /// </summary>
122+ /// <param name="minLength">The minimum length of the generated password.</param>
123+ /// <param name="maxLength">The maximum length of the generated password.</param>
124+ /// <returns>A randomly generated password.</returns>
125+ public string GeneratePassword(int minLength, int maxLength)
126+ {
127+ if (minLength > maxLength)
128+ throw new ArgumentException("minLength must be less than or equal to maxLength");
129+
130+ return GeneratePassword(Random.Int32Between(minLength, maxLength + 1));
131+ }
132+
133+ /// <summary>
134+ /// Generates a password with the given length.
135+ /// </summary>
136+ /// <param name="length">The length of the password to be generated.</param>
137+ /// <returns>A randomly generated password.</returns>
138+ public string GeneratePassword(int length)
139+ {
140+ List<CharacterGroup> characterGroups;
141+ char[] passwordChars;
142+
143+ if (length < MinLength)
144+ throw new ArgumentOutOfRangeException(nameof(length), $"The length of the generated password must be at least {MinLength} characters.");
145+
146+ // Create a collection of character groups the size of the password to be generated.
147+ // The number of times a character group appears in this collection is equal to the
148+ // minimum number of occurrences of that character group. An AllCharacters group is
149+ // created to fill in the characters not accounted for by the other character groups.
150+ characterGroups = m_characterGroups
151+ .SelectMany(characterGroup => Enumerable.Repeat(characterGroup, characterGroup.MinOccurrence))
152+ .Concat(Enumerable.Repeat(new CharacterGroup(AllCharacters), length - MinLength))
153+ .ToList();
154+
155+ passwordChars = new char[length];
156+
157+ for (int i = 0; i < length; i++)
158+ {
159+ // Pull a random character from the character group into the password
160+ CharacterGroup characterGroup = characterGroups[i];
161+ int index = Random.Int32Between(0, characterGroup.Characters.Length);
162+ passwordChars[i] = characterGroup.Characters[index];
163+ }
164+
165+ // Scramble the generated set of characters
166+ passwordChars.Scramble();
167+
168+ return new string(passwordChars);
169+ }
170+
171+ #endregion
172+
173+ #region [ Static ]
174+
175+ // Static Fields
176+
177+ /// <summary>
178+ /// Default set of character groups used by the <see cref="PasswordGenerator"/>.
179+ /// </summary>
180+ public static readonly IReadOnlyList<CharacterGroup> DefaultCharacterGroups = new List<CharacterGroup>()
181+ {
182+ new CharacterGroup() { Characters = "abcdefghijklmnopqrstuvwxyz", MinOccurrence = 1 },
183+ new CharacterGroup() { Characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", MinOccurrence = 1 },
184+ new CharacterGroup() { Characters = "0123456789", MinOccurrence = 1 },
185+ new CharacterGroup() { Characters = "~!@#$%^&*-_=+;:,.?", MinOccurrence = 1 }
186+ };
187+
188+ /// <summary>
189+ /// Defines the default password generator.
190+ /// </summary>
191+ public static readonly PasswordGenerator Default = new PasswordGenerator();
192+
193+ #endregion
194+ }
195+}
Source/Libraries/GSF.Core/Security/Cryptography/Random.cs+38−38
@@ -39,19 +39,19 @@ namespace GSF.Security.Cryptography · 38 unmodified lines
3939 /// </summary>
4040 public static class Random
4141 {
42− private static readonly RNGCryptoServiceProvider s_randomNumberGenerator = new RNGCryptoServiceProvider();
42+ private static readonly RNGCryptoServiceProvider RandomNumberGenerator = new RNGCryptoServiceProvider();
4343
4444 /// <summary>
4545 /// Generates a cryptographically strong double-precision floating-point random number between zero and one.
4646 /// </summary>
47− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
47+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
4848 public static double Number
4949 {
5050 get
5151 {
5252 unchecked
5353 {
54− return (double)UInt32 / (double)uint.MaxValue;
54+ return UInt32 / (uint.MaxValue + 1.0D);
5555 }
5656 }
5757 }
@@ -59,14 +59,14 @@ namespace GSF.Security.Cryptography · 1 unmodified line
5959 /// <summary>
6060 /// Generates a cryptographically strong random decimal between zero and one.
6161 /// </summary>
62− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
62+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
6363 public static decimal Decimal
6464 {
6565 get
6666 {
6767 unchecked
6868 {
69− return (decimal)UInt64 / (decimal)ulong.MaxValue;
69+ return UInt64 / (ulong.MaxValue + 1.0M);
7070 }
7171 }
7272 }
@@ -76,7 +76,7 @@ namespace GSF.Security.Cryptography · 3 unmodified lines
7676 /// </summary>
7777 /// <param name="startNumber">A <see cref="double"/> that is the low end of our range.</param>
7878 /// <param name="stopNumber">A <see cref="double"/> that is the high end of our range.</param>
79− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
79+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
8080 /// <returns>A <see cref="double"/> that is generated between the <paramref name="startNumber"/> and the <paramref name="stopNumber"/>, or an excception.</returns>
8181 public static double Between(double startNumber, double stopNumber)
8282 {
@@ -94,24 +94,24 @@ namespace GSF.Security.Cryptography · 11 unmodified lines
9494 /// <para>The length of the byte array determines how many cryptographically strong random bytes are produced.</para>
9595 /// <para>This method is thread safe.</para>
9696 /// </remarks>
97− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
98− /// <exception cref="System.ArgumentNullException">buffer is null.</exception>
97+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
98+ /// <exception cref="ArgumentNullException">buffer is null.</exception>
9999 public static void GetBytes(byte[] buffer)
100100 {
101− s_randomNumberGenerator.GetBytes(buffer);
101+ RandomNumberGenerator.GetBytes(buffer);
102102 }
103103
104104 /// <summary>
105105 /// Generates a cryptographically strong random boolean (i.e., a coin toss).
106106 /// </summary>
107− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
107+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
108108 public static bool Boolean
109109 {
110110 get
111111 {
112112 byte[] value = new byte[1];
113113
114− s_randomNumberGenerator.GetBytes(value);
114+ RandomNumberGenerator.GetBytes(value);
115115
116116 return value[0] % 2 == 0;
117117 }
@@ -120,14 +120,14 @@ namespace GSF.Security.Cryptography · 2 unmodified lines
120120 /// <summary>
121121 /// Generates a cryptographically strong 8-bit random integer.
122122 /// </summary>
123− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
123+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
124124 public static byte Byte
125125 {
126126 get
127127 {
128128 byte[] value = new byte[1];
129129
130− s_randomNumberGenerator.GetBytes(value);
130+ RandomNumberGenerator.GetBytes(value);
131131
132132 return value[0];
133133 }
@@ -136,7 +136,7 @@ namespace GSF.Security.Cryptography · 2 unmodified lines
136136 /// <summary>
137137 /// Generates a cryptographically strong 8-bit random integer between specified values.
138138 /// </summary>
139− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
139+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
140140 /// <param name="startNumber">A <see cref="byte"/> that is the low end of our range.</param>
141141 /// <param name="stopNumber">A <see cref="byte"/> that is the high end of our range.</param>
142142 /// <returns>A <see cref="byte"/> that is generated between the <paramref name="startNumber"/> and the <paramref name="stopNumber"/>.</returns>
@@ -151,14 +151,14 @@ namespace GSF.Security.Cryptography · 8 unmodified lines
151151 /// <summary>
152152 /// Generates a cryptographically strong 16-bit random integer.
153153 /// </summary>
154− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
154+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
155155 public static short Int16
156156 {
157157 get
158158 {
159159 byte[] value = new byte[2];
160160
161− s_randomNumberGenerator.GetBytes(value);
161+ RandomNumberGenerator.GetBytes(value);
162162
163163 return BitConverter.ToInt16(value, 0);
164164 }
@@ -167,7 +167,7 @@ namespace GSF.Security.Cryptography · 2 unmodified lines
167167 /// <summary>
168168 /// Generates a cryptographically strong 16-bit random integer between specified values.
169169 /// </summary>
170− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
170+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
171171 /// <param name="startNumber">A <see cref="short"/> that is the low end of our range.</param>
172172 /// <param name="stopNumber">A <see cref="short"/> that is the high end of our range.</param>
173173 /// <returns>A <see cref="short"/> that is generated between the <paramref name="startNumber"/> and the <paramref name="stopNumber"/>.</returns>
@@ -182,14 +182,14 @@ namespace GSF.Security.Cryptography · 8 unmodified lines
182182 /// <summary>
183183 /// Generates a cryptographically strong unsigned 16-bit random integer.
184184 /// </summary>
185− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
185+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
186186 public static ushort UInt16
187187 {
188188 get
189189 {
190190 byte[] value = new byte[2];
191191
192− s_randomNumberGenerator.GetBytes(value);
192+ RandomNumberGenerator.GetBytes(value);
193193
194194 return BitConverter.ToUInt16(value, 0);
195195 }
@@ -198,7 +198,7 @@ namespace GSF.Security.Cryptography · 2 unmodified lines
198198 /// <summary>
199199 /// Generates a cryptographically strong unsigned 16-bit random integer between specified values.
200200 /// </summary>
201− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
201+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
202202 /// <param name="startNumber">A <see cref="ushort"/> that is the low end of our range.</param>
203203 /// <param name="stopNumber">A <see cref="ushort"/> that is the high end of our range.</param>
204204 /// <returns>A <see cref="ushort"/> that is generated between the <paramref name="startNumber"/> and the <paramref name="stopNumber"/>.</returns>
@@ -213,14 +213,14 @@ namespace GSF.Security.Cryptography · 8 unmodified lines
213213 /// <summary>
214214 /// Generates a cryptographically strong 24-bit random integer.
215215 /// </summary>
216− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
216+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
217217 public static Int24 Int24
218218 {
219219 get
220220 {
221221 byte[] value = new byte[3];
222222
223− s_randomNumberGenerator.GetBytes(value);
223+ RandomNumberGenerator.GetBytes(value);
224224
225225 return Int24.GetValue(value, 0);
226226 }
@@ -229,7 +229,7 @@ namespace GSF.Security.Cryptography · 2 unmodified lines
229229 /// <summary>
230230 /// Generates a cryptographically strong 24-bit random integer between specified values.
231231 /// </summary>
232− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
232+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
233233 /// <param name="startNumber">A <see cref="Int24"/> that is the low end of our range.</param>
234234 /// <param name="stopNumber">A <see cref="Int24"/> that is the high end of our range.</param>
235235 /// <returns>A <see cref="Int24"/> that is generated between the <paramref name="startNumber"/> and the <paramref name="stopNumber"/>.</returns>
@@ -244,14 +244,14 @@ namespace GSF.Security.Cryptography · 8 unmodified lines
244244 /// <summary>
245245 /// Generates a cryptographically strong unsigned 24-bit random integer.
246246 /// </summary>
247− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
247+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
248248 public static UInt24 UInt24
249249 {
250250 get
251251 {
252252 byte[] value = new byte[3];
253253
254− s_randomNumberGenerator.GetBytes(value);
254+ RandomNumberGenerator.GetBytes(value);
255255
256256 return UInt24.GetValue(value, 0);
257257 }
@@ -260,7 +260,7 @@ namespace GSF.Security.Cryptography · 2 unmodified lines
260260 /// <summary>
261261 /// Generates a cryptographically strong unsigned 24-bit random integer between specified values.
262262 /// </summary>
263− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
263+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
264264 /// <param name="startNumber">A <see cref="UInt24"/> that is the low end of our range.</param>
265265 /// <param name="stopNumber">A <see cref="UInt24"/> that is the high end of our range.</param>
266266 /// <returns>A <see cref="UInt24"/> that is generated between the <paramref name="startNumber"/> and the <paramref name="stopNumber"/>.</returns>
@@ -275,14 +275,14 @@ namespace GSF.Security.Cryptography · 8 unmodified lines
275275 /// <summary>
276276 /// Generates a cryptographically strong 32-bit random integer.
277277 /// </summary>
278− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
278+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
279279 public static int Int32
280280 {
281281 get
282282 {
283283 byte[] value = new byte[4];
284284
285− s_randomNumberGenerator.GetBytes(value);
285+ RandomNumberGenerator.GetBytes(value);
286286
287287 return BitConverter.ToInt32(value, 0);
288288 }
@@ -291,7 +291,7 @@ namespace GSF.Security.Cryptography · 2 unmodified lines
291291 /// <summary>
292292 /// Generates a cryptographically strong 32-bit random integer between specified values.
293293 /// </summary>
294− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
294+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
295295 /// <param name="startNumber">A <see cref="int"/> that is the low end of our range.</param>
296296 /// <param name="stopNumber">A <see cref="int"/> that is the high end of our range.</param>
297297 /// <returns>A <see cref="int"/> that is generated between the <paramref name="startNumber"/> and the <paramref name="stopNumber"/>.</returns>
@@ -306,14 +306,14 @@ namespace GSF.Security.Cryptography · 8 unmodified lines
306306 /// <summary>
307307 /// Generates a cryptographically strong unsigned 32-bit random integer.
308308 /// </summary>
309− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
309+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
310310 public static uint UInt32
311311 {
312312 get
313313 {
314314 byte[] value = new byte[4];
315315
316− s_randomNumberGenerator.GetBytes(value);
316+ RandomNumberGenerator.GetBytes(value);
317317
318318 return BitConverter.ToUInt32(value, 0);
319319 }
@@ -322,7 +322,7 @@ namespace GSF.Security.Cryptography · 2 unmodified lines
322322 /// <summary>
323323 /// Generates a cryptographically strong unsigned 32-bit random integer between specified values.
324324 /// </summary>
325− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
325+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
326326 /// <param name="startNumber">A <see cref="uint"/> that is the low end of our range.</param>
327327 /// <param name="stopNumber">A <see cref="uint"/> that is the high end of our range.</param>
328328 /// <returns>A <see cref="uint"/> that is generated between the <paramref name="startNumber"/> and the <paramref name="stopNumber"/>.</returns>
@@ -337,14 +337,14 @@ namespace GSF.Security.Cryptography · 8 unmodified lines
337337 /// <summary>
338338 /// Generates a cryptographically strong 64-bit random integer.
339339 /// </summary>
340− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
340+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
341341 public static long Int64
342342 {
343343 get
344344 {
345345 byte[] value = new byte[8];
346346
347− s_randomNumberGenerator.GetBytes(value);
347+ RandomNumberGenerator.GetBytes(value);
348348
349349 return BitConverter.ToInt64(value, 0);
350350 }
@@ -353,7 +353,7 @@ namespace GSF.Security.Cryptography · 2 unmodified lines
353353 /// <summary>
354354 /// Generates a cryptographically strong 64-bit random integer between specified values.
355355 /// </summary>
356− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
356+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
357357 /// <param name="startNumber">A <see cref="long"/> that is the low end of our range.</param>
358358 /// <param name="stopNumber">A <see cref="long"/> that is the high end of our range.</param>
359359 /// <returns>A <see cref="long"/> that is generated between the <paramref name="startNumber"/> and the <paramref name="stopNumber"/>.</returns>
@@ -368,14 +368,14 @@ namespace GSF.Security.Cryptography · 8 unmodified lines
368368 /// <summary>
369369 /// Generates a cryptographically strong unsigned 64-bit random integer.
370370 /// </summary>
371− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
371+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
372372 public static ulong UInt64
373373 {
374374 get
375375 {
376376 byte[] value = new byte[8];
377377
378− s_randomNumberGenerator.GetBytes(value);
378+ RandomNumberGenerator.GetBytes(value);
379379
380380 return BitConverter.ToUInt64(value, 0);
381381 }
@@ -384,7 +384,7 @@ namespace GSF.Security.Cryptography · 2 unmodified lines
384384 /// <summary>
385385 /// Generates a cryptographically strong unsigned 64-bit random integer between specified values.
386386 /// </summary>
387− /// <exception cref="System.Security.Cryptography.CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
387+ /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired.</exception>
388388 /// <param name="startNumber">A <see cref="ulong"/> that is the low end of our range.</param>
389389 /// <param name="stopNumber">A <see cref="ulong"/> that is the high end of our range.</param>
390390 /// <returns>A <see cref="ulong"/> that is generated between the <paramref name="startNumber"/> and the <paramref name="stopNumber"/>.</returns>
Source/Libraries/GSF.InstallerActions/CustomActions.cs+23−0
@@ -38,6 +38,7 @@ using System.Xml.Linq; · 37 unmodified lines
3838 using GSF.Data;
3939 using GSF.Identity;
4040 using GSF.Interop;
41+using GSF.Security.Cryptography;
4142 using GSF.ServiceProcess;
4243 using Microsoft.Deployment.WindowsInstaller;
4344
@@ -370,6 +371,28 @@ namespace GSF.InstallerActions · 326 unmodified lines
370371 return ActionResult.Success;
371372 }
372373
374+ /// <summary>
375+ /// Tests a connection to a database server.
376+ /// </summary>
377+ /// <param name="session">Session object containing data from the installer.</param>
378+ /// <returns>Result of the custom action.</returns>
379+ [CustomAction]
380+ public static ActionResult PasswordGenerationAction(Session session)
381+ {
382+ int passwordLength;
383+
384+ session.Log("Begin PasswordGenerationAction");
385+
386+ if (int.TryParse(session["GENPASSWORDLENGTH"], out passwordLength))
387+ session["GENERATEDPASSWORD"] = PasswordGenerator.Default.GeneratePassword(passwordLength);
388+ else
389+ session["GENERATEDPASSWORD"] = PasswordGenerator.Default.GeneratePassword();
390+
391+ session.Log("End PasswordGenerationAction");
392+
393+ return ActionResult.Success;
394+ }
395+
373396 /// <summary>
374397 /// Tests a connection to a database server.
375398 /// </summary>
Source/Libraries/GSF.InstallerActions/GSF.InstallerActions.csproj+1−0
@@ -78,6 +78,7 @@ · 77 unmodified lines
7878 <Reference Include="System.Core" />
7979 <Reference Include="System.IO.Compression" />
8080 <Reference Include="System.IO.Compression.FileSystem" />
81+ <Reference Include="System.Web" />
8182 <Reference Include="System.Windows" />
8283 <Reference Include="System.Windows.Forms" />
8384 <Reference Include="System.Xml.Linq" />
Source/Libraries/GSF.Security/SecurityProviderUtility.cs+2−39
@@ -215,46 +215,9 @@ namespace GSF.Security · 214 unmodified lines
215215 public static string GeneratePassword(int length)
216216 {
217217 if (length < 8)
218− throw new ArgumentException("Value must be at least 8", "length");
218+ throw new ArgumentException("Value must be at least 8", nameof(length));
219219
220− // ASCII character ranges:
221− // Lower case - 97 to 122
222− // Upper case - 65 to 90
223− // Special character - 33 to 47
224− // Digits - 48 to 57
225−
226− int cursor = 0;
227− int lower = Random.Int32Between(1, length / 2);
228− int upper = Random.Int32Between(1, (length - lower) / 2);
229− int special = Random.Int32Between(1, (length - (lower + upper)) / 2);
230− int digits = length - (lower + upper + special);
231− char[] password = new char[length];
232− for (int i = 0; i < lower; i++)
233− {
234− password[cursor] = (char)Random.Int32Between(97, 122);
235− cursor++;
236− }
237− for (int i = 0; i < upper; i++)
238− {
239− password[cursor] = (char)Random.Int32Between(65, 90);
240− cursor++;
241− }
242− for (int i = 0; i < special; i++)
243− {
244− password[cursor] = (char)Random.Int32Between(33, 47);
245− cursor++;
246− }
247− for (int i = 0; i < digits; i++)
248− {
249− password[cursor] = (char)Random.Int32Between(48, 57);
250− cursor++;
251− }
252−
253− // Scramble for more randomness.
254− List<char> scrambledPassword = new List<char>(password);
255− scrambledPassword.Scramble();
256−
257− return new string(scrambledPassword.ToArray());
220+ return PasswordGenerator.Default.GeneratePassword(length);
258221 }
259222
260223 /// <summary>

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t