Mik*_* R. 68 python security random passwords
我有兴趣创建一个非常简单,高(加密)质量的随机密码生成器.有一个更好的方法吗?
import os, random, string
length = 13
chars = string.ascii_letters + string.digits + '!@#$%^&*()'
random.seed = (os.urandom(1024))
print ''.join(random.choice(chars) for i in range(length))
Run Code Online (Sandbox Code Playgroud)
Tho*_*nin 46
密码的难点在于使它们足够强大并且仍然能够记住它们.如果密码不是由人类记住的,那么它实际上不是密码.
你使用Python os.urandom():那很好.对于任何实际目的(甚至加密),输出os.urandom()与真正的alea无法区分.然后你用它作为种子random,这不太好:一个是非加密的PRNG,它的输出可能会展示一些不会在统计测量工具中注册的结构,但可能被智能攻击者利用.你应该一直工作os.urandom().为简单起见:选择长度为64的字母表,例如字母(大写和小写),数字和两个额外的标点字符(例如"+"和"/").然后,对于每个密码字符,从中获取一个字节os.urandom(),减少模64的值(这是无偏的,因为64除以256)并将结果用作chars数组中的索引.
使用长度为64的字母表,每个字符可获得6位熵(因为2 6 = 64).因此,对于13个字符,您将获得78位熵.在所有情况下,这并不是最终的强大,但已经非常强大(它可能被预算打败,预算将以数月和数十亿美元计算,而不仅仅是数百万美元).
小智 42
XKCD很好地解释了为什么你认为强密码不是.

对于任何理解信息理论和安全性的人,与那些没有(可能涉及混合案件)的人激怒的争论,我真诚地道歉. - Randall Munroe
如果你不理解这个插图所解释的背后的数学,不要尝试编写任何应该加密安全的东西,因为它不会.只需将鼠标放下并远离键盘即可.
Ric*_*ich 23
仅供在 2020 年以上遇到此问题的任何人使用。Python 3.6+ 有一个secrets专门用于此目的的模块:
import secrets
password_length = 13
print(secrets.token_urlsafe(password_length))
Run Code Online (Sandbox Code Playgroud)
Ros*_*ews 13
就在两天前,Kragen Javier Sitaker在http://lists.canonical.org/pipermail/kragen-hacks/2011-September/000527.html上发布了一个程序来实现这一目标(现在走了 - 试试https://github.com/jesterpm/bin/blob/master/mkpasswd)
生成一个随机的,可记忆的密码:http://xkcd.com/936/
示例运行:
kragen无情:〜/ devel/inexorable-misc $ ./mkpass.py 5 12您的密码是"学习损坏保存的住宅阶段".这相当于一个60位密钥.
假设对MS-Cache哈希进行离线攻击,这是常用的最差密码哈希算法,比简单的MD5差一点,那密码将花费2.5e + 03 CPU年来破解我的廉价Celeron E1200.
目前最常见的密码散列算法是FreeBSD的迭代MD5; 破解这样的哈希需要5.2e + 06 CPU-years.
但是现代GPU可以快速破解大约250倍,因此相同的迭代MD5将落在2e + 04 GPU年.
GPU在2011年的运行成本约为每天1.45美元,因此破解密码的成本约为3美元+ 09美元.
我开始使用以这种方式生成的密码代替9-printable-ASCII字符随机密码,这同样强大.Munroe断言这些密码更容易记忆是正确的.然而,仍然存在一个问题:因为每个字符的熵比较少(大约1.7而不是6.6),密码中存在大量冗余,因此诸如ssh定时信道攻击(Song, Wagner和Tian Herbivore的攻击,我在凌晨一年多的凌晨时分在BagdadCafé中从Bram Cohen那里了解到的,并且键盘录音攻击有更好的机会获取足够的信息以使密码可攻击.
我对草食动物攻击的对策,它与9个字符的密码配合得很好但是我的新密码非常烦人,就是输入字符之间延迟半秒的密码,这样定时通道就不会带来很多关于使用的实际字符.此外,9个字符密码的较低长度固有地为草食动物方法提供了更少的咀嚼信息.
其他可能的对策包括使用Emacs shell模式,它在识别密码提示时会在本地提示您输入密码,然后立即发送整个密码,并从其他地方复制并粘贴密码.
正如您所期望的那样,此密码也需要更长的时间来输入:大约6秒而不是大约3秒.
#!/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))
Run Code Online (Sandbox Code Playgroud)
yos*_*ssi 10
实施@Thomas Pornin解决方案
import M2Crypto
import string
def random_password(length=10):
chars = string.ascii_uppercase + string.digits + string.ascii_lowercase
password = ''
for i in range(length):
password += chars[ord(M2Crypto.m2.rand_bytes(1)) % len(chars)]
return password
Run Code Online (Sandbox Code Playgroud)
XKCD方法的另一个实现:
#!/usr/bin/env python
import random
import re
# apt-get install wbritish
def randomWords(num, dictionary="/usr/share/dict/british-english"):
r = random.SystemRandom() # i.e. preferably not pseudo-random
f = open(dictionary, "r")
count = 0
chosen = []
for i in range(num):
chosen.append("")
prog = re.compile("^[a-z]{5,9}$") # reasonable length, no proper nouns
if(f):
for word in f:
if(prog.match(word)):
for i in range(num): # generate all words in one pass thru file
if(r.randint(0,count) == 0):
chosen[i] = word.strip()
count += 1
return(chosen)
def genPassword(num=4):
return(" ".join(randomWords(num)))
if(__name__ == "__main__"):
print genPassword()
Run Code Online (Sandbox Code Playgroud)
样本输出:
$ ./randompassword.py
affluent afford scarlets twines
$ ./randompassword.py
speedboat ellipse further staffer
Run Code Online (Sandbox Code Playgroud)
我知道这个问题是在2011年发布的,但是对于那些现在在2014年及以后的人来说,我有一件事要说:抵制重建轮子的危险.
在这些情况下,最好的办法是搜索开源软件,例如,将搜索限制为github结果.到目前为止,我发现了最好的东西:
https://github.com/redacted/XKCD-password-generator
生成密码时,您不能信任 python 的伪随机数生成器。它不一定是加密随机的。您正在播种伪随机数生成器,os.urandom这是一个良好的开端。但是在那之后你依赖于python的生成器。
更好的选择是random.SystemRandom()从与urandom. 根据python文档,应该足以用于加密使用。该SystemRandom班给你的一切,主随机类做,但你并不需要对伪随机性担心。
使用 random.SystemRandom 的示例代码(适用于 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)))
Run Code Online (Sandbox Code Playgroud)
注意:您的里程可能会有所不同 - Python 文档说 random.SystemRandom 可用性因操作系统而异。