import hashlib
import os
from typing import Union, List
from Cryptodome.Cipher import AES
from utils import wx_core_error, wx_core_loger
SQLITE_FILE_HEADER = "SQLite format 3\x00"
KEY_SIZE = 32
DEFAULT_PAGESIZE = 4096
PAGE_DATA_SIZE = 4064
@wx_core_error
def encrypt(key: str, db_path: str, out_path: str):
if not os.path.exists(db_path) or not os.path.isfile(db_path):
return False, f"[-] db_path:'{db_path}' File not found!"
if not os.path.exists(os.path.dirname(out_path)):
return False, f"[-] out_path:'{out_path}' File not found!"
if len(key) != 64:
return False, f"[-] key:'{key}' Len Error!"
password = bytes.fromhex(key.strip())
original_size = os.path.getsize(db_path)
try:
with open(db_path, "rb") as file:
blist = file.read()
except Exception as e:
return False, f"[-] db_path:'{db_path}' {e}!"
if not blist.startswith(SQLITE_FILE_HEADER.encode()):
return False, f"[-] db_path:'{db_path}' is not a valid SQLite database!"
salt = os.urandom(16)
mac_salt = bytes([(salt[i] ^ 58) for i in range(16)])
byteHmac = hashlib.pbkdf2_hmac("sha1", password, salt, 64000, KEY_SIZE)
mac_key = hashlib.pbkdf2_hmac("sha1", byteHmac, mac_salt, 2, KEY_SIZE)
with open(out_path, "wb") as encFile:
encFile.write(salt)
first_page_data = blist[len(SQLITE_FILE_HEADER):len(SQLITE_FILE_HEADER) + 4032]
if len(first_page_data) % 16 != 0:
padding = 16 - (len(first_page_data) % 16)
first_page_data += bytes(padding)
else:
padding = 0
iv = os.urandom(16)
cipher = AES.new(byteHmac, AES.MODE_CBC, iv)
encrypted_data = cipher.encrypt(first_page_data)
hmac_data = encrypted_data + iv
hash_mac = hmac.new(mac_key, hmac_data, hashlib.sha1)
hash_mac.update(b'\x01\x00\x00\x00')
page_hmac = hash_mac.digest()[:20]
encFile.write(encrypted_data)
encFile.write(iv)
encFile.write(page_hmac)
encFile.write(b'\x00' * (12 + padding))
pos = len(SQLITE_FILE_HEADER) + 4032
while pos < len(blist):
page_data = blist[pos:pos + 4048]
if len(page_data) % 16 != 0:
padding = 16 - (len(page_data) % 16)
page_data += bytes(padding)
else:
padding = 0
iv = os.urandom(16)
cipher = AES.new(byteHmac, AES.MODE_CBC, iv)
encrypted_data = cipher.encrypt(page_data)
hmac_data = encrypted_data + iv
hash_mac = hmac.new(mac_key, hmac_data, hashlib.sha1)
hash_mac.update(b'\x01\x00\x00\x00')
page_hmac = hash_mac.digest()[:20]
encFile.write(encrypted_data)
encFile.write(iv)
encFile.write(page_hmac)
encFile.write(b'\x00' * (12 + padding))
pos += 4048
return True, [db_path, out_path, key]