DEV Community

Cover image for How Secure is Your Password? Calculating Shannon Entropy in the Browser
kandz
kandz

Posted on

How Secure is Your Password? Calculating Shannon Entropy in the Browser

We've all seen password strength meters on sign-up forms. Most of them rely on simplistic, static rules: "Must contain at least 8 characters, one number, and one special character."

But from a mathematical standpoint, these rules are a poor proxy for actual password security. A password like Tr0ub4dor&3 conforms to these rules but is far easier to compromise than a randomly generated four-word passphrase like correct-horse-battery-staple.

To truly measure password security, we have to look at information theory and compute its Shannon Entropy.

Here is how password entropy works, the math behind it, and how you can calculate it directly in the browser with 100% client-side privacy.


What is Password Entropy?

In cryptography, entropy is a measure of the unpredictability or randomness of a password. It is expressed in bits.

An entropy of $N$ bits means there are $2^N$ possible combinations that an attacker would have to guess in a worst-case brute-force search.

  • < 28 bits: Very weak (easily guessed in milliseconds).
  • 28 to 35 bits: Weak (cracked in minutes or hours).
  • 36 to 59 bits: Reasonable protection (days to months).
  • 60 to 127 bits: Very strong (takes years to decades to crack).
  • 128+ bits: Extremely secure (mathematically unfeasible to crack).

The Mathematical Formula

To calculate the entropy ($E$) of a password, we use the following equation:

$$E = L \times \log_2(R)$$

Where:

  • $L$ is the length of the password (number of characters).
  • $R$ is the size of the pool of unique characters from which the password is drawn.
  • $\log_2(R)$ is the binary logarithm of the pool size, representing the amount of information carried by each character.

Determining Pool Size ($R$)

To find $R$, we analyze which character sets are present in the password string:

  • Lowercase letters (a-z): 26 characters
  • Uppercase letters (A-Z): 26 characters
  • Numbers (0-9): 10 characters
  • Common special characters/punctuation: 33 characters (e.g., !@#$%^&*()-_=+[]{}|;:',.<>/? etc.)

If a password uses characters from all four pools, the total pool size is $R = 26 + 26 + 10 + 33 = 95$.


Calculating Entropy in JavaScript

Here is a clean, vanilla JavaScript function to evaluate a password's entropy:

function calculatePasswordEntropy(password) {
  if (!password) return 0;

  let poolSize = 0;

  // Check character sets used
  if (/[a-z]/.test(password)) poolSize += 26;
  if (/[A-Z]/.test(password)) poolSize += 26;
  if (/[0-9]/.test(password)) poolSize += 10;
  if (/[^a-zA-Z0-9]/.test(password)) poolSize += 33; // Special characters

  if (poolSize === 0) return 0;

  const length = password.length;

  // Calculate entropy: L * log2(R)
  const entropy = length * Math.log2(poolSize);

  return parseFloat(entropy.toFixed(2));
}

// Example usage:
console.log(calculatePasswordEntropy("P@ss123")); // Length 7, Pool 95 => ~45.99 bits
console.log(calculatePasswordEntropy("correcthorsebatterystaple")); // Length 25, Pool 26 => ~117.51 bits
Enter fullscreen mode Exit fullscreen mode

Estimating Brute-Force Cracking Times

Once you know the entropy, you can estimate how long it would take an attacker to crack it.

If a password has

EE

bits of entropy, the total number of combinations is

2E2E

. On average, an attacker will find the password after searching half of the keyspace (

2E−12E−1

attempts).

The actual time to crack depends on the speed of the attacker's hardware:

Online/Standard Brute Force: Standard web APIs rate-limit attempts (e.g., 100 guesses/sec).

Offline Hash Cracking (GPU Rig): If the database was leaked, a modern high-end GPU rig running Hashcat can guess billions of hashes per second (e.g.,


109109



attempts/sec for MD5/SHA256, though much slower for heavily salted modern algorithms like bcrypt or Argon2).
Enter fullscreen mode Exit fullscreen mode

Using these guesses-per-second values, you can divide

2E−12E−1

by the hash rate to find the total seconds required, then convert that into days, months, or years.
Auditing Security Privately

Because passwords are highly sensitive, checking your password strength using an online service that transmits your password to a remote server is a major security risk.

To address this, we built a free, 100% Client-Side Password Strength & Entropy Analyzer at KandZ Tools.

Our tool processes all calculations strictly inside your browser's RAM. Your passwords are never transmitted over the network, keeping your credentials entirely confidential. It computes the exact Shannon entropy, determines character distributions, and models real-world brute-force resistance.

Try the tool privately: https://tools.kandz.me/password-strength-analyzer

Top comments (2)

Collapse
 
frank_signorini profile image
Frank

I've seen some password strength meters use regex to check for character variety, but calculating Shannon Entropy is a more nuanced approach - how do you handle edge cases like passwords with non-ASCII characters? I'd love to swap ideas on this.

Collapse
 
kandz profile image
kandz

Hi Frank,

That is an excellent point. Standard ASCII-based entropy calculations fall apart quickly when dealing with multi-byte Unicode characters (like accented letters, non-Latin scripts, or emojis).

To handle Unicode edge cases accurately in a browser-based parser, we focus on two core adjustments:

1. Counting actual code points (not JS code units)

In JavaScript, standard string length ("💩".length) returns 2 instead of 1 because it measures 16-bit code units (surrogate pairs) rather than actual Unicode characters. If a user enters emojis or complex scripts, using .length artificially inflates the entropy.

We solve this by spreading the string into an array of true code points before measuring:

const actualLength = [...password].length;
Enter fullscreen mode Exit fullscreen mode

2. Dynamically expanding the character pool ($R$)

Using standard ASCII character groups (which sum to 95) is too restrictive for non-ASCII entries. To handle this, we can detect Unicode characters using Unicode property escapes (e.g., /\P{ASCII}/u).

Once detected, we dynamically scale up the alphabet pool size ($R$):

  • Basic Non-ASCII / Accented Latin: We expand the pool size $R$ by $+256$ to account for extended Latin scripts.
  • Basic Multilingual Plane (BMP): For non-Western alphabets (like Cyrillic, Greek, or Arabic), we can scale the pool by $+65,536$.
  • CJK / Emojis: If characters exceed the BMP range, we can treat $R$ as pulling from a massive pool of $+100,000$+ characters.

3. Combining Keyspace Entropy with Character Frequency

To prevent users from bypassing complexity checks by typing repetitive non-ASCII strings (like entering ααααα which technically uses an expanded Unicode pool but carries very little unpredictable information), we overlay keyspace entropy ($L \log_2 R$) with a character frequency count based on classic Shannon text entropy ($H = -\sum p_i \log_2 p_i$). This lets us penalize repetitive patterns regardless of the alphabet pool size.