That way works. It is perfectly fine. If you had additional rules, such as excluding dictionary words, then you may want to include those filters as well, but the likelihood of randomly generating a dictionary word with that setup is extremely small.
XKCD has a great explanation of why what you think are strong passwords aren't.
To anyone who understands information theory and security and is in an
infuriating argument with someone who does not (possibly involving
mixed case), I sincerely apologize. - Randall Munroe
And if you don't understand the math behind what this illustration is explaining, don't try writing anything that should be cryptographically secure, because it won't be. Just put the mouse down and step away from the keyboard.
kragen at inexorable:~/devel/inexorable-misc$ ./mkpass.py 5 12 Your password is "learned damage saved residential stages". That's equivalent to a 60-bit key.
That password would take 2.5e+03 CPU-years to crack on my inexpensive Celeron E1200 from 2008, assuming an offline attack on a MS-Cache hash, which is the worst password hashing algorithm in common use, slightly worse than even simple MD5.
The most common password-hashing algorithm these days is FreeBSD’s iterated MD5; cracking such a hash would take 5.2e+06 CPU-years.
But a modern GPU can crack about 250 times as fast, so that same iterated MD5 would fall in 2e+04 GPU-years.
That GPU costs about US$1.45 per day to run in 2011, so cracking the password would cost about US$3e+09.
I've started using a password generated this way in place of a 9-printable- ASCII-character random password, which is equally strong. Munroe's assertion that these passwords are much easier to memorize is correct. However, there is still a problem: because there are many fewer bits of entropy per character (about 1.7 instead of 6.6) there is a lot of redundancy in the password, and so attacks such as the ssh timing-channel attack (the Song, Wagner, and Tian Herbivore attack, which I learned about from Bram Cohen in the Bagdad Café in the wee hours one morning, years ago) and keyboard audio recording attacks have a much better chance of capturing enough information to make the password attackable.
My countermeasure to the Herbivore attack, which works well with 9-character password but is extremely annoying with my new password, is to type the password with a half-second delay between characters, so that the timing channel does not carry much information about the actual characters used. Additionally, the lower length of the 9-character password inherently gives the Herbivore approach much less information to chew on.
Other possible countermeasures include using Emacs shell-mode, which prompts you locally for the password when it recognizes a password prompt and then sends the whole password at once, and copying and pasting the password from somewhere else.
As you'd expect, this password also takes a little while longer to type: about 6 seconds instead of about 3 seconds.
#!/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))
You can't trust python's pseudo random number generator when generating a password. It is not necessarily cryptographically random. You are seeding the pseudo random number generator from os.urandom which is a good start. But then you depend on python's generator after that.
A better choice would be the random.SystemRandom() class which takes random numbers from the same source as urandom. According to the python documentation that should be good enough for cryptographic use. The SystemRandom class gives you everything that the main random class does but you don't need to worry about the pseudorandomness.
Example code using random.SystemRandom (for Python 3):
import random, string
length = 13
chars = string.ascii_letters + string.digits + '!@#$%^&*()'
rnd = random.SystemRandom()
print(''.join(rnd.choice(chars) for i in range(length)))
Note: Your mileage may vary - the Python Documentation says that random.SystemRandom availability varies by operating system.
I just need to be able to generate passwords that are more secure than the ones I would come up with in my head.
it seems you want to use your program to generate passwords, rather than just writing it as an exercise. It is preferable to use an existing implementation, because if you make a mistake, the output might be compromised. Read about random number generator attacks; in particular, a well-known RNG bug in Debian exposed people's SSL private keys.
So instead, consider using pwgen. It provides several options, which you should choose depending on what you plan to use the passwords for.
The difficult thing with passwords is to make them strong enough and still be able to remember them. If the password is not meant to be remembered by a human being, then it is not really a password.
You use Python's os.urandom(): that's good. For any practical purpose (even cryptography), the output of os.urandom() is indistinguishable from true alea. Then you use it as seed in random, which is less good: that one is a non-cryptographic PRNG, and its output may exhibit some structure which will not register in a statistical measurement tool, but might be exploited by an intelligent attacker. You should work with os.urandom() all along. To make things simple: choose an alphabet of length 64, e.g. letters (uppercase and lowercase), digits, and two extra punctuation characters (such as '+' and '/'). Then, for each password character, get one byte from os.urandom(), reduce the value modulo 64 (this is unbiased because 64 divides 256) and use the result as index in your chars array.
With an alphabet of length 64, you get 6 bits of entropy per character (because 26 = 64). Thus, with 13 characters, you get 78 bits of entropy. This is not ultimately strong in all cases, but already very strong (it could be defeated with a budget which will be counted in months and billions of dollars, not mere millions).
Here is another implementation (python 2; would require some minor rewrites to get it working in 3) that is much faster than OJW's, which seems to loop through the dictionary for each word, despite the comment/implication to the contrary. Timing of OJW's script on my machine, with an 80,000 IOP SSD:
real 0m3.264s
user 0m1.768s
sys 0m1.444s
The following script loads the whole dictionary into a list, then picks words based on a random selection of the index value, using OJW's regex for filtering.
This also generates 10 passphrase sets, allows passing command-line parameters to adjust the number of words, and adds number and symbol padding (also adjustable length).
Sample times for this script:
real 0m0.289s
user 0m0.176s
sys 0m0.108s
Usage: xkcdpass-mod.py 2 4 (for example; these are the default values).
It prints spaces in the output for easy reading, although I've almost never encountered an online service that allows using them, so I would just ignore them. This could definitely be cleaned up with argparse or getopt and allowing switches for including spaces or not, including/excluding symbols, capitals, etc., plus some additional refactoring, but I haven't gotten to that yet. So, without further ado:
#!/usr/bin/env python
#Copyright AMH, 2013; dedicated to public domain.
import os, re, sys, random
from sys import argv
def getargs():
if len(argv) == 3:
numwords = argv[1]
numpads = argv[2]
return(numwords, numpads)
elif len(argv) == 2:
numwords = argv[1]
numpads = 4
return (numwords, numpads)
else:
numwords = 2
numpads = 4
return (numwords, numpads)
def dicopen(dictionary="/usr/share/dict/american-english"):
f = open(dictionary, "r")
dic = f.readlines()
return dic
def genPassword(numwords, numpads):
r = random.SystemRandom()
pads = '0123456789!@#$%^&*()'
padding = []
words = dicopen()
wordlist = []
for i in range (0,int(numpads)):
padding.append(pads[r.randint(0,len(pads)-1)])
#initialize counter for only adding filtered words to passphrase
j = 0
while (j < int(numwords)):
inclusion_criteria = re.compile('^[a-z]{5,10}$')
#Select a random number, then pull the word at that index value, rather than looping through the dictionary for each word
current_word = words[r.randint(0,len(words)-1)].strip()
#Only append matching words
if inclusion_criteria.match(current_word):
wordlist.append(current_word)
j += 1
else:
#Ignore non-matching words
pass
return(" ".join(wordlist)+' '+''.join(padding))
if(__name__ == "__main__"):
for i in range (1,11):
print "item "+str(i)+"\n"+genPassword(getargs()[0], getargs()[1])
According to https://www.grc.com/haystack.htm, for all practical purposes, assuming 100 trillion guesses per second (i.e., 100 TH/s) the shorter version would take about 50-60 million centuries to crack; the full CHBS = 1.24 hundred trillion trillion centuries; adding padding to that, 15.51 trillion trillion trillion centuries.
Even enlisting the entire Bitcoin mining network (~2500 TH/s as of this writing), the short version would still likely take 250-300 million years to break, which is probably secure enough for most purposes.
I know this question was posted back in 2011, but for those coming to it now in 2014 and beyond, I have one thing to say: RESIST THE URGE TO REINVENT THE WHEEL.
In these situations your best bet is to search for open-source software, e.g., constrain your search to github results. By far the best thing I've found:
This does not seed the random number generator; it replaces the seed function with a bytestring. You need to call seed, like, random.seed(…).
print ''.join(random.choice(chars) for i in range(length))
Python's default PRNG is a Mersenne Twister, which is not a cryptographically strong PRNG, so I'm wary of using it for cryptographic purposes. The random module includes random.SystemRandom, which on at least most *nix systems, should use a CSPRNG. However,
random.choice(chars)
…is implemented as…
def choice(self, seq):
"""Choose a random element from a non-empty sequence."""
return seq[int(self.random() * len(seq))] # raises IndexError if seq is empty
…in Python 2. Unfortunately, self.random here is a C function, so this gets hard to see; the code smell here is that this code almost certainly doesn't choose uniformly. The code has completely changed in Python 3, and does a much better job of ensuring uniformity. The Python 3 docs for randrange note,
Changed in version 3.2: randrange() is more sophisticated about producing equally distributed values. Formerly it used a style like int(random()*n) which could produce slightly uneven distributions.
randrange and choice both call the same method (_randbelow) under the hood.
In Python 3, choice is fine; in Python 2, it only comes close to a uniform distribution, but does not guarantee it. Since this is crypto, I lean on the "take no chances" side of the fence, and would like to have that guarantee.
import random
r = random.SystemRandom()
def generate_password(words, top=2000, k=4, numbers=None, characters=None,
first_upper=True):
"""Return a random password based on a sorted word list."""
elements = r.sample(words[:top], k)
if numbers:
elements.insert(r.randint(1, len(elements)), r.choice(numbers))
if characters:
elements.insert(r.randint(1, len(elements)), r.choice(characters))
if first_upper:
elements[0] = elements[0].title()
return ''.join(elements)
if __name__ == '__main__':
with open('./google-10000-english-usa.txt') as f:
words = [w.strip() for w in f]
print(generate_password(words, numbers='0123456789', characters='!@#$%'))
Generates passwords that you can remember
Uses os.urandom()
Handles real-world rules like adding numbers, uppercase, characters.
Wrote a password generator using argparse.
Hope this helps someone (either building a password generator or using argparse)!
Either way, it was fun to build!
$ ./pwgen.py -h
usage: pwgen.py [-h] [-c COUNT] [-a] [-l] [-n] [-s] [-u] [-p]
Create a random password
Special characters, numbers, UPPERCASE -"Oscar",
and lowercase -"lima" to avoid confusion.
Default options (no arguments): -c 16 -a
Enjoy! --0NetEnv@gmail.com
optional arguments:
-h, --help show this help message and exit
-c COUNT, --count COUNT
password length
-a, --all same as -l -n -s -u
-l, --lower include lowercase characters
-n, --number include 0-9
-s, --special include special characters
-u, --upper include uppercase characters
-p, --license print license and exit
Here's the code:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
license = """
# pwgen -- the pseudo-random password generator
#
# This software is distributed under the MIT license.
#
# The MIT License (MIT)
#
# Copyright (c) 2016 0NetEnv 0netenv@gmail.com
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without
# limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions
# of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
# ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
# TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
# SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
# IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
# NOTE:
# This software was tested on Slackware 14.2, Raspbian, &
# Mac OS X 10.11
#
"""
import string
import random
import sys
# first time using argparse library
import argparse
# wanted to change the formatting of the help menu a little bit, so used RawTextHelpFormatter directly
from argparse import RawTextHelpFormatter
typo = ''
c = 16
counter = 0
line = '-' * 40
# CREATE FUNCTION for PWGEN
def pwgen(z, t):
# EMPTY SET OF CHARACTERS
charsset = ''
# UPPERCASE -"O"
U = 'ABCDEFGHIJKLMNPQRSTUVWXYZ'
# lowercase -"l"
L = 'abcdefghijkmnopqrstuvwxyz'
N = '0123456789'
S = '!@#$%^&*?<>'
# make sure we're using an integer, not a char/string
z = int(z)
for type in t:
if 'u' in t:
charsset = charsset + U
if 'l' in t:
charsset = charsset + L
if 'n' in t:
charsset = charsset + N
if 's' in t:
charsset = charsset + S
if 'a' == t:
charsset = charsset + U + L + N + S
return ''.join(random.choice(charsset) for _ in range(0, int(z)))
# GET ARGUMENTS using ARGPARSE
parser = argparse.ArgumentParser(description='\n Create a random password\n\
Special characters, numbers, UPPERCASE -"Oscar",\n\
and lowercase -"lima" to avoid confusion.\n\
Default options (no arguments): -c 16 -a\n\
\t\tEnjoy! --0NetEnv@gmail.com', formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("-c", "--count", dest="count", action="store", help="password length")
parser.add_argument("-a", "--all", help="same as -l -n -s -u", action="store_true")
parser.add_argument("-l", "--lower", help="include lowercase characters", action="store_true")
parser.add_argument("-n", "--number", help="include 0-9", action="store_true")
parser.add_argument("-s", "--special", help="include special characters", action="store_true")
parser.add_argument("-u", "--upper", help="include uppercase characters", action="store_true")
parser.add_argument("-p", "--license", help="print license and exit", action="store_true")
# COLLECT ARGPARSE RESULTS
results = args = parser.parse_args()
# CHECK RESULTS
# Check that a length was given.
# If not, gripe and exit.
if args.count == '0':
print ("Input error:\nCannot create a zero length password.\nExiting")
exit (0)
# check character results and add to counter if
# selection is made.
if args.lower:
typo = typo + 'l'
counter = counter + 1
#print "lower"
if args.number:
typo = typo + 'n'
counter = counter + 1
#print "number"
if args.special:
typo = typo + 's'
counter = counter + 1
#print "special"
if args.upper:
typo = typo + 'u'
counter = counter + 1
#print "upper"
if args.all:
typo = 'a'
counter = counter + 1
#print "all"
if args.license:
print (license)
exit (1)
# CHECK COUNTER
# Check our counter and see if we used any command line
# options. We don't want to error out.
# try it gracefully. If no arguments are given,
# use defaults and tell the user.
# args.count comes from argparse and by default requires
# an input to '-c'. We want to get around that for the
# sake of convenience.
# Without further adieu, here's our if statement:
if args.count:
if counter == 0:
typo = 'a'
print ("defaulting to '--all'")
print (line)
print (pwgen(results.count,typo))
else:
if counter == 0:
typo = 'a'
print ("defaulting to '--count 16 --all'")
print (line)
print (pwgen(c,typo))
print (line)
#print typo
This is a simple small program addressed to people whome can't figure out a secure passwords for there own public accounts.
Just run the program on a command console and pass in a bunch of letters that seems familiar to you, and it will generate a sequence of symbols based on what you've inserted.
of course, the program does not support multiple sequences generation.
from string import ascii_lowercase, ascii_uppercase, digits, punctuation
from random import randint, choice, shuffle
from math import ceil
from re import finditer
lower_cases = ascii_lowercase
upper_cases = ascii_uppercase
lower_upper = dict(zip(lower_cases, upper_cases))
upper_lower = dict(zip(upper_cases, lower_cases))
punctuations = '#$%&@!?.'
space = ' '
class PunctOrDigit():
def __init__(self, number_of_punctuations, number_of_digits):
self.puncts = number_of_punctuations
self.digits = number_of_digits
self.dupl_puncts = self.puncts
self.dupl_digits = self.digits
def PorD(self):
symbol_type = choice('pd')
if symbol_type == 'p':
if self.puncts == 0:
return 'd'
else:
self.puncts -= 1
return symbol_type
if symbol_type == 'd':
if self.digits == 0:
return 'p'
else:
self.digits -= 1
return symbol_type
def reset(self):
self.puncts = self.dupl_puncts
self.digits = self.dupl_digits
def is_empty(text):
for symbol in text:
if symbol != space:
return False
return True
def contain_unauthorized_symbols(text):
for symbol in text:
if symbol in punctuation or symbol in digits:
return True
return False
def user_input():
user_input = input('-- Sentence to transform: ')
while is_empty(user_input) or len(user_input) < 8 or contain_unauthorized_symbols(user_input):
user_input = input('-- Sentence to transform: ')
return user_input
def number_of_punctuations(text):
return ceil(len(text) / 2) - 3
def number_of_digits(text):
return ceil(len(text) / 2) - 2
def total_symbols(text):
return (number_of_digits(text) + number_of_punctuations(text),
number_of_punctuations(text),
number_of_digits(text))
def positions_to_change(text):
pos_objct = PunctOrDigit(number_of_punctuations(text), number_of_digits(text))
positions = {}
while len(positions) < total_symbols(text)[0]:
i = randint(0,len(text)-1)
while i in positions:
i = randint(0,len(text)-1)
positions[i] = pos_objct.PorD()
pos_objct.reset()
return positions
def random_switch(letter):
if letter in lower_cases:
switch_or_pass = choice('sp')
if switch_or_pass == 's': return lower_upper[letter]
else: return letter
if letter in upper_cases:
switch_or_pass = choice('sp')
if switch_or_pass == 's': return upper_lower[letter]
else: return letter
def repeated(text):
reps = {}
for letter in set(list(text)):
indexs = [w.start() for w in finditer(letter, text)]
if letter != ' ':
if len(indexs) != 1:
reps[letter] = indexs
return reps
def not_repeated(text):
reps = {}
for letter in set(list(text)):
indexs = [w.start() for w in finditer(letter, text)]
if letter != ' ':
if len(indexs) == 1:
reps[letter] = indexs
return reps
def generator(text, positions_to_change):
rep = repeated(text)
not_rep = not_repeated(text)
text = list(text)
for x in text:
x_pos = text.index(x)
if x not in positions_to_change:
text[x_pos] = random_switch(x)
for x in rep:
for pos in rep[x]:
if pos in positions_to_change:
if positions_to_change[pos] == 'p':
shuffle(list(punctuations))
text[pos] = choice(punctuations)
if positions_to_change[pos] == 'd':
shuffle(list(digits))
text[pos] = choice(digits)
for x in not_rep:
for pos in not_rep[x]:
if pos in positions_to_change:
if positions_to_change[pos] == 'p':
shuffle(list(punctuations))
text[pos] = choice(punctuations)
if positions_to_change[pos] == 'd':
shuffle(list(digits))
text[pos] = choice(digits)
text = ''.join(text)
return text
if __name__ == '__main__':
x = user_input()
print(generator(x, positions_to_change(x)))
This will generate a random password with 1 random uppercase letter, 3 random lowercase letters, 3 random digits, and 1 random special character--this can be adjusted as needed. Then it combines each random character and creates a random order. I don't know if this is considered "high quality", but it gets the job done.
I love linguistics, in my approach I create memorable pseudo words with high level of entropy by alternating consonants & vowels.
Not susceptible to dictionary attacks
Pronounceable and therefore good chance to be
memorable
Short passwords with decent strength
Optional parameter to add a random digit for compatibility (less memorable, but conforms to apps built with the old password security thinking, e.g. requiring a digit)
Python code:
import random
import string
def make_pseudo_word(syllables=5, add_number=False):
"""Create decent memorable passwords.
Alternate random consonants & vowels
"""
rnd = random.SystemRandom()
s = string.ascii_lowercase
vowels = 'aeiou'
consonants = ''.join([x for x in s if x not in vowels])
pwd = ''.join([rnd.choice(consonants) + rnd.choice(vowels)
for x in range(syllables)]).title()
if add_number:
pwd += str(rnd.choice(range(10)))
return pwd
>>> make_pseudo_word(syllables=5)
'Bidedatuci'
>>> make_pseudo_word(syllables=5)
'Fobumehura'
>>> make_pseudo_word(syllables=5)
'Seganiwasi'
>>> make_pseudo_word(syllables=4)
'Dokibiqa'
>>> make_pseudo_word(syllables=4)
'Lapoxuho'
>>> make_pseudo_word(syllables=4)
'Qodepira'
>>> make_pseudo_word(syllables=3)
'Minavo'
>>> make_pseudo_word(syllables=3)
'Fiqone'
>>> make_pseudo_word(syllables=3)
'Wiwohi'
Cons:
for Latin and Germanic language speakers and those familiar with English
one should use vowels and consonants of the language predominant with the application users or focus group and tune
My solution based on @Thomas Pornin's answer (Updated)
import os, string
def get_pass(password_len=12):
new_password=None
symbols='+!'
chars=string.ascii_lowercase+\
string.ascii_uppercase+\
string.digits+\
symbols
while new_password is None or \
new_password[0] in string.digits or \
new_password[0] in symbols:
new_password=''.join([chars[ord(os.urandom(1)) % len(chars)] \
for i in range(password_len)])
return new_password
print(get_pass())
This function returns a random password (without a number or a symbol in beginning of the password).
"""
This code below in any shape or form is owned by A.S Gallery
This code is the asnwer for Password Generator quiz - CodeHs
This code works 100%
Have fun exploring !!!
"""
# Imports
import random
import time
print "Hi !!!"
password_output = "this is your new password : "
ask_name = input("Enter your Name : ")
greetings_name = "Hi "+ str(ask_name) + "!!! "
print greetings_name
print "Now we will make your new password using the ULTIMATE password generator !!!"
time.sleep(8)
print "Our password generator will give you multiple choices, you can choose any password generator you want !!! "
time.sleep(8)
print "You can choose if you want a strong password or a weak password !! (strong recommended) "
time.sleep(8)
print "You can also make your own password, to make your own password type own !!! "
time.sleep(8)
print "If you want to choose strong type strong, if weak then type weak !!! "
time.sleep(8)
# Example:
# Returns random number within and including 0 and 10.
def strong_password():
user_input = int(input("Enter a number : "))
print type(user_input)
time.sleep(3)
# calculate_input = user_input * user_input
calculate_types = input("Do you want to add, multiply or mod the numbers : ")
time.sleep(3)
if calculate_types == "add":
calculate_input = user_input + user_input
elif calculate_types == "multiply" :
calculate_input = user_input * user_input
elif calculate_types == "mod":
calculate_input = user_input & user_input
else:
print "Check your spelling and try again :( "
# Random element in a string
time.sleep(4)
want_symbols = input("Do you want symbols ?(Y/N) : ")
time.sleep(4)
random_element = random.choice('abcdefg345')
if want_symbols == "Y":
random_element2 = random.choice('@#()@*($*(@)(*^()*()(#$)*@#)*((@*()@*#)(*)@*($*(%#*)#(*@@_!_()(')
elif want_symbols == "N":
random_element2 = random.choice('29371294203712492703740182903820498201381204AKSJFKSHEHJKFJAODL')
random_element3 = random.choice('abcdefghiiasudasdjsiasdhwudagsjdgaskdjsafgjasj')
random_element4 = random.choice('abcdefghijsdhjaskdhkasjdhakdjhaskdasjdhakjsd')
random_element5 = random.choice('abcdefghijsdhsakjdhsajdldasjdasdjasldas')
random_elements6 = random.choice('129389230928308290382109830293943827492347')
random_elements7 = random.choice('2473285473q9mdnuwyr8KSDJKDSJKL932uc3487389473289479h3289wjdi94802w')
random_elements8 = random.choice('AKDJKAJDKJIKJDUIFHSJHUFRUDIJFDKLDJKDJLJFKLJKLDJLDJKLDJLDJLSKJDKLJDLJDKSLJD')
time.sleep(8)
print str(ask_name) + " " + str(password_output) + str(calculate_input) + str(random_element) + str(random_element2) + str(random_element3) + str(random_element4) + str(random_element5) + str(random_elements6) + str(random_elements7) + str(random_elements8)
def weak_password():
user_input = int(input("Enter a number : "))
print type(user_input)
time.sleep(3)
# calculate_input = user_input * user_input
calculate_types = input("Do you want to add, multiply or mod the numbers : ")
time.sleep(3)
if calculate_types == "add":
calculate_input = user_input + user_input
elif calculate_types == "multiply" :
calculate_input = user_input * user_input
elif calculate_types == "mod":
calculate_input = user_input & user_input
else:
time.sleep(3)
print "Check your spelling and try again :( "
# Random element in a string
random_ness = random.choice("ABCDEFGHI*(#*#$()#*$)(E)(UWIJEDSH(*#U$()UDSLKH)UW*)$(*&#*(YE(*DY#*YUHSLDF:LKDDSDK")
my_tuple = (calculate_input, random_ness, user_input, ask_name)
new_tuple = my_tuple[1]
new_tuple1 = my_tuple[2]
new_tuple2 = my_tuple[3]
time.sleep(7)
print str(ask_name) + str(password_output) + str(new_tuple) + str(new_tuple1) + str(new_tuple2)
def own_password():
my_list = []
ask_times = int(input("How many characters do you want ? (between 1 - 8) : "))
time.sleep(10)
if ask_times > 8:
print "Invalid Request"
elif ask_times < 1:
print "Invalid Request"
else:
time.sleep(2)
print "You CANNOT include symbols or numbers in this option !!! "
for i in range(ask_times):
user_ask = input("Enter the character: ")
time.sleep(0.6)
my_list.append(user_ask)
own_password = "".join(map(str,my_list))
time.sleep(4)
print "Your own password is : " + own_password
strong_pass = input("Do you want a strong password or a weak one or make your own password !! ? : ")
if strong_pass == "strong":
strong_password()
elif strong_pass == "weak":
weak_password()
elif strong_pass == "own":
own_password()
else :
print "Invalid Request"
time.sleep(3)
print "Congrats, on creating your best password !!! I belived you used strong password generator because its the BEST !!"
time.sleep(7)
print "If not, no problem just restart the program and type strong when prompted !!! "
time.sleep(6)
print "Have a nice day !"
This code is the answer for CodeHs Quiz too (if you had any ) !!!
Yes, no amatuer hacker is going to be cracking that password. Now, after this I recommend continuing on your random password generator project and make a UI or GUI interface either with Tkinter or Flask so others can use it. For example, I found this nice little project just by searching, 'password generator python UI'. https://passwordgenerator.pythonanywhere.com/
Maybe you'd like to make something similar to above? Its a good skill to know how to implement python into web development.