Generate password in python

前端 未结 9 1963
既然无缘
既然无缘 2020-12-12 21:51

I\'dl like to generate some alphanumeric passwords in python. Some possible ways are:

import string
from random import sample, choice
chars = string.letters          


        
相关标签:
9条回答
  • 2020-12-12 22:17

    Two recipes using the builtin secrets (python 3.6+)

    1. secrets.token_urlsafe

    This is much faster than the accepted answer. (see timings below)

    import secrets
    password = secrets.token_urlsafe(32)
    

    Example output:

    4EPn9Z7RE3l6jtCxEy7CPhia2EnYDEkE6N1O3-WnntU
    

    The argument for token_urlsafe is number of bytes. On average, one byte is 1.3 characters (base64 encoded).

    2. Enforce amount of digits/upper characters etc

    This is slighly modified copy from the docs of secrets. With this you have more fine grained control on how to generated passwords have to look. Of course, this is not fast option if you need to generate a lot of passwords.

    • Forcing length to be 20 characters
    • Forcing at least 4 lower case character
    • Forcing at least 4 upper case characters
    • Forcing at least 4 digits
    • Special characters can be added to alphabet. In this example, there are just - and _ added.
    import string
    import secrets
    alphabet = string.ascii_letters + string.digits + '-_'
    while True:
        password = ''.join(secrets.choice(alphabet) for i in range(20))
        if (sum(c.islower() for c in password) >=4
                and sum(c.isupper() for c in password) >=4
                and sum(c.isdigit() for c in password) >=4):
            break
    

    Example output:

    HlxTm2fcFE54JA1I_Yp5
    

    3. "I don't need the finer-grained control"

    If considered speed, you can also drop the while-loop. In this case, it actually simplifies to gerrit's answer (but then you loose the finer-grained control):

    import string
    import secrets
    alphabet = string.ascii_letters + string.digits + '-_'
    password = ''.join(secrets.choice(alphabet) for i in range(20))
    

    Speed comparison

    1. secrets.token_urlsafe

    1.62 µs ± 96.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
    

    2. Enforce amount of digits/upper characters etc

    107 µs ± 11.9 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    

    3. "I don't need the finer-grained control"

    77.2 µs ± 9.31 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    

    Speed comparison setup: python 3.8.5 64-bit on Win10, 43 characters in each password (=32 bytes for token_urlsafe).

    0 讨论(0)
  • 2020-12-12 22:19

    WARNING this answer should be ignored due to critical security issues!

    Option #2 seems quite reasonable except you could add a couple of improvements:

    ''.join(choice(chars) for _ in range(length))          # in py2k use xrange
    

    _ is a conventional "I don't care what is in there" variable. And you don't need list comprehension there, generator expression works just fine for str.join. It is also not clear what "slow" means, if it is the only correct way.

    0 讨论(0)
  • 2020-12-12 22:19

    I think this'll do the trick. random.SystemRandom uses the same underlying crypto random function as os.urandom but it uses the familiar random interface. This function won't be subject to the weird 128 byte thing as in Ben's answer.

    import random
    import string
    
    def gen_random_string(char_set, length):
        if not hasattr(gen_random_string, "rng"):
            gen_random_string.rng = random.SystemRandom() # Create a static variable
        return ''.join([ gen_random_string.rng.choice(char_set) for _ in xrange(length) ])
    
    password_charset = string.ascii_letters + string.digits
    gen_random_string(password_charset, 32)
    
    0 讨论(0)
  • 2020-12-12 22:20

    For the crypto-PRNG folks out there:

    def generate_temp_password(length):
        if not isinstance(length, int) or length < 8:
            raise ValueError("temp password must have positive length")
    
        chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
        from os import urandom
        return "".join(chars[ord(c) % len(chars)] for c in urandom(length))
    

    Note that for an even distribution, the chars string length ought to be an integral divisor of 128; otherwise, you'll need a different way to choose uniformly from the space.

    0 讨论(0)
  • 2020-12-12 22:27

    You should use the secrets module to generate cryptographically safe passwords, which is available starting in Python 3.6. Adapted from the documentation:

    import secrets
    import string
    alphabet = string.ascii_letters + string.digits
    password = ''.join(secrets.choice(alphabet) for i in range(20))  # for a 20-character password
    

    For more information on recipes and best practices, see this section on recipes in the Python documentation. You can also consider adding string.punctuation or even just using string.printable for a wider set of characters.

    0 讨论(0)
  • 2020-12-12 22:27

    I suggest the following for those stuck on python <3.6:

    import os, math, string, struct
    
    def generate_password(pass_len):
        symbols = string.printable.strip()
        return ''.join([symbols[x * len(symbols) / 256] for x in struct.unpack('%dB' % (pass_len,), os.urandom(pass_len))])
    

    This has the advantage over Ben Mosher's solution that the each symbol from symbols has an equal change of occurring whereas using modulus slightly favors the first symbols in the alpabet. The alphabet of symbols is also larger in this suggestion.

    0 讨论(0)
提交回复
热议问题