您的位置:首页 > 编程语言 > Python开发

帐号密码管理器“passManager.py”

2016-12-15 00:00 99 查看
摘要: 密码管理 加密 python

前言

平时注册有很多电商购物和论坛的帐号,注册的帐号密码要求各不相同,所以登陆时经常忘记帐号或者密码,为此用python开发了一个小工具“passManager.py”来管理自己的帐号密码。

本工具在文件目录权限方面做了诸多权限限制以保证安全,并且采用了md5加密算法来保存登录密码,采用了RSA加密算法加密相关账号密码信息,只有linux账号所有者,并且注册了本软件才能使用并访问自己账号下的相关数据。

如果希望进一步提升安全性,建议在本机编译为pyc文件后使用。(python3.5 -m py_compile passManager.py)

如果任何建议或想法,欢迎交流指导 liyanqing1987@163.com。

开发环境:

OS : centos7

language : python3.5

使用环境:

linux,装有python3.5,Tk

使用界面:

1. register and login



2. save account and password for the specified project



3. Input project name and get account/password info



4. Get account/password info with full name project



5. Get account/password infos with short project name, it will show all of the matched projects



源代码:

#!/usr/bin/env python3.5

"""
This script is used to management your account/password informations for your projects (shopping, forum).
To guarantee the data security, this script do below things.
1. Set permission to "700" for all of the related drectories/scripts/database, so only the system user can access the his own data.
2. Use hashlib.md5 to encrypt the login password.
3. Use RAS to envrypt the saved password information.
It should be save if you make sure your system account is not stolen.

Author : liyanqing
Version 1.0
Wed Dec 14 23:40:40 CST 2016
"""

import os
import re
import sys
import getpass
import hashlib
import math
from tkinter import *
from tkinter import messagebox

os.environ["PYTHONUNBUFFERED"]="1"
titleBarName = "passManager"
user = getpass.getuser()
homeDir = "/home/" + str(user) + "/.passManager"

def createPermissionDir(dir, permission):
"""
If the directory is not exists, create it.
Set specified permission to the drictory.
"""
if not os.path.exists(dir) or not os.path.isdir(dir):
os.makedirs(dir)

try:
os.system('chmod ' + str(permission) + ' ' + str(dir))
except Exception as error:
print('*Error*: Failed to set directory permission for file ' + str(file) + ', ' + str(error))
messagebox.showerror(titleBarName, '*Error*: Failed to set directory permission for file ' + str(file) + ', ' + str(error))
sys.exit(1)

def createPermissionFile(file, permission):
 
7fe0
; """
If the file is not exists, create it.
Set specified permission to the file.
"""
if not os.path.exists(file) or not os.path.isfile(file):
os.mknod(file)

try:
os.system('chmod ' + str(permission) + ' ' + str(file))
except Exception as error:
print('*Error*: Failed to set file permission for ' + str(file) + ', ' + str(error))
messagebox.showerror(titleBarName, '*Error*: Failed to set file permission for ' + str(file) + ', ' + str(error))
sys.exit(1)

class encrypt():
"""
Use RSA to encrypt and decrypt string.
Use two input strings (script login account and password) to generate public/private keys.
"""
def __init__(self, string1, string2):
self.num1 = self.stringToAscii(string1)
self.num2 = self.stringToAscii(string2)
(self.N, self.e, self.d) = self.genRsaKey(self.num1, self.num2)

def stringToAscii(self, string):
asciiNum = 0

for char in string:
ascii = ord(char)
asciiNum += ascii

return(asciiNum)

def getMaxPrime(self, num):
if num < 2:
print('*Error*: No max prime number for number ' + str(num) + '.')

while (num > 1):
mark = 0
sqrt_num = int(math.sqrt(num))+1

for j in range(2,sqrt_num):
if num%j == 0:
mark = 1
break

if mark == 0:
return(num)
else:
num -= 1

def genRsaKey(self, num1, num2):
p = self.getMaxPrime(num1)
q = self.getMaxPrime(num2)
N = p*q
r = (p-1)*(q-1)
e = self.getMaxPrime(r)
d = 0

for d in range(2,r):
if (e*d)%r == 1:
break

return(N, e, d)

def encrypt(self, string):
"""
Encrypt the string with RSA, encrypt string chars one by one, the join the generated number with "#" to a new string.
"""
encryptedString = ""

for char in string:
char = ord(char)
encryptedChar = (int(char)**self.e)%self.N
if encryptedString == "":
encryptedString = str(encryptedChar)
else:
encryptedString = str(encryptedString) + '#' + str(encryptedChar)

return(encryptedString)

def decrypt(self, string):
"""
Based on the encrypt string generation, split the encrypt string with "#", decrypt it to charaters, then joins the chars to the original string.
"""
decryptedString = ""

for char in re.split('#', string):
char = (int(char)**self.d)%self.N
decryptedChar = chr(char)
decryptedString = str(decryptedString) + str(decryptedChar)

return(decryptedString)

class loginGUI():
"""
Login this script with specified account and password.
The login account and password are also be used to generate public/private keys on RSA.
"""
def __init__(self):
"""
"self.accountFile" is used to save the script account/password information, set the file permission to "700" for information protect.
"""
self.accountFile = str(homeDir) + '/account.txt'
createPermissionFile(self.accountFile, 700)

self.root = Tk()
self.root.geometry('800x200+200+200')
self.root.title(titleBarName)

# account could not be empty.
def accountCheck(self, account):
if re.match(r'^[ ]*$', account):
print('*Error*: account name cannot be empty!')
messagebox.showerror(titleBarName, '*Error*: password length should be longer than 6!')
return(1)

def passwordCheck(self, password):
"""
Password length should be longer than 6.
Password must be character or number.
"""
if len(password) < 6:
print('*Error*: password length should be longer than 6!')
messagebox.showerror(titleBarName, '*Error*: password length should be longer than 6!')
return(1)
elif not re.match(r'^\w+$', password):
print('*Error*: password must be character or number!')
messagebox.showerror(titleBarName, '*Error*: password must be character or number!')
return(1)

def toMd5(self, string):
"""
Encrypt the specified string with hashlib.md5, return a new string.
It always be used to save and validate login password.
"""
md5 = hashlib.md5()
md5.update(string.encode("utf-8"))
return(md5.hexdigest())

def login(self, account, password):
self.account = account
self.password = password
passwordMd5 = self.toMd5(password)
print('*Info*: login passManager with account ' + str(account) + '.')
if self.accountCheck(account) or self.passwordCheck(password):
return(1)

FL = open(self.accountFile, 'r')
for line in FL.readlines():
(registeredAccount, registeredPassword) = line.split()
if account == registeredAccount:
if passwordMd5 == registeredPassword:
FL.close()
print('*Info*: login pass for account ' + str(self.account) + '.')
self.root.destroy()
return(0)
else:
FL.close()
print('*Error*: password is incorrect!')
messagebox.showerror(titleBarName, '*Error*: password is incorrect!')
return(1)
FL.close()

print('*Error*: account name is incorrect!')
messagebox.showerror(titleBarName, '*Error*: account name is incorrect!')
return(1)

def register(self, account, password):
"""
Register login account/password, once be regiesterd, it cannot be updated any more.
"""
print('*Info*: register account ' + str(account) + '.')
FL = open(self.accountFile, 'r')
for line in FL.readlines():
(registeredAccount, registeredPassword) = line.split()
if account == registeredAccount:
print('*Error*: account ' + str(account) + ' have been registered!')
messagebox.showerror(titleBarName, '*Error*: account ' + str(account) + ' have been registered!')
FL.close()
return(1)
FL.close()

if self.accountCheck(account) or self.passwordCheck(password):
return(1)
elif str(account) == str(password):
print('*Error*: password should not be the same with account name!')
messagebox.showerror(titleBarName, '*Error*: password should not be the same with account name!')
return(1)

FL = open(self.accountFile, 'a')
password = self.toMd5(password)
FL.write(str(account) + ' ' + str(password) + '\n')
FL.close()
print('*Info*: register pass for account ' + str(self.account) + '.')

def loginGUI(self):
self.accountLable = Label(self.root, text='Account:')
self.accountLable.grid(row=1, column=1, sticky=W, ipadx=20, ipady=10)

self.accountEntryVar = StringVar()
self.account = Entry(self.root, textvariable=self.accountEntryVar, bg='white')
self.account.grid(row=1, column=2, sticky=W, ipadx=250, ipady=10)

self.passwordLabel = Label(self.root, text='Password:')
self.passwordLabel.grid(row=2, column=1, sticky=W, ipadx=20, ipady=10)

self.passwordEntryVar = StringVar()
self.passwordEntry = Entry(self.root, textvariable=self.passwordEntryVar, show='*', bg='white')
self.passwordEntry.grid(row=2, column=2, sticky=W, ipadx=250, ipady=10)

self.loginButton = Button(self.root, text='Login', command=lambda:self.login(self.accountEntryVar.get().strip(), self.passwordEntryVar.get().strip()), bg='blue')
self.loginButton.grid(row=3, column=2, ipadx=50, ipady=10)

self.registerButton = Button(self.root, text='Register', command=lambda:self.register(self.accountEntryVar.get().strip(), self.passwordEntryVar.get().strip()), bg='blue')
self.registerButton.grid(row=4, column=2, ipadx=50, ipady=10)

self.root.mainloop()

class getPasswordGUI():
"""
Save and get project informations, it contains project account and password.
If you only supply a short name, and several matched projects, show all of them.
"""
def __init__(self, account, password):
"""
"self.database" is the database for specified login account, set "700" permission for safe.
"""
self.database = str(homeDir) + '/' + str(account) + '.db'
createPermissionFile(self.database, 700)
self.myEncrypt = encrypt(account, password)

self.root = Tk()
self.root.geometry('800x600+200+200')
self.root.title(titleBarName)

def savePassword(self, project, account, password):
"""
Save project account/password information into database.
Cannot save repated account for the same project.
"""
mark = 0
FL = open(self.database, 'r')
for line in FL.readlines():
(registeredObject, registeredAccount, registeredPassword) = line.split()
if registeredObject == project and registeredAccount == account:
mark = 1
if (messagebox.askyesno(titleBarName, '*Warning*: project ' + str(project) + '(' + str(account) +') have been in database, would you like to re-write it?')):
os.system("sed -i 's/^" + str(project) + " " + str(account) + " .*$/" + str(project) + " " + str(account) + " " + str(password) + "/g' " + str(self.database))
print('*Info*: save password pass for project ' + str(project) + '-' + str(account) + '.')
FL.close()

if mark == 0:
FL = open(self.database, 'a')
passwordEncrypt = self.myEncrypt.encrypt(password)
FL.write(str(project) + ' ' + str(account) + ' ' + str(passwordEncrypt) + '\n')
FL.close()
print('*Info*: save password pass for project ' + str(project) + '-' + str(account) + '.')

def getPassword(self, project):
"""
Get project account/password information with the matched projects.
"""
possibleProjects = []
infos = "Project account password"
infos = str(infos) + "\n=============================="

FL = open(self.database, 'r')
for line in FL.readlines():
(registeredObject, registeredAccount, registeredPassword) = line.split()
if re.match(project, registeredObject):
possibleProjects.append(registeredObject)
registeredPasswordDecrypt = self.myEncrypt.decrypt(registeredPassword)
infos = str(infos) + '\n' + str(registeredObject) + ' ' + str(registeredAccount) + ' ' + str(registeredPasswordDecrypt)
FL.close()

if len(possibleProjects) == 0:
print('*Error*: ' + str(project) + ': No registered project!')
messagebox.showerror(titleBarName, '*Error*: ' + str(project) + ': No registered project!')
else:
self.showPasswordGUI(infos)

def getPasswordGUI(self):
self.projectLable = Label(self.root, text='* Project:')
self.projectLable.grid(row=1, column=1, sticky=W, ipadx=20, ipady=10)

self.projectEntryVar = StringVar()
self.project = Entry(self.root, textvariable=self.projectEntryVar, bg='white')
self.project.grid(row=1, column=2, sticky=W, ipadx=250, ipady=10)

self.accountLabel = Label(self.root, text='Account:')
self.accountLabel.grid(row=2, column=1, sticky=W, ipadx=20, ipady=10)

self.accountEntryVar = StringVar()
self.account = Entry(self.root, textvariable=self.accountEntryVar, bg='white')
self.account.grid(row=2, column=2, sticky=W, ipadx=250, ipady=10)

self.passwordLabel = Label(self.root, text='Password:')
self.passwordLabel.grid(row=3, column=1, sticky=W, ipadx=20, ipady=10)

self.passwordEntryVar = StringVar()
self.passwordEntry = Entry(self.root, textvariable=self.passwordEntryVar, show='*', bg='white')
self.passwordEntry.grid(row=3, column=2, sticky=W, ipadx=250, ipady=10)

self.loginButton = Button(self.root, text='Get password', command=lambda:self.getPassword(self.projectEntryVar.get().strip()), bg='blue')
self.loginButton.grid(row=4, column=2, ipadx=50, ipady=10)

self.registerButton = Button(self.root, text='Save password', command=lambda:self.savePassword(self.projectEntryVar.get().strip(), self.accountEntryVar.get().strip(), self.passwordEntryVar.get().strip()), bg='blue')
self.registerButton.grid(row=5, column=2, ipadx=50, ipady=10)

self.root.mainloop()

def showPasswordGUI(self, infos):
self.infosText = Text(self.root, bg='white')
self.infosText.insert(1.0, infos)
self.infosText.grid(row=6, column=2, sticky=W, ipadx=50, ipady=12)

self.infosTextSbY = Scrollbar(self.root)
self.infosTextSbY.grid(row=6, column=3, sticky=W, ipadx=2, ipady=165)
self.infosText.configure(yscrollcommand=self.infosTextSbY.set)
self.infosTextSbY.configure(command=self.infosText.yview)

self.root.mainloop()

def main():
# "homeDir" is used to save login configure file and project/account/password files for registered users.
# Set "700" permission to stop other users access the protected infos.
createPermissionDir(homeDir, 700)

# set '700' permission for current script, so other user cannot read/write/execute it.
currentScript = os.path.realpath(sys.argv[0])
createPermissionFile(currentScript, 700)

# login this script. (or register a account for this script)
myLoginGUI = loginGUI()
myLoginGUI.loginGUI()

# save/get project account/password information.
myGetPasswordGUI = getPasswordGUI(myLoginGUI.account, myLoginGUI.password)
myGetPasswordGUI.getPasswordGUI()

###################
## Main Function ##
###################
if __name__ == "__main__":
main()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息