Python中的加密数据库文件

14 投票
4 回答
36930 浏览
提问于 2025-04-15 12:12

我在Python中有一个SQLite数据库。这个应用程序可以正常运行,但我希望没有人能在没有密码的情况下读取这个数据库。我该如何在Python中实现这个功能呢?

4 个回答

5

你可以使用存储在内存(RAM)中的数据库,并且只保存你通过加密模块得到的加密版本。然后,你可以通过解密你存储的内容,重新在内存中创建这个数据库:

from cryptography.fernet import Fernet
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
import base64
from os import getcwd
import sqlite3
import gzip


def key_creation(password):
    kdf=PBKDF2HMAC(algorithm = hashes.SHA256(), salt=b'\xfaz\xb5\xf2|\xa1z\xa9\xfe\xd1F@1\xaa\x8a\xc2', iterations=1024, length=32, backend=default_backend())
    key=Fernet(base64.urlsafe_b64encode(kdf.derive(password)))
    return key

def encryption(b, password):
    f=key_creation(password)
    safe=f.encrypt(b)
    return safe

def decryption(safe, password):
    f=key_creation(password)
    b=f.decrypt(safe)
    return b

def open_cdb(name,password):
    f=gzip.open(getcwd()+name+'_crypted.sql.gz','rb')
    safe=f.read()
    f.close()
    content=decryption(safe,password)
    content=content.decode('utf-8')
    con=sqlite3.connect(':memory:')
    con.executescript(content)
    return con

def save_cdb(con,name,password):
    fp=gzip.open(getcwd()+name+'_crypted.sql.gz','wb')
    b=b''
    for line in con.iterdump():
        b+=bytes('%s\n','utf8') % bytes(line,'utf8')
    b=encryption(b,password)
    fp.write(b)
    fp.close()


if __name__=='__main__':
    password=b'Sw0rdFish'
    name='PRODUCTS'
    conn = sqlite3.connect(':memory:')
    conn.execute('CREATE TABLE PRODUCTS (ID INT PRIMARY KEY     NOT NULL,\nNAME           TEXT    NOT NULL,\nPRICE            REAL     NOT NULL,\nTAXES        REAL    NOT NULL);')
    save_cdb(conn,name,password)
    conn.close()
    conn = open_cdb(name,password)
    cursor = conn.execute('select * from ' + name)
    headers = list(map(lambda x: x[0], cursor.description))
    print(headers)
    for x in cursor:
        for j in range(len(x)):
            print(headers[j]+' ',x[j])
        print('\n')
    conn.close()
5

正如Frontware所建议的,你可以使用sqlcipher。

pysqlcipher这个Python包可以让你更方便地使用,因为它把sqlcipher的代码整合在一起,编译成了一个扩展。

使用pysqlcipher就像使用普通的sqlite.dbapi2一样,只需要设置正确的加密参数就可以了。

8

我的应用程序可能会同时运行多个实例,所以我不能仅仅对SQLite数据库文件进行加密。我也觉得在Python中加密数据不是个好主意,因为这样一来就无法在数据库中进行任何数据操作。我想到了以下几种方法:

  1. 使用之前提到的SQLCipher。我需要为Python编写自己的绑定,并自己编译(或者支付费用)。
  2. 使用PyCrypto来加密数据库文件。我会实现一个SQL服务器来解密数据库文件,然后处理来自客户端的请求。每当没有未处理的请求时,它会重新加密数据库。这种方法会比较慢,并且会让数据库在某些时候处于临时解密状态。

我没能成功编译SQLCipher,它还使用了OpenSSL(对于简单的AES 128来说,这个库太庞大了)。我发现了wxSQLite3,并了解了如何分离SQLite的加密。我成功地让它与最新版本的SQLite3一起工作。wxSQLite3支持AES 256。我的下一步是将PySQLite(Python内置的SQLite库)与修改过的sqlite3.dll一起编译,并调整PySQLite以支持wxSQLite3的sqlite3.dll中的扩展加密。

撰写回答