将记住的本地密码,密码加密混淆后保存到SQLCipher中

使用加密混淆来保存记住的本地密码

本文介绍一种 直接使用文本混淆来加密保存本地密码的方式,此加密文件取自这个项目 SeleniumBase

实现方式:

  1. 先使用文本混淆加密原始密码
  2. 将混淆的密码,保存到 SQLCipher,编译安装见这里

加密代码

加密函数文件如下,GitHub源代码见这里,还需要3个配置项

"""This is mainly for string obfuscation."""

import base64
import codecs
import hashlib

from setting import CONFIG  # 配置项
# 配置项如下
# ENCRYPTION_KEY = "Pg^.l!8UdJ+Y7dMIe&fl*%!p9@ej]/#tL~3E4%6?"  # 默认加密密钥,需要你修改
# OBFUSCATION_START_TOKEN = "$^*ENCRYPT="  # 加密密钥的开头
# OBFUSCATION_END_TOKEN = "?&#$"  # 加密密钥的结尾

def str_xor(string, key):
    if len(key) < 1:
        raise Exception("2nd arg of str_xor() must be a string of length > 0!")
    if len(string) > len(key):
        difference = len(string) - len(key)
        key = key + (((difference / len(key)) * key) + key)
    result = None
    try:
        result = "".join(
            [chr(ord(c1) ^ ord(c2)) for (c1, c2) in zip(string, key)]
        )
    except Exception:
        string = string.decode("utf-8")
        result = "".join(
            [chr(ord(c1) ^ ord(c2)) for (c1, c2) in zip(string, key)]
        )
    return result


def is_obfuscated(string):
    # Based on settings, determines if a string has already been obfuscated.
    # Obfuscated strings have a common predefined start token and end token.
    start_token = CONFIG.OBFUSCATION_START_TOKEN
    end_token = CONFIG.OBFUSCATION_END_TOKEN
    return string.startswith(start_token) and string.endswith(end_token)


def shuffle_string(string):
    if len(string) < 2:
        return string
    return string[1::2] + string[::2]


def reverse_shuffle_string(string):
    if len(string) < 2:
        return string
    new_string = ""
    odd = len(string) % 2 == 1
    part1 = string[: int(len(string) / 2): 1]  # noqa: E203
    part2 = string[int(len(string) / 2):: 1]  # noqa: E203
    for c in range(len(part1)):
        new_string += part2[c]
        new_string += part1[c]
    if odd:
        new_string += part2[-1]
    return new_string


def blend_strings(string1, string2):
    smallest_length = min(len(string1), len(string2))
    new_string = ""
    for c in range(smallest_length):
        new_string += string1[c]
        new_string += string2[c]
    if len(string1) > len(string2):
        new_string += string1[smallest_length:]
    elif len(string2) > len(string1):
        new_string += string2[smallest_length:]
    else:
        # Equal length strings
        pass
    return new_string


def rotate(string, n):
    return string[n:] + string[:n]


def ord_string_sum(string):
    count = 0
    try:
        for c in string:
            count += ord(c)
    except Exception:
        string = string.decode("utf-8")
        for c in string:
            count += ord(c)
    return count


def decrypt(string):
    # Password/String obfuscation/de-obfuscation
    # Used for both encryption and decryption
    # If you update the algorithm, you must re-encrypt all encrypted passwords!
    encryption_key = CONFIG.ENCRYPTION_KEY
    start_token = CONFIG.OBFUSCATION_START_TOKEN
    end_token = CONFIG.OBFUSCATION_END_TOKEN
    already_encrypted = False
    if is_obfuscated(string):
        already_encrypted = True
        string = string[len(start_token): -len(end_token)]  # noqa: E203
        string = base64.b64decode(codecs.encode(string))
    # Obfuscate the key used for string obfuscation
    hd1 = hashlib.sha256(str(encryption_key).encode("utf-8")).hexdigest()
    hd2 = hashlib.sha256(str(encryption_key[::-1]).encode("utf-8")).hexdigest()
    b64_key = base64.b64encode(codecs.encode(encryption_key * 8))
    xor_key = "".join(
        [
            chr(ord(str(c3)) - int(c1, 16) - int(c2, 16))
            for (c1, c2, c3) in zip(hd1, hd2, b64_key.decode("utf-8"))
        ]
    )
    xor_key = blend_strings(xor_key, encryption_key)
    if len(xor_key) % 7 == 0:
        xor_key = xor_key + encryption_key[-1]
    xor_key = shuffle_string((xor_key * 8)[::7])
    # Use the str_xor method for the main string obfuscation / de-obfuscation
    if not already_encrypted:
        if len(string) > 0:
            rem1 = (ord_string_sum(string)) % 3
            rem2 = (ord_string_sum(string)) % 4
            rem3 = (ord_string_sum(string)) % 2
            rem4 = (len(string) + ord_string_sum(string)) % 2
        if len(string) % 2 != 0:
            if rem3 == 1:
                string = (chr(ord(string[-1]) - 5 - rem1) + string + chr(ord(string[-1]) - 13 - rem1))
            else:
                string = (chr(ord(string[-1]) - 11 - rem1) + string + chr(ord(string[-1]) - 23 - rem1))
        elif len(string) > 1:
            if rem4 == 1:
                string = (chr(ord(string[0]) - 19 + rem2) + string + chr(ord(string[0]) - 7 - rem2))
            else:
                string = (chr(ord(string[0]) - 26 + rem2) + string + chr(ord(string[0]) - 12 - rem2))
        rem5 = (len(string) + ord_string_sum(string)) % 23
        string = rotate(string, rem5)
        result = str_xor(shuffle_string(string)[::-1], xor_key)
        rem6 = (len(result) + ord_string_sum(result)) % 17
        result = rotate(result, rem6)
    else:
        rem6 = (len(string) + ord_string_sum(string)) % 17
        string = rotate(string, -rem6)
        result = reverse_shuffle_string(str_xor(string, xor_key)[::-1])
        if len(result) > 2:
            rem5 = (len(result) + ord_string_sum(result)) % 23
            result = rotate(result, -rem5)
            result = result[1:-1]
    # Finalize encryption of non-encrypted string
    if not already_encrypted:
        result = base64.b64encode(codecs.encode(result))
        result = start_token + result.decode("utf-8") + end_token
    return result


使用方法

文本混淆使用方法举例

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
@ File        : test_encrypted_decrypted.py
@ Author      : yqbao
@ Version     : V1.0.0
@ Description :
"""


def encrypted(password):
    """加密混淆"""
    try:
        encrypted_password = decrypt(password)
        return encrypted_password
    except KeyboardInterrupt as e:
        print(e)


def decrypted(encrypted_password):
    """测试解密"""
    try:
        password = decrypt(encrypted_password)
        return password
    except KeyboardInterrupt as e:
        print(e)


if __name__ == '__main__':
    print(encrypted("123456"))
    print(decrypted("$^*ENCRYPT=GB8UJl0DGmE=?&#$"))

效果如下
image

保存到SQLCipher

配合使用SQLCipher,来保存密码

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
@ File        : test_pysqlcipher3.py
@ Author      : yqbao
@ Version     : V1.0.0
@ Description :
"""
from pysqlcipher3 import dbapi2 as sqlite3


def create_db(db, table):
    conn = sqlite3.connect(db)
    cursor = conn.cursor()
    cursor.execute(f"PRAGMA key='123456'")  # sqlcipher密码
    try:
        cursor.execute(f'CREATE TABLE {table} (username text , password text)')
        conn.commit()
    except sqlite3.OperationalError:
        pass
    conn.close()


def insert_db(db, table, username, password):
    conn = sqlite3.connect(db)
    cursor = conn.cursor()
    cursor.execute(f"PRAGMA key='123456'")
    encrypt = encrypted(password)  # 文本加密混淆
    cursor.execute(f"INSERT INTO {table}(username,password) VALUES(?,?)", (username, encrypt))
    conn.commit()
    conn.close()


def decrypt_db(db, table):
    conn = sqlite3.connect(db)
    cursor = conn.cursor()
    cursor.execute(f"PRAGMA key='123456'")
    cursor.execute(f"SELECT * FROM {table}")
    result = cursor.fetchall()[-1]
    username = result[0]
    password = decrypted(result[1])  # 解密原始文本
    return username, password

if __name__ == '__main__':
    create_db('test.db', 'test')
    insert_db('test.db', 'test', 'test', '123456')
    print(decrypt_db('test.db', 'test'))

效果如下:

image

本文章的原文地址
GitHub主页

posted @ 2024-03-28 15:10  星尘的博客  阅读(24)  评论(0编辑  收藏  举报