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

前言

平时注册有很多电商购物和论坛的帐号,注册的帐号密码要求各不相同,所以登陆时经常忘记帐号或者密码,为此用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

Register and login

2. save account and password for the specified project

save project/account/password

3. Input project name and get account/password info

get password1

4. Get account/password info with full name project

get password2

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

get password3

 

 

源代码:

#!/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):
    """
    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()

 

转载于:https://my.oschina.net/liyanqing/blog/806095

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值