Como o gerador funciona e quais são seus limites

Como o Senha Gerador escolhe caracteres e blocos, calcula a estimativa e trata o resultado. Implementação 3.0.0, revisada em 8 de outubro de 2026.

Atualizado em 8 de outubro de 2026. Responsável: Rafael.

Fonte aleatória e distribuição

As escolhas vêm de crypto.getRandomValues, a API criptográfica do navegador. Para sortear um índice de 0 a n−1, rejeitamos inteiros de 32 bits fora do maior múltiplo de n. Isso evita o viés de módulo. Se a API falhar, a geração para: não há alternativa com Math.random.

No modo aleatório, sorteamos uma sequência inteira a partir da união das classes escolhidas e rejeitamos o candidato se faltar alguma classe. Cada candidato tem a mesma probabilidade. Condicionar a aceitação às regras preserva a distribuição uniforme entre as sequências válidas. Não inserimos um caractere obrigatório para depois embaralhar.

As classes são disjuntas. O limite é de 8 a 128 caracteres. Evitar parecidos retira exatamente 0, O, o, l, I e 1 quando presentes. O padrão de 20 caracteres é uma decisão desta ferramenta. Nenhum resultado é garantidamente inédito: sorteios independentes podem coincidir.

Como calculamos a estimativa

Para comprimento L, tamanho total N e classes de tamanhos s₁…sₖ, contamos as sequências que contêm todas as classes por inclusão–exclusão: V = Σ(−1)^|S| (N − Σ sᵢ)^L, sobre os subconjuntos S de classes. A interface exibe log₂(V), arredondado a uma casa decimal. A contagem usa inteiros BigInt; não subtrai aproximações de ponto flutuante.

Exemplo pequeno de teste: para as classes {a,b} e {0}, com comprimento 3, há 3³ − 2³ − 1³ = 18 sequências válidas. A enumeração independente deve encontrar exatamente 18. Este exemplo explica a contagem; não é uma senha para usar.

A estimativa descreve o espaço de sorteio desta implementação. Não fornece um tempo universal de quebra nem mede phishing, malware, armazenamento do serviço, recuperação, reutilização ou vazamentos. As referências não certificam este projeto.

Blocos pronunciáveis, não palavras

Um bloco combina uma de 33 entradas iniciais, uma de 5 vogais, uma de 6 consoantes internas e outra de 5 vogais: 33 × 5 × 6 × 5 = 4.950 combinações distintas. As tabelas aparecem no código abaixo. Nenhum bloco é o início completo de outro bloco; isso permite delimitar a sequência mesmo sem separador.

A opção de números sorteia um dígito de 0 a 9 por bloco. Com b blocos, a entropia é b × log₂(4.950), ou b × log₂(49.500) com dígitos. Capitalização da primeira letra e separador fixo não acrescentam aleatoriedade. Comprimento final e entropia são conceitos diferentes.

Onde o resultado fica

O gerador não mantém histórico nem envia resultados ao servidor. A senha permanece na memória e na interface da página até ser substituída ou a página ser encerrada. Recarregar descarta esse estado; não é uma garantia de apagamento forense da memória.

Copiar coloca o resultado na área de transferência do sistema. Baixar um lote solicita ao navegador um arquivo de texto sem criptografia. O site não controla o histórico do clipboard, sincronização, backups, extensões ou outros aplicativos. A confirmação de download informa uma solicitação, não a gravação ou importação concluída.

Como verificar esta versão

Os testes da implementação incluem enumeração independente de espaços pequenos, rejeição dos inteiros fora do intervalo, falha da fonte aleatória, presença das classes, exclusão dos caracteres parecidos e unicidade das 4.950 combinações silábicas. Amostras aleatórias sozinhas não provam uniformidade.

A interface também precisa preservar Ocultar ao gerar ou ajustar opções, invalidar a cópia após configuração inválida, funcionar com métricas recusadas e conservar a sequência exata ao copiar ou exportar. Uma correção que altere o algoritmo exige atualizar método e testes na mesma versão.

Código do motor, versão 3.0.0

Consultar fonte desta versão
// Senha Gerador 3.0.0. Pure functions: no storage, DOM, network or logging.
export const VERSION = "3.0.0";
export const CHARACTER_SETS = Object.freeze({
  lowercase: "abcdefghijklmnopqrstuvwxyz",
  uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  numbers: "0123456789",
  symbols: "!@#$%^&*()-_=+[]{};:,.?/",
});
export const AMBIGUOUS = "0OolI1";
export const SYLLABLES = Object.freeze({
  onsets: ["b", "br", "c", "cl", "cr", "d", "dr", "f", "fl", "fr", "g", "gl", "gr", "j", "k", "l", "m", "n", "p", "pl", "pr", "qu", "r", "s", "st", "t", "tr", "v", "w", "x", "z", "ch", "sh"],
  vowels: ["a", "e", "i", "o", "u"],
  codas: ["l", "m", "n", "r", "s", "t"],
});

export function secureInt(maximum, cryptoSource = globalThis.crypto) {
  if (!cryptoSource?.getRandomValues) throw new Error("CRYPTO_UNAVAILABLE");
  if (!Number.isSafeInteger(maximum) || maximum < 1 || maximum > 2 ** 32) throw new Error("INVALID_RANGE");
  const limit = Math.floor(2 ** 32 / maximum) * maximum;
  const buffer = new Uint32Array(1);
  for (let attempt = 0; attempt < 100000; attempt++) {
    try { cryptoSource.getRandomValues(buffer); } catch { throw new Error("CRYPTO_UNAVAILABLE"); }
    if (buffer[0] < limit) return buffer[0] % maximum;
  }
  throw new Error("CRYPTO_UNAVAILABLE");
}

// Inclusion–exclusion counts every string containing every selected class once.
export function countValid(length, sizes) {
  if (!Number.isInteger(length) || length < 0 || length > 128 || sizes.length > 4 || sizes.some(n => !Number.isInteger(n) || n < 1)) throw new Error("INVALID_LENGTH");
  if (!sizes.length) return 0n;
  const total = sizes.reduce((a, b) => a + b, 0);
  let count = 0n;
  for (let mask = 0; mask < 2 ** sizes.length; mask++) {
    let remaining = total, parity = 0;
    sizes.forEach((size, index) => { if (mask & (1 << index)) { remaining -= size; parity++; } });
    const term = BigInt(remaining) ** BigInt(length);
    count += parity % 2 ? -term : term;
  }
  return count;
}

export function log2BigInt(value) {
  if (value <= 0n) throw new Error("NO_CHARACTER_SET");
  const bits = value.toString(2).length;
  const shift = Math.max(0, bits - 53);
  return Math.log2(Number(value >> BigInt(shift))) + shift;
}

export function selectedSets(settings) {
  return Object.entries(CHARACTER_SETS).filter(([key]) => settings[key]).map(([, set]) =>
    settings.excludeAmbiguous ? [...set].filter(c => !AMBIGUOUS.includes(c)).join("") : set);
}

export function randomPassword(settings, cryptoSource = globalThis.crypto) {
  const length = Number(settings.length);
  if (!Number.isInteger(length) || length < 8 || length > 128) throw new Error("INVALID_LENGTH");
  const sets = selectedSets(settings);
  if (!sets.length) throw new Error("NO_CHARACTER_SET");
  const pool = sets.join("");
  // Each complete candidate has probability pool.length ** -length.
  // Conditioning on acceptance preserves uniformity across all valid strings.
  for (let attempt = 0; attempt < 10000; attempt++) {
    let value = "";
    for (let i = 0; i < length; i++) value += pool[secureInt(pool.length, cryptoSource)];
    if (sets.every(set => [...value].some(c => set.includes(c)))) {
      return { value, entropy: log2BigInt(countValid(length, sets.map(s => s.length))) };
    }
  }
  throw new Error("CRYPTO_UNAVAILABLE");
}

export function memorablePassword(settings, cryptoSource = globalThis.crypto) {
  const count = Number(settings.segments);
  if (!Number.isInteger(count) || count < 3 || count > 8) throw new Error("INVALID_LENGTH");
  if (!["-", "_", ".", " ", ""].includes(settings.separator)) throw new Error("INVALID_SEPARATOR");
  const choose = list => list[secureInt(list.length, cryptoSource)];
  const values = Array.from({ length: count }, () => {
    let value = choose(SYLLABLES.onsets) + choose(SYLLABLES.vowels) + choose(SYLLABLES.codas) + choose(SYLLABLES.vowels);
    if (settings.capitalize) value = value[0].toUpperCase() + value.slice(1);
    if (settings.addNumbers) value += secureInt(10, cryptoSource);
    return value;
  });
  return { value: values.join(settings.separator), entropy: count * Math.log2(4950 * (settings.addNumbers ? 10 : 1)) };
}

Compare o algoritmo com os testes de enumeração descritos acima. Reporte divergências pelo canal de correções.

Continue sua tarefa