Password Strength Analyser — C# source
Estimate password strength with zxcvbn - realistic dictionary and pattern cracking with crack-time estimates and improvement suggestions. Runs entirely in your browser.
This is the C# implementation — the same logic the interactive tool runs, in a shareable, citable form.
// password-strength-analyser — C# port: password strength scoring & feedback. (.NET 7+). Port of src/lib/password-strength.ts — same self-contained heuristic estimator as this dir's python.py (the live TS/Go twins wrap zxcvbn, whose ranking data is too large to vendor).
using System;
using System.Collections.Generic;
using System.Linq;
namespace PasswordStrengthAnalyser;
/// <summary>Strength breakdown — mirrors the TS PasswordAnalysis / Go pwstrength.Result.</summary>
public readonly record struct Analysis(int Score, string Label, double Entropy, string CrackTime);
public static class PasswordStrength
{
static readonly string[] Labels = { "Very weak", "Weak", "Fair", "Good", "Strong" };
static readonly double[] Thresholds = { 28, 36, 60, 128 };
/// <summary>Curated common-password blocklist — an exact (lowercased) match forces score 0.</summary>
static readonly HashSet<string> Common = new() {
"1234", "12345", "123123", "123456", "12345678", "123456789", "1234567890",
"000000", "111111", "654321", "666666", "abc123", "admin", "baseball", "batman",
"dragon", "iloveyou", "letmein", "login", "master", "monkey", "passw0rd", "password",
"password1", "princess", "qwerty", "root", "shadow", "superman", "sunshine", "trustno1", "welcome" };
static readonly string[] Sequences = { "qwertyuiop", "asdfghjkl", "zxcvbnm", "1234567890", "0987654321", "abcdefg", "gfedcba" };
/// <summary>Guess-pool size: 26 lower + 26 upper + 10 digit + 33 ASCII symbol + 128 other.</summary>
static int PoolSize(string pw)
{
bool lower = false, upper = false, digit = false, sym = false, other = false;
foreach (char c in pw)
if (c >= 128) other = true; else if (char.IsLower(c)) lower = true;
else if (char.IsUpper(c)) upper = true; else if (char.IsDigit(c)) digit = true; else sym = true;
return (lower ? 26 : 0) + (upper ? 26 : 0) + (digit ? 10 : 0) + (sym ? 33 : 0) + (other ? 128 : 0);
}
/// <summary>Does <paramref name="lower"/> contain a length-4 window of <paramref name="seq"/>?</summary>
static bool ContainsSequence(string lower, string seq) =>
seq.Length >= 4 && Enumerable.Range(0, seq.Length - 3).Any(i => lower.Contains(seq[i..(i + 4)]));
/// <summary>Human crack time at 1e10 guesses/s — zxcvbn's offline-fast display.</summary>
static string CrackTime(double entropy)
{
if (entropy <= 0 || Math.Pow(2, entropy) / 1e10 < 1) return "instant";
double seconds = Math.Pow(2, entropy) / 1e10;
(double div, string name) = seconds < 60 ? (1, "second") : seconds < 3_600 ? (60, "minute")
: seconds < 86_400 ? (3_600, "hour") : seconds < 2_592_000 ? (86_400, "day")
: seconds < 31_536_000 ? (2_592_000, "month") : (31_536_000, "year");
double v = seconds / div;
return v >= 1e9 ? "centuries" : v >= 1e6 ? $"{v / 1e6:F0} million years"
: v >= 1e3 ? $"{v / 1e3:F0} thousand years" : $"{v:F0} {name}s";
}
/// <summary>Scores 0-4. <paramref name="userInputs"/> seeds the estimator with
/// related tokens (username, site name) — a substring match weakens the score.</summary>
public static Analysis Analyse(string password, params string[] userInputs)
{
int len = password.Length; int pool = PoolSize(password);
double lp = pool > 1 ? Math.Log2(pool) : 0; int unique = password.Distinct().Count();
// Base entropy len*log2(pool), capped by variety — repeats earn quarter credit.
double entropy = pool > 1 ? Math.Min(len * lp, (unique + (len - unique) * 0.25) * lp) : 0;
string lower = password.ToLowerInvariant();
if (Common.Contains(lower)) entropy = 0; // blocklist hit — dictionary collapse
else
{
foreach (string seq in Sequences) if (ContainsSequence(lower, seq)) entropy -= 12;
foreach (string ui in userInputs)
if (ui.Length >= 3 && lower.Contains(ui.ToLowerInvariant())) entropy -= 10;
entropy = Math.Max(0, entropy);
}
int score = len < 4 || entropy < Thresholds[0] ? 0 : entropy < Thresholds[1] ? 1
: entropy < Thresholds[2] ? 2 : entropy < Thresholds[3] ? 3 : 4;
return new Analysis(score, Labels[score], entropy, CrackTime(entropy));
}
}
public class Demo
{
public static void Main()
{
foreach (string pw in new[] { "password", "12345678", "Tr0ub4dour&3", "correct horse battery staple", "u2#9Xq!Lp$7wZ" })
{
Analysis r = PasswordStrength.Analyse(pw);
Console.WriteLine($"{pw,-26} {r.Score}/4 {r.Label,-9} {r.Entropy,6:F1} bits {r.CrackTime}");
}
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →