视频演示链接:用python做的密码管理器
1.前言
自从迷上各种网站以后,各种注册压根停不下来,密码老是记不住是接触互联网的人都会遇到的问题。
有的人不管是什么密码,都统一用相同的密码,省去了不必要的麻烦,但是如果某天随意一个账号密码泄露,坏人来入侵你简直易如反掌。(只要知道你手机号和一个密码,就可以去尝试登陆不同的网站,并不是什么平台都会有短信验证码这种安全操作的)
有的人会使用网上的密码管理器,看似安全,但是假如不法分子在软件上故意留了后门,那岂不是很危险。大数据时代,防人之心不可无啊!
这几天在学习python语言,倒不如来练练手,自己写一个简易的密码管理器,密码的规则只有你知道,设置不同符号就可以挡住暴力破解,每一个账号的密码都不相同,都不简单。
2.需求
① 输入不同账户名,就可以生成不同的可设置长度的密码;
② 也能够自己修改密码,并且更新密码文件;
③ 不想记密码,要有保存密码的文件,以后可以查看;
④ 密码文件不轻易被别人看到,能够加密、自动备份、隐藏。
(大神请绕路,不要尝试找我的漏洞,因为你一定找得到~小小百姓能够使用就可以啦,本文旨在分享学习心得)
3.问题思路
把账户名用哈希计算,得到固定长度的数据,比如SHA-512算法得到512位长度的数据,此过程不可逆。然后自行设置规则 —— 提取该数据的某一段、什么字符替换什么字符等,这个规则自行设定且要牢记。得到某一长度的密码后,连同账户名一起写入到文件中,这里可以使用python的字典来保存账号密码,对于后续多账号的管理操作会比较简单。然后使用RSA非对称加密来加密密码文件里的信息,在需要读取文件时,再用私钥去解密即可读取出文件内容。
关键点1:如果担心规则记不住,可以在提示信息里加以备注;
关键点2:RSA加解密中必须考虑到的密钥长度、明文长度和密文长度问题,对于1024长度的密钥,128字节(1024bits)-减去11字节正好是117字节,可以先对数据进行bas64加密, 再对加密后的内容使用rsa加密, 最后对rsa解密后的内容进行bas64解密。
关键点3:关于公钥密钥的保存,可以在代码里嵌入在线获取公钥密钥的方法(有点危险),也可以先把公钥密钥保存为pem文件放在本地,在代码里调用出公钥,只有在自己修改查看密码时将私钥文件放进特定路径再使用(安全系数更高)。
关键点4:每一次对密码文件的读写,都要经过加密、解密、备份的过程。加密过程是先读取文件里所有文本,经过加密再保存到文件里;解密过程是先读取文件的密文,经过解密后再将信息保存到文件里,对于文件的隐藏和备份,使用os.system()执行cmd命令。
4.开始办事
环境:WIN7 32位 python3.8.1
需要用到的包:hashlib,rsa,base64,os,re(注意有些自带了)
可以使用镜像源下载:pip install -i http://pypi.douban.com/simple --trusted-host pypi.douban.com hashlib(需要下载哪个包,就把黄色名字改成包名)
查看是否有某个工具包的方法:进入cmd,先输入python,再输入import+包名,如果有这个工具包,则不会报错。
![](https://i-blog.csdnimg.cn/blog_migrate/43974edb5a9d659c89d81f1103b6ce91.png)
文件操作 |
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True)
参数 | 用途 |
---|---|
file | 必需,文件路径(相对或者绝对路径) |
mode | 可选,文件打开模式 |
模式 | 描述 |
---|---|
r | 以只读方式打开文件,这是默认模式 |
w | 打开一个文件只用于写入,如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
2、file.read()方法
read() 方法用于从文件读取指定的字节数,如果未给定或为负则读取所有
3、file.readlines()方法
readlines() 方法用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for… in … 结构进行处理。 如果碰到结束符 EOF 则返回空字符串。
4、file.write()方法
write() 方法用于向文件中写入指定字符串。如果文件打开模式带 b,那写入文件内容时,str (参数)要用 encode 方法转为 bytes 形式,否则报错:TypeError: a bytes-like object is required, not ‘str’。
示例:
在F:\MyPwd\b.txt下,输入如下内容:
123
456
789
{
123}
新建一个.py文件,然后运行代码
file_path = "F:\\MyPwd\\b.txt" #使用绝对路径
f = open(file_path,'r')
read_data = f.read()
readlines_data = f.readlines()
f.close() #记得一定要关了文件
print('read_data:\n{}\ntype: {}\n\n'.format(read_data,type(read_data)))
print('readlines_data:\n{}\ntype: {}'.format(readlines_data,type(readlines_data)))
f = open(file_path,'w')
f.write('abcd')
f.close()
运行结果为:
readlines_data: #使用readlines读取文件,返回列表
['123\n', '456\n', '789\n', '{123}']
type: <class 'list'>
read_data: #使用read读取文件,返回字符串
123
456
789
{
123}
type: <class 'str'>
abcd #使用write写文件,将删除原有内容,再写入
鉴于此,先对密码文件的储存格式规划,在代码里,希望通过字典的方式来保存、调用信息,键值为账号名称,其值里再包含密码长度、密码内容,示例如下:
data = {
'张三': {
'len': '13', 'value': '1aswedwxdsaaa'},
'李四': {
'len': '12', 'value': '1aswedwxdsaa'},
'小五': {
'len': '11', 'value': '1aswedwxdsa'}
}
使用write()函数时,传入参数不能直接将字典传进去,否则报错:TypeError: write() argument must be str, not dict,所以可以规定,将键值存放在单数行,值存放在双数行
f = open(file_path,'w') #file_path和data在前文已定义
for k,v in data.items():#data.items()返回字典的某一项内容
#k为键值,写入在文件的单数行,如'张三'
#v为value,如{'len': '13', 'value': '1aswedwxdsaaa'}
f.write(str(k)+'\n') #主键值写完,回车
#x为键值,如'len' y为该键值对应的value,如'13'
for x,y in v.items(): #同理操作
f.write(str(x)+' ') #以空格隔开,方便后续分离
f.write(str(y)+' ')
f.write('\n') #次键值写完,回车
f.close()
运行结果如下,在txt文件可以看到:
张三 #主键值
len 13 value 1aswedwxdsaaa #以空格分开
李四
len 12 value 1aswedwxdsaa
小五
len 11 value 1aswedwxdsa
#最后一行是回车
现在已经完成将字典内容写入txt文件,内容是以字符串形式储存的,接下来是如何读取出txt文件的字符串,再转成字典格式呢?回忆上文的readlines()函数,使用它读取文件返回的是list类型数据
f = open(file_path,'r')
data = f.readlines()
print(data)
f.close()
返回的结果如下
['张三\n', 'len 13 value 1aswedwxdsaaa \n', '李四\n', 'len 12 value 1aswedwxdsaa \n', '小五\n', 'len 11 value 1aswedwxdsa \n']
返回的是列表,列表的每一项内容是字符串,因此可以接着对这个返回结果操作,将有用信息提取出来
print('原字典信息:\n{}\n\n'.format(data))#file_path和data在前文已定义
f = open(file_path,'r')
information = f.readlines()
name,lenth,value = [],[],[] #分别存放姓名、密码长度、密码
data = {
} #新建空白字典
for i in range(len(information)): #遍历所有信息条
if i % 2 == 0: # for循环从0开始,因此对应的是文件的第一行,即键值
s1 = information[i].replace('\n', '')#将字符串中的'\n'替换,即删除
name.append(s1) #添加到name列表
else: #对应的是主键值的value,如'len 13 value 1aswedwxdsaaa \n'
s2 = information[i].split() #将该字符串以空格分开组成新的列表,如['len', '13', 'value', '1aswedwxdsaaa']
lenth.append(s2[1]) #index=1对应长度的数值
value.append(s2[3]) #index=3对应密码的数值
for j in range(len(name)): #在所有账号中遍历
#新建字典,格式如下:
temp = {
name[j]:{
'len':lenth[j],'value':value[j]}}
data.update(temp) #在data字典里增加新的内容
f.close()
print('读取出的信息:\n{}\n\n'.format(data))
运行结果如下:
原字典信息:
{
'张三': {
'len':