Retour au blog

Ingénierie des mots de passe

D'où vient l'aléatoire des mots de passe ?

12 mai 2026 · 6 min de lecture

Pierres colorées disposées de façon apparemment aléatoire
Image de Sara sur Pixabay

Les générateurs de mots de passe semblent simples : un clic, un secret. L’essentiel est ce qui se passe avant l’affichage. D’où vient l’aléatoire ? Comment le transforme-t-on en caractères ou en mots ? Que peut faire un utilisateur qui souhaite ajouter sa propre dose d’aléatoire ?

Cet article décrit la source d’aléatoire des générateurs côté navigateur, la bonne façon de penser l’entropie, et comment une interaction optionnelle (par exemple un petit jeu au clavier) peut être combinée à la source cryptographique du navigateur.

La réponse courte

Sur passwords.lu, la génération se fait dans le navigateur. La page demande des octets aléatoires cryptographiquement sûrs, les transforme en caractères ou en mots et affiche le résultat localement.

On obtient deux propriétés distinctes : l’aléa rend les tentatives de devinette difficiles, et la génération locale évite d’envoyer le secret dans l’infrastructure applicative.

Pourquoi la génération locale change la donne

Les anciens sites généraient souvent le secret sur le serveur avant de l’afficher. Ce modèle peut être honnête, mais il impose un problème de confiance évitable.

L’utilisateur doit croire que le serveur n’a pas journalisé le mot de passe, mis en cache, exposé via l’analytique ou fuité par l’infra. La génération native dans le navigateur inverse l’architecture : le serveur livre le code, le secret naît sur l’appareil.

Pour un générateur de mots de passe, c’est le modèle de confidentialité le plus propre. Moins de systèmes voient le secret, moins il y a de risques de mauvaise manipulation.

Pourquoi l’aléa compte

Les humains sont de piètres générateurs aléatoires : dates, prénoms, motifs clavier, mots favoris, formes mémorables, petites variantes d’habitudes.

Les attaquants le savent. Les outils de cassage n’essaient pas toutes les chaînes de aaa à zzz : fuites, dictionnaires, substitutions, motifs clavier, années, combinaisons « humaines ».

Un bon générateur ne demande pas la créativité. Il tire des valeurs imprévisibles d’une source aléatoire cryptographiquement sûre, puis les projette en caractères ou mots sans biais évitable.

Ce que signifie « entropie »

Pour la génération de mots de passe, l’entropie mesure combien de possibilités un attaquant doit envisager. On l’exprime souvent en bits.

Un bit, deux issues équiprobables ; deux bits, quatre issues ; dix bits, 1 024. Chaque bit supplémentaire double l’espace de recherche, bien au-delà de l’intuition.

Courbe de croissance de l’entropieGraphique en noir et blanc : l’espace de recherche croît exponentiellement quand le nombre de bits d’entropie augmente.01101K201M301B401T501Q+Bits d’entropieEspace de recherche
Courbe illustrative : chaque bit ajouté double l’espace de recherche ; la croissance accélère fortement.

Si le mot de passe est tiré uniformément dans un ensemble fini, l’entropie vaut log2(nombre de possibilités). Un caractère parmi 64 symboles apporte 6 bits (2^6 = 64).

La méthode prime : un mot de passe n’est pas fort parce qu’il paraît compliqué, mais parce qu’il est tiré dans un grand ensemble de façon imprévisible pour l’attaquant.

Un mot de passe de 16 caractères tirés uniformément sur 64 symboles donne environ 96 bits d’entropie. Une phrase de passe façon Diceware avec 5 mots d’une liste de 7 776 mots donne environ 64,6 bits (log2(7 776) ≈ 12,9 bits par mot).

Une phrase peut être excellente à mémoriser, mais plus longue visuellement ne veut pas dire plus forte qu’une chaîne courte bien aléatoire. Comptent les choix aléatoires réels derrière le secret.

Le tableau met cette idée en chiffres avec des exemples de mots de passe et de phrases de passe. Les valeurs exactes sont moins importantes que le principe : une génération uniforme et assez de choix indépendants créent la marge de sécurité.

ExempleEspace de rechercheEntropieInterprétation
12 caractères aléatoires parmi 64 symboles64^1272 bitsSolide pour beaucoup de cas d’usage
16 caractères aléatoires parmi 64 symboles64^1696 bitsTrès bon défaut pour un gestionnaire de mots de passe
5 mots Diceware parmi 7 776 mots7 776^564,6 bitsBonne base pour une phrase mémorisée
6 mots Diceware parmi 7 776 mots7 776^677,5 bitsPhrase mémorisée plus robuste

Comment le navigateur expose l’aléa sûr

Les navigateurs modernes exposent l’aléa cryptographique via la Web Crypto API. La fonction utile ici est crypto.getRandomValues(). On fournit un tableau typé, par exemple un Uint8Array, que le navigateur remplit d’octets aléatoires sûrs.

La Web Crypto API ne s’est pas déployée partout le même jour, mais l’aléa cryptographique côté navigateur est largement disponible depuis des années. MDN considère l’interface Crypto et crypto.getRandomValues() comme baseline, disponible dans les navigateurs majeurs depuis juillet 2015.

Note développeur : getRandomValues() sert pour de petits tampons. La spécification limite chaque appel à 65 536 octets ; au-delà, il faut enchaîner plusieurs appels.

Sous une forme simplifiée, cela ressemble à ceci :

const bytes = new Uint8Array(32);
crypto.getRandomValues(bytes);

Ces octets sont la matière première, pas encore un mot de passe. Il faut encore les convertir en caractères, mots de phrase, chiffres de PIN ou octets de clé API.

Cette conversion doit être soignée. La section suivante présente une erreur fréquente, le biais modulo, et comment l’éviter.

Ce que fait passwords.lu localement

Le générateur demande des octets sûrs au navigateur, vérifie qu’une source sûre existe et rejette des sorties catastrophiques (tampon entièrement nul ou octets identiques). Ce n’est pas un substitut au RNG du navigateur : c’est une garde-fou contre des états de panne évidents.

Pour les mots de passe alphanumériques, les octets sont projetés dans l’alphabet choisi par échantillonnage par rejet. Pour les phrases, on indexe des listes de mots fixes. Pour les PIN et secrets numériques, même principe : tirer, rejeter ce qui créerait un biais, puis mapper.

L’essentiel : le mot de passe généré reste le résultat local de la page exécutée dans votre navigateur.

Biais modulo : la petite erreur qui compte

Erreur classique : prendre un octet aléatoire et faire octet % 62 pour choisir un symbole dans un alphabet de 62 caractères.

Or 256 ne se divise pas par 62 : huit positions reçoivent une valeur d’octet en trop, donc une probabilité légèrement plus élevée. C’est le biais modulo.

Sur un script jouet, l’effet semble négligeable. Pour un outil de sécurité, chaque symbole autorisé doit être aussi uniforme que le permet la source : les petits biais sont inutiles et faciles à supprimer.

Échantillonnage par rejet : calculer le plus grand intervalle [0, max) divisible par la taille de l’alphabet. Pour 62 symboles, accepter 0–247 (248 divisible par 62) ; rejeter 248–255 et retirer un nouvel octet. Ensuite seulement octet % 62 est sans biais.

D’où le fait qu’un générateur sûr consomme parfois plus d’octets aléatoires que la longueur finale : certains octets sont jetés à dessein.

function randomIndex(byte, alphabetSize) {
  const max = Math.floor(256 / alphabetSize) * alphabetSize;
  if (byte >= max) return null; // reject and draw again
  return byte % alphabetSize;
}

Le générateur de ce dépôt suit ce schéma pour mapper les octets aux caractères ; la même idée s’applique aux index de mots et plages numériques : tirer assez d’aléa, rejeter les valeurs qui créent des compartiments inégaux, puis seulement projeter.

L’entrée utilisateur peut-elle ajouter de l’aléa ?

Oui : on peut mélanger l’aléa du navigateur avec de l’entropie fournie par l’utilisateur. Ce n’est en général pas indispensable si le navigateur et l’OS sont sains, mais cela renforce la transparence et la défense en profondeur pour qui doute du RNG local.

Exemple connu : l’idée de « remuer la marmite » — un mini-jeu ou une interaction dont le timing et la direction enrichissent l’imprévisibilité.

Un déplacement façon « serpent » capte changements de direction, intervalles entre touches, historique de mouvement. Ce n’est pas la seule source : on le mélange avec des octets de crypto.getRandomValues().

À traiter comme défense en profondeur, pas comme excuse pour raccourcir le mot de passe. Une minute à déplacer un serpent ne rend pas sûr un mot de passe de 6 caractères. Longueur, grand espace de recherche et génération sans biais restent indispensables.

Un exemple concret : passwordgenerator.ws, qui propose une interaction façon serpent pour « remuer » une entrée utilisateur dans le processus.

Comment mélanger deux sources proprement

Mauvaise idée : concaténer deux tampons et espérer. Un simple hachage ne suffit pas non plus pour produire tout le flux nécessaire. Le bon schéma est une fonction de dérivation de clé (KDF) avec extraction puis expansion, par exemple HKDF.

L’étape d’extraction ne se réduit pas à de la compression : elle condense l’entropie disponible à partir de données peut-être structurées ou partiellement contrôlées, en une clé courte pseudo-aléatoire — idée centrale du papier HKDF de Krawczyk. L’expansion dérive ensuite les octets nécessaires en liant le contexte, par exemple password-generator/v1.

En résumé : octets navigateur + octets d’interaction entrent dans une KDF contextualisée ; sa sortie alimente la génération.

Si au moins une source est forte et la KDF est correcte, la sortie reste imprévisible. L’entrée utilisateur ajoute une couche utile, mais ne remplace pas le RNG cryptographique du navigateur.

Cela rejoint un principe plus large : combiner plusieurs sources peut compenser la défaillance d’un composant, à condition que la construction de mélange soit sûre. L’article Many a Mickle Makes a Muckle l’illustre pour l’échange de clés hybride. La génération de mots de passe est plus simple, mais la leçon est la même : le mélange n’a de valeur qu’avec une construction sûre.

browserRandom = crypto.getRandomValues(...)
userRandom = collectKeyboardTimingAndMovement(...)
seed = HKDF-Extract(salt = browserRandom, inputKeyMaterial = userRandom)
bytes = HKDF-Expand(seed, info = "password-generator/v1" || context, length = neededBytes)
password = mapBytesToCharactersWithRejectionSampling(bytes)

En production : utiliser une KDF standard, un contexte explicite pour éviter les collisions d’usage, assez d’octets dérivés, et conserver l’échantillonnage par rejet sur les alphabets.

Faut-il se méfier du navigateur ?

Pour un usage courant, la Web Crypto API est la bonne base : le navigateur s’appuie sur le générateur aléatoire cryptographique de l’OS, conçu pour ce type de tâche.

En revanche, aucun générateur dans le navigateur ne résiste à un poste déjà compromis : code malveillant, extensions, presse-papiers, enregistrement des frappes.

D’où une défense en couches : navigateur de confiance, génération locale, aléa cryptographique, stockage dans un gestionnaire de mots de passe.

Évitez de transmettre le secret quand c’est possible. Si vous devez le partager, utilisez un canal sûr comme privatenote.ai, intégré à passwords.lu.

Pour choisir le bon canal, lisez notre guide sur le partage sécurisé (e-mail, messagerie, note sécurisée ou gestionnaire).

En pratique

Un bon générateur doit être « ennuyeux » au bon sens : aléa cryptographique, pas de biais, génération locale, hypothèses claires.

L’entrée utilisateur peut aider, mais la base reste la même : assez de longueur, un grand alphabet ou une bonne liste de mots, projection sans biais, et un secret issu d’une source cryptographique plutôt que de l’imagination.

Références

Générer un mot de passe localement

Essayez le générateur passwords.lu : le résultat reste dans votre navigateur et n’est pas envoyé à notre serveur.

Ouvrir le générateur de mots de passe