SECURITY

Password Generator

Generate cryptographically secure passwords with custom length and character sets.

16
Uppercase A–Z
Lowercase a–z
Numbers 0–9
Symbols !@#$%^&*
Exclude ambiguous (l,1,O,0,I)
BULK GENERATION

About Password Generator

In an era of increasing cyber threats, using "123456" or your pet's name as a password is a major security risk. Our Password Generator is designed to create truly random, cryptographically secure passwords that are virtually impossible for hackers to guess or "brute-force."

What makes a secure password?

Is it safe to generate passwords online?

It depends on the tool. Many sites send your generated password to their servers, which is a major red flag. toolpad.cc generates your password entirely on your device using the crypto.getRandomValues() browser API. Your password never leaves your browser, and we never see it. For maximum safety, you can even use this tool while offline.

Frequently Asked Questions

Should I change my passwords often?

Modern security best practices suggest that if you have a strong, unique password for every account, you don't need to change it unless there is a known security breach. Using a password manager in combination with this generator is the best strategy.

What does 'Entropy' mean?

Entropy is a measure of randomness. In password terms, it tells you how many guesses a computer would need to try every possible combination. The higher the entropy, the more 'work' an attacker has to do.

Why exclude ambiguous characters?

Characters like 'l' (lowercase L), '1' (number one), 'O' (uppercase O), and '0' (zero) can look identical in certain fonts. Excluding them makes it much easier to type your password manually if needed.

Developer Reference

Core Algorithm & Standalone Script

Standalone, zero-dependency JavaScript implementation powering this tool. Free to inspect, copy, and build upon.

const UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  const LOWER = 'abcdefghijklmnopqrstuvwxyz';
  const DIGITS = '0123456789';
  const SYMBOLS = '!@#$%^&*()-_=+[]{}|;:,.<>?';
  const AMBIGUOUS = new Set(['l','1','O','0','I','|']);

  const state = { upper: true, lower: true, digits: true, symbols: true, noambig: false, length: 16 };

  document.getElementById('len-slider').addEventListener('input', e => {
    state.length = parseInt(e.target.value);
    document.getElementById('len-display').textContent = state.length;
    generateAndShow();
  });

  document.querySelectorAll('.toggle-item').forEach(item => {
    item.addEventListener('click', () => {
      const key = item.dataset.set;
      // Prevent disabling all charset options simultaneously
      if (key !== 'noambig') {
        const activeCharSets = ['upper','lower','digits','symbols'].filter(k => state[k]);
        if (state[key] && activeCharSets.length === 1) return; // must keep at least one
      }
      state[key] = !state[key];
      item.classList.toggle('active', state[key]);
      generateAndShow();
    });
  });

  function buildCharset() {
    let chars = '';
    if (state.upper) chars += UPPER;
    if (state.lower) chars += LOWER;
    if (state.digits) chars += DIGITS;
    if (state.symbols) chars += SYMBOLS;
    if (state.noambig) {
      chars = chars.split('').filter(c => !AMBIGUOUS.has(c)).join('');
    }
    return chars;
  }

  function secureRandom(max) {
    const arr = new Uint32Array(1);
    let result;
    do {
      crypto.getRandomValues(arr);
      result = arr[0];
    } while (result >= Math.floor(0xFFFFFFFF / max) * max);
    return result % max;
  }

  function generatePassword(length) {
    const charset = buildCharset();
    if (!charset.length) return '';
    let pw = '';
    for (let i = 0; i < length; i++) {
      pw += charset[secureRandom(charset.length)];
    }
    return pw;
  }

  function calcEntropy(length) {
    const charset = buildCharset();
    if (!charset.length) return 0;
    return length * Math.log2(charset.length);
  }

  function strengthFromEntropy(entropy) {
    if (entropy < 28) return { label: 'Weak', pct: 10, color: '#ff2200' };
    if (entropy < 36) return { label: 'Fair', pct: 30, color: '#ff7700' };
    if (entropy < 60) return { label: 'Good', pct: 55, color: '#f0c000' };
    if (entropy < 80) return { label: 'Strong', pct: 78, color: '#00c896' };
    return { label: 'Very Strong', pct: 100, color: '#00c896' };
  }

  function generateAndShow() {
    const pw = generatePassword(state.length);
    document.getElementById('pw-text').textContent = pw;

    const entropy = calcEntropy(state.length);
    const s = strengthFromEntropy(entropy);
    document.getElementById('strength-fill').style.width = s.pct + '%';
    document.getElementById('strength-fill').style.backgroundColor = s.color;
    document.getElementById('strength-label').textContent = s.label;
    document.getElementById('strength-label').style.color = s.color;
    document.getElementById('entropy-info').textContent = `~${entropy.toFixed(0)} bits of entropy · ${buildCharset().length} character pool`;
  }

  function copyText(text, btn, label = 'copy') {
    navigator.clipboard.writeText(text).then(() => {
      btn.textContent = 'copied!';
      setTimeout(() => { btn.textContent = label; }, 2000);
    });
  }

  document.getElementById('copy-main').addEventListener('click', () => {
    const pw = document.getElementById('pw-text').textContent;
    copyText(pw, document.getElementById('copy-main'));
  });

  document.getElementById('gen-btn').addEventListener('click', generateAndShow);

  // Bulk generation
  document.getElementById('bulk-btn').addEventListener('click', () => {
    const list = document.getElementById('bulk-list');
    list.innerHTML = '';
    for (let i = 0; i < 5; i++) {
      const pw = generatePassword(state.length);
      const div = document.createElement('div');
      div.className = 'bulk-item';
      div.innerHTML = `<div class="bulk-pw">${pw}</div><button class="bulk-copy">copy</button>`;
      div.querySelector('.bulk-copy').addEventListener('click', function() {
        copyText(pw, this);
      });
      list.appendChild(div);
    }
  });

  // Auto-generate on load
  generateAndShow();
  // Populate bulk on load too
  document.getElementById('bulk-btn').click();