I'm 赵一开/BlahGeek, a CS&T Student @ Tsinghua U.

Get in touch:   See more:

我是如何管理密码的

某天突然意识到自己使用的各个网站都类似的密码太不安全了,于是下决心整改...

刚开始的想法是

  • 自己牢记一个通用的“密码”,只用于生成密码,记为p。
  • 将p做10次sha512sum。
  • 再加上使用密码的网站名称,比如p += "google"。
  • 再将p做10次sha512sum。
  • 取p的一个字串为该网站密码。

代码:

  for i in xrange(10):
      passwd = sha512(passwd).hexdigest()
  ret = passwd + domain
  for i in xrange(10):
      ret = sha512(ret).hexdigest()

为了减小暴力破解的可能

不应该直接使用生成的十六进制字符,因此将其转为Ascii码63~126中的字符。

splitLine = lambda s, n: [s[n*i:n*i+n] for i in xrange(len(s)/n)]
b = bin(int(s, 16)).partition('b')[2]
chs = splitLine(b, 6)
ret = [chr(int(ch, 2) + 63) for ch in chs]
return ''.join(ret)

当心身后的人

这样已经可以有效防止暴力破解以及网站泄密的情况,但无法防止站在身后的人“不小心”看到,因为生成密码时它会出现在屏幕上。

我使用的方法是,把生成的字符排列成10*8的矩阵,自己按照一定规则获得密码,比如“第2行第一个出现的小写字母开始的10个字符”,这样就算被看到了输出结果,也无法得到密码(不过会方便其暴力破解)。像这样:

> python mypasswd.py google
Password: 
lXNQ[br\]q
?Eod\oSnZJ
N^_t[QQGoY
CRxFlxMdUS
muMbQiJyV_
kftVs{`Fk|
_kmKionj@i
qyXEf|Jz_e

Easily Access

然后,算法确定了之后一个更加重要的事情就是在需要的时候要随时能得到结果。

命令行

上文已经实现。

passwd = getpass('Password: ')
domain = ' '.join(sys.argv[1:])
ret = '\n'.join(generate(passwd, domain))
print ret

GUI

调用zenity简单实现,再使用快捷键打开程序。

import subprocess
passwd = subprocess.check_output(
        ['zenity', '--password', '--title=My Password'])
domain = subprocess.check_output(
        ['zenity', '--entry', '--title=My Password', '--text=Domain:'])
ret = '\n'.join(generate(passwd, domain))
fname = os.path.join(gettempdir(), 'my_passwd')
with open(fname, 'w') as f:
    f.write(ret)
try:
    subprocess.check_output(
            ['zenity', '--width=50', '--height=330', '--text-info', \
             '--filename='+fname, '--font=Monospace 18', '--title=My Password'])
except subprocess.CalledProcessError:
    pass
os.remove(fname)

效果如下:

网页端

为了在手机上使用,还需要有个网页端。当然,是使用网页端的javascript计算,而不是发送至服务器端计算。像这样(在这里):

在iOS上可以将其添加到主屏幕。