Linux générateurs de mots de passe

Linux générateurs de mots de passe

Notes › PC1

Voici plusieurs options, de la plus simple à la plus complète.

1. En une ligne (shell)

1
2
3
4
5
6
7
8
# 24 caractères alphanumériques + symboles
tr -dc 'A-Za-z0-9!@#$%^&*()_+=-' < /dev/urandom | head -c 24; echo

# Avec openssl (base64, 24 caractères)
openssl rand -base64 18

# Avec pwgen (à installer : apt install pwgen / pacman -S pwgen)
pwgen -sy 24 5

2. Script shell

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env bash
# genpass.sh : génère N mots de passe de longueur L
# Usage : ./genpass.sh [longueur] [nombre]

LEN="${1:-24}"
COUNT="${2:-1}"
CHARS='A-Za-z0-9!@#$%^&*()_+=,.?-'

for _ in $(seq "$COUNT"); do
    LC_ALL=C tr -dc "$CHARS" < /dev/urandom | head -c "$LEN"
    echo
done
1
2
chmod +x genpass.sh
./genpass.sh 32 5

3. Script Python (recommandé)

Utilise le module secrets (cryptographiquement sûr, contrairement à random) et garantit au moins un caractère de chaque catégorie :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/bin/env python3
import argparse
import secrets
import string

def generate(length, symbols, no_ambiguous):
    lower = string.ascii_lowercase
    upper = string.ascii_uppercase
    digits = string.digits
    special = symbols

    if no_ambiguous:
        ambiguous = set("O0oIl1|`'\"")
        lower, upper, digits, special = (
            "".join(c for c in s if c not in ambiguous)
            for s in (lower, upper, digits, special)
        )

    pools = [lower, upper, digits]
    if special:
        pools.append(special)

    if length < len(pools):
        raise SystemExit(f"Longueur minimale : {len(pools)}")

    # Au moins un caractère de chaque catégorie
    chars = [secrets.choice(p) for p in pools]
    alphabet = "".join(pools)
    chars += [secrets.choice(alphabet) for _ in range(length - len(chars))]

    # Mélange sûr
    secrets.SystemRandom().shuffle(chars)
    return "".join(chars)

def main():
    p = argparse.ArgumentParser(description="Générateur de mots de passe")
    p.add_argument("-l", "--length", type=int, default=24)
    p.add_argument("-n", "--count", type=int, default=1)
    p.add_argument("-s", "--symbols", default="!@#$%^&*()-_=+[]{};:,.?",
                   help="symboles autorisés ('' pour aucun)")
    p.add_argument("-a", "--no-ambiguous", action="store_true",
                   help="exclure les caractères ambigus (O/0, l/1/I...)")
    args = p.parse_args()

    for _ in range(args.count):
        print(generate(args.length, args.symbols, args.no_ambiguous))

if __name__ == "__main__":
    main()

Exemples :

1
2
3
4
./genpass.py                    # 1 mot de passe de 24 caractères
./genpass.py -l 32 -n 5         # 5 mots de passe de 32 caractères
./genpass.py -l 20 -a           # sans caractères ambigus
./genpass.py -l 16 -s ''        # alphanumérique uniquement (sites qui refusent les symboles)

4. Passphrase (mots aléatoires, plus facile à retenir)

1
2
3
4
5
6
7
#!/usr/bin/env python3
import secrets

with open("/usr/share/dict/words") as f:   # apt install wamerican
    words = [w.strip() for w in f if w.strip().isalpha() and 4 <= len(w.strip()) <= 8]

print("-".join(secrets.choice(words) for _ in range(6)))

Conseils

  • Évite $RANDOM ou le module random de Python : non adaptés à la cryptographie.
  • Certains sites refusent certains symboles : prévois l’option sans symboles (-s '') en augmentant la longueur à 32 pour compenser.
  • Si tu utilises KeePassXC, son générateur intégré (et keepassxc-cli generate) fait aussi très bien le travail :
1
keepassxc-cli generate -L 24 -l -u -n -s

Diceware

1. Outil tout fait

1
2
3
pipx install diceware        # ou : pip install --user diceware
diceware -n 6 -d - --no-caps # 6 mots séparés par des tirets
diceware --help              # listes de mots disponibles (-w), dont d'autres langues selon la version

Alternative : xkcdpass (apt install xkcdpass).

2. Script Python avec la liste EFF

1
curl -O https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env python3
import argparse
import secrets

def load(path):
    # Format EFF : "11111<TAB>abacus"
    with open(path, encoding="utf-8") as f:
        return [line.split()[-1] for line in f if line.strip()]

def main():
    p = argparse.ArgumentParser(description="Générateur diceware")
    p.add_argument("-w", "--wordlist", default="eff_large_wordlist.txt")
    p.add_argument("-n", "--words", type=int, default=6)
    p.add_argument("-c", "--count", type=int, default=1)
    p.add_argument("-d", "--sep", default="-")
    p.add_argument("--digit", action="store_true",
                   help="ajoute un chiffre à la fin (sites qui l'exigent)")
    args = p.parse_args()

    words = load(args.wordlist)
    for _ in range(args.count):
        phrase = args.sep.join(secrets.choice(words) for _ in range(args.words))
        if args.digit:
            phrase += args.sep + str(secrets.randbelow(10))
        print(phrase)

    bits = args.words * len(words).bit_length()
    print(f"# ~{args.words * __import__('math').log2(len(words)):.0f} bits d'entropie",
          file=__import__('sys').stderr)

if __name__ == "__main__":
    main()
1
./diceware.py -n 7 -c 3

3. Shell pur (sans Python)

1
shuf --random-source=/dev/urandom -n 6 eff_large_wordlist.txt | cut -f2 | paste -sd'-'

4. Vrais dés

Lance 5 dés par mot, cherche le nombre obtenu (ex. 43125) dans la liste :

1
grep -P '^43125\t' eff_large_wordlist.txt

Entropie

La liste EFF large contient 7776 mots (6⁵), soit environ 12,9 bits par mot :

Mots Entropie
5 ~65 bits (minimum pour un usage courant)
6 ~77 bits (bon compromis)
7 ~90 bits (mot de passe maître, chiffrement de disque)

L’entropie vient du tirage aléatoire, pas des mots eux-mêmes. Ne choisis jamais les mots toi-même et ne relance pas jusqu’à obtenir une phrase qui te plaît. Pour un mot de passe maître KeePassXC ou une passphrase LUKS, 7 mots est un bon choix.

Tags tendance