Il y a deux jours à peine, Kragen Javier Sitaker a mis en ligne un programme permettant de faire cela à l'adresse suivante http://lists.canonical.org/pipermail/kragen-hacks/2011-September/000527.html (disparu maintenant - essayez https://github.com/jesterpm/bin/blob/master/mkpasswd )
Générer un mot de passe aléatoire et mémorisable : http://xkcd.com/936/
Exemple d'exécution :
kragen at inexorable:~/devel/inexorable-misc$ ./mkpass.py 5 12 Votre mot de passe est "learned damage saved residential stages". C'est l'équivalent d'une clé de 60 bits.
Il faudrait 2,5e+03 années-processeur pour craquer ce mot de passe sur mon Celeron E1200 bon marché de 2008, en supposant une attaque hors ligne sur un hachage MS-Cache, qui est le pire algorithme de hachage de mot de passe couramment utilisé, légèrement pire que le simple MD5.
L'algorithme de hachage de mot de passe le plus courant de nos jours est le MD5 itéré de FreeBSD ; le craquage d'un tel hachage prendrait 5.2e+06 années-processeur.
Mais un GPU moderne peut craquer environ 250 fois plus vite, de sorte que le même MD5 itéré tomberait en 2e+04 GPU-années.
Le fonctionnement de ce GPU coûte environ 1,45 dollar par jour en 2011, et le craquage du mot de passe coûterait donc environ 3e+09 dollars.
J'ai commencé à utiliser un mot de passe généré de cette manière à la place d'un mot de passe aléatoire à 9 caractères ASCII imprimables, qui est tout aussi fort. L'affirmation de Munroe selon laquelle ces mots de passe sont beaucoup plus faciles à mémoriser est correcte. Cependant, il y a toujours un problème : comme il y a beaucoup moins de bits d'entropie par caractère (environ 1,7 au lieu de 6,6), il y a beaucoup de redondance dans le mot de passe, et donc des attaques telles que l'attaque ssh par canal temporel (l'attaque Song, Wagner et Tian Herbivore, que j'ai apprise de Bram Cohen au Bagdad Café au petit matin, il y a des années) et les attaques par enregistrement audio du clavier ont beaucoup plus de chances de capturer suffisamment d'informations pour rendre le mot de passe attaquable.
Ma contre-mesure à l'attaque Herbivore, qui fonctionne bien avec un mot de passe à 9 caractères mais est extrêmement gênante avec mon nouveau mot de passe, est de taper le mot de passe avec un délai d'une demi-seconde entre les caractères, de sorte que le canal de synchronisation ne porte pas beaucoup d'informations sur les caractères réellement utilisés. De plus, la longueur plus faible du mot de passe à 9 caractères donne intrinsèquement à l'approche Herbivore beaucoup moins d'informations à mâcher.
Parmi les autres contre-mesures possibles, citons l'utilisation du mode shell d'Emacs, qui vous demande localement le mot de passe lorsqu'il reconnaît une demande de mot de passe, puis envoie l'intégralité du mot de passe en une seule fois, et le copier-coller du mot de passe depuis un autre endroit.
Comme on peut s'y attendre, ce mot de passe est également un peu plus long à taper : environ 6 secondes au lieu de 3 secondes.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import random, itertools, os, sys
def main(argv):
try:
nwords = int(argv[1])
except IndexError:
return usage(argv[0])
try:
nbits = int(argv[2])
except IndexError:
nbits = 11
filename = os.path.join(os.environ['HOME'], 'devel', 'wordlist')
wordlist = read_file(filename, nbits)
if len(wordlist) != 2**nbits:
sys.stderr.write("%r contains only %d words, not %d.\n" %
(filename, len(wordlist), 2**nbits))
return 2
display_password(generate_password(nwords, wordlist), nwords, nbits)
return 0
def usage(argv0):
p = sys.stderr.write
p("Usage: %s nwords [nbits]\n" % argv0)
p("Generates a password of nwords words, each with nbits bits\n")
p("of entropy, choosing words from the first entries in\n")
p("$HOME/devel/wordlist, which should be in the same format as\n")
p("<http://canonical.org/~kragen/sw/wordlist>, which is a text file\n")
p("with one word per line, preceded by its frequency, most frequent\n")
p("words first.\n")
p("\nRecommended:\n")
p(" %s 5 12\n" % argv0)
p(" %s 6\n" % argv0)
return 1
def read_file(filename, nbits):
return [line.split()[1] for line in
itertools.islice(open(filename), 2**nbits)]
def generate_password(nwords, wordlist):
choice = random.SystemRandom().choice
return ' '.join(choice(wordlist) for ii in range(nwords))
def display_password(password, nwords, nbits):
print 'Your password is "%s".' % password
entropy = nwords * nbits
print "That's equivalent to a %d-bit key." % entropy
print
# My Celeron E1200
# (<http://ark.intel.com/products/34440/Intel-Celeron-Processor-E1200-(512K-Cache-1_60-GHz-800-MHz-FSB)>)
# was released on January 20, 2008. Running it in 32-bit mode,
# john --test (<http://www.openwall.com/john/>) reports that it
# can do 7303000 MD5 operations per second, but I’m pretty sure
# that’s a single-core number (I don’t think John is
# multithreaded) on a dual-core processor.
t = years(entropy, 7303000 * 2)
print "That password would take %.2g CPU-years to crack" % t
print "on my inexpensive Celeron E1200 from 2008,"
print "assuming an offline attack on a MS-Cache hash,"
print "which is the worst password hashing algorithm in common use,"
print "slightly worse than even simple MD5."
print
t = years(entropy, 3539 * 2)
print "The most common password-hashing algorithm these days is FreeBSD’s"
print "iterated MD5; cracking such a hash would take %.2g CPU-years." % t
print
# (As it happens, my own machines use Drepper’s SHA-2-based
# hashing algorithm that was developed to replace the one
# mentioned above; I am assuming that it’s at least as slow as the
# MD5-crypt.)
# <https://en.bitcoin.it/wiki/Mining_hardware_comparison> says a
# Core 2 Duo U7600 can do 1.1 Mhash/s (of Bitcoin) at a 1.2GHz
# clock with one thread. The Celeron in my machine that I
# benchmarked is basically a Core 2 Duo with a smaller cache, so
# I’m going to assume that it could probably do about 1.5Mhash/s.
# All common password-hashing algorithms (the ones mentioned
# above, the others implemented in John, and bcrypt, but not
# scrypt) use very little memory and, I believe, should scale on
# GPUs comparably to the SHA-256 used in Bitcoin.
# The same mining-hardware comparison says a Radeon 5870 card can
# do 393.46 Mhash/s for US$350.
print "But a modern GPU can crack about 250 times as fast,"
print "so that same iterated MD5 would fall in %.1g GPU-years." % (t / 250)
print
# Suppose we depreciate the video card by Moore’s law,
# i.e. halving in value every 18 months. That's a loss of about
# 0.13% in value every day; at US$350, that’s about 44¢ per day,
# or US$160 per GPU-year. If someone wanted your password as
# quickly as possible, they could distribute the cracking job
# across a network of millions of these cards. The cards
# additionally use about 200 watts of power, which at 16¢/kWh
# works out to 77¢ per day. If we assume an additional 20%
# overhead, that’s US$1.45/day or US$529/GPU-year.
cost_per_day = 1.45
cost_per_crack = cost_per_day * 365 * t
print "That GPU costs about US$%.2f per day to run in 2011," % cost_per_day
print "so cracking the password would cost about US$%.1g." % cost_per_crack
def years(entropy, crypts_per_second):
return float(2**entropy) / crypts_per_second / 86400 / 365.2422
if __name__ == '__main__':
sys.exit(main(sys.argv))
7 votes
Ces mots de passe sont-ils destinés aux humains ou aux machines ?
21 votes
@JarrodRoberson Affirmer que "aléatoire != cryptographie" est tout simplement flagrant en soi, puisque la cryptographie moderne est construite sur l'aléatoire. Tous les aléas ne sont pas égaux (par exemple, un mot de passe choisi au hasard parmi "password" et "passwords" n'est évidemment pas sûr), mais au fond, cryptographie = = aléa.
4 votes
N'est-ce pas ?
random.seed
une méthode, doncrandom.seed = 'random_string'
détruit essentiellement cette méthode et ne fait rien ? Voulez-vous direrandom.seed('random_string')
?1 votes
os.urandom(1024)
récupère 1024 octets. Cela me semble un peu excessif. Peut-être qu'un chargement de 16 ou 32 octets serait plus approprié.0 votes
Vous avez causé une telle confusion avec la formulation de cette question. Après avoir lu toutes les réponses, je ne suis plus sûr si vous vouliez un moyen plus efficace de générer un mot de passe aléatoire ou si vous vouliez un meilleur manière de générer un mot de passe en général. Je cherche simplement la première option et je l'ai heureusement trouvée tout en bas de la page.
0 votes
AlenSiljak Oui, c'est déroutant. Il nous serait utile de savoir laquelle des nombreuses implémentations vous a été utile pour vos besoins (par rapport à l'hypothèse faite par la réponse la mieux classée de Pornin concernant les mots de passe mémorisables par l'homme). Il serait également utile de savoir ce que vous recherchez dans un "mot de passe". D'après vos autres commentaires, il semble que vous utilisiez une application de stockage de mots de passe comme keepass. Une chaîne de bits brute non biaisée est bonne pour certains usages, mais à l'autre bout du spectre, de nombreux sites Web ont une variété d'exigences très spécifiques en matière de mots de passe, ce qui complique considérablement la tâche.
1 votes
@nealmcb, si vous le trouvez bénéfique - mon objectif était, comme indiqué dans la question, un "générateur de mot de passe aléatoire". Dans mon cas, il est utilisé pour le cryptage des jetons (JWT) de Flask pour l'accès aux API Web et, par conséquent, ma seule préoccupation est qu'il soit aléatoire. Et à une longueur prédéfinie. Par conséquent, je ne cherchais qu'une solution technique, pas une discussion sur ce qu'est un bon mot de passe / phrase. Oui, j'utilise des solutions de type KeePass exactement dans ce but. Ces choses sont des clés et ne valent pas la peine d'être mémorisées, à mon avis. Ne pas connaître un mot de passe est parfois une option plus sûre.
0 votes
Ahh, merci, @AlenSiljak. Quelle implémentation ici ("en bas de la page" ?) avez-vous fini par aimer pour générer des secrets JWT ?
0 votes
@nealmcb, j'ai fini par utiliser la réponse d'Avikd, qui utilise des lettres en minuscules et majuscules, des chiffres et des symboles prédéfinis, à une longueur donnée. Pour mon cas, c'est suffisant et est régénéré à chaque fois que le serveur API est redémarré. La valeur générée est utilisée comme clé secrète pour le hachage JWT.
0 votes
AlenSiljak Ahh - alors vous avez une réponse imparfaite. Je viens de tester cela, et j'ai ajouté un commentaire pour noter le gros biais dans les fréquences de sélection des caractères à travers l'alphabet qu'Avikd a utilisé. Il est vraiment préférable de n'utiliser que le code cryptographique le plus soigneusement vérifié.
0 votes
@nealmcb, c'est pourquoi je suis ici ;). Merci pour la recommandation de l'implémentation de l'algorithme de Pornin par foudfou ! J'apprécie beaucoup. Même si je n'en avais besoin que pour un petit projet de test, c'est toujours un plaisir d'apprendre quelque chose de nouveau. Par ailleurs, je vois que beaucoup de gens discutent des codes de passe, des mots et des phrases. C'est très intéressant mais probablement au-delà du sujet de cette question particulière. Mais c'est tout de même instructif.