C# Password Generator
Generate cryptographically secure passwords in C# using System.Security.Cryptography.RandomNumberGenerator.
The Secure Way
Since .NET 6, RandomNumberGenerator exposes simple static methods backed by the OS cryptographic random source.
using System;
using System.Security.Cryptography;
using System.Text;
public static class PasswordGenerator
{
private const string Upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private const string Lower = "abcdefghijklmnopqrstuvwxyz";
private const string Digits = "0123456789";
private const string Symbols = "!@#$%^&*()-_=+[]{}";
public static string Generate(int length = 20, bool upper = true, bool lower = true,
bool digits = true, bool symbols = true)
{
var pools = new System.Collections.Generic.List<string>();
if (upper) pools.Add(Upper);
if (lower) pools.Add(Lower);
if (digits) pools.Add(Digits);
if (symbols) pools.Add(Symbols);
if (pools.Count == 0) throw new ArgumentException("Select at least one character type");
string fullPool = string.Concat(pools);
var chars = new char[length];
for (int i = 0; i < pools.Count; i++)
chars[i] = pools[i][RandomNumberGenerator.GetInt32(pools[i].Length)];
for (int i = pools.Count; i < length; i++)
chars[i] = fullPool[RandomNumberGenerator.GetInt32(fullPool.Length)];
// Fisher-Yates shuffle using the same secure source
for (int i = chars.Length - 1; i > 0; i--)
{
int j = RandomNumberGenerator.GetInt32(i + 1);
(chars[i], chars[j]) = (chars[j], chars[i]);
}
return new string(chars);
}
}
// Console.WriteLine(PasswordGenerator.Generate(20));
// e.g. "k7$Rt2Xz!mQ9wLp#4vNc"
The Wrong Way (Don't Do This)
System.Random for passwords, tokens, or cryptographic keys. The .NET documentation itself states it is not suitable for security-sensitive applications.
// INSECURE โ System.Random is not cryptographically secure
var random = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var password = new string(Enumerable.Range(0, 16)
.Select(_ => chars[random.Next(chars.Length)]).ToArray());
Common Mistakes
- Using the older
RNGCryptoServiceProviderpattern unnecessarily โ it still works but is now legacy; the staticRandomNumberGeneratormethods (available since .NET 6) are simpler and preferred. - Using
Guid.NewGuid()as a password โ its fixed format (hyphens, version/variant bits) reduces effective entropy versus a purpose-built generator. - Computing
RandomNumberGenerator.GetBytes()output modulo pool length manually โ this reintroduces modulo bias.GetInt32(max)already performs unbiased bounded generation internally. - Storing passwords in immutable
stringinstances for longer than necessary in highly sensitive contexts, where a pinned, zeroable buffer would be preferable.
Frequently Asked Questions
System.Random is a deterministic PRNG meant for general-purpose use. Microsoft's own documentation states it should not be used for security-sensitive applications. Use System.Security.Cryptography.RandomNumberGenerator instead.
It still functions but is considered legacy. Since .NET 6, the static methods on RandomNumberGenerator (like GetInt32 and Fill) provide the same security with a simpler API and are the current recommended approach.
Not recommended. Its format includes fixed hyphens and reserved version/variant bits, which reduce effective entropy compared with a password generator that uses the full character space you intend.
Prefer not to write the code?
Generate a strong password instantly in your browser.
Use the Password Generator โ