mirror of
https://github.com/KnugiHK/WhatsApp-Chat-Exporter.git
synced 2026-04-20 13:11:15 +00:00
Support crypt14 WhatsApp Backup
This commit is contained in:
@@ -40,7 +40,7 @@ def main():
|
||||
"--backup",
|
||||
dest="backup",
|
||||
default=None,
|
||||
help="Path to iPhone backup")
|
||||
help="Path to Android (must be used together with -k)/iPhone WhatsApp backup")
|
||||
parser.add_option(
|
||||
"-o",
|
||||
"--output",
|
||||
@@ -60,6 +60,13 @@ def main():
|
||||
dest='db',
|
||||
default=None,
|
||||
help="Path to database file")
|
||||
parser.add_option(
|
||||
'-k',
|
||||
'--key',
|
||||
dest='key',
|
||||
default=None,
|
||||
help="Path to key file"
|
||||
)
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.android and options.iphone:
|
||||
@@ -80,6 +87,16 @@ def main():
|
||||
msg_db = "msgstore.db"
|
||||
else:
|
||||
msg_db = options.db
|
||||
if options.key is not None:
|
||||
if options.backup is None:
|
||||
print("You must specify the backup file with -b")
|
||||
return False
|
||||
print("Decryption key specified, decrypting WhatsApp backup...")
|
||||
key = open(options.key, "rb").read()
|
||||
db = open(options.backup, "rb").read()
|
||||
if not extract.decrypt_backup(db, key, msg_db):
|
||||
print("Dependencies of decrypt_backup are not present. For details, see README.md")
|
||||
return False
|
||||
if options.wa is None:
|
||||
contact_db = "wa.db"
|
||||
else:
|
||||
|
||||
@@ -10,6 +10,13 @@ import re
|
||||
import pkgutil
|
||||
from datetime import datetime
|
||||
from mimetypes import MimeTypes
|
||||
try:
|
||||
import zlib
|
||||
from Crypto.Cipher import AES
|
||||
except ModuleNotFoundError:
|
||||
support_backup = False
|
||||
else:
|
||||
support_backup = True
|
||||
|
||||
|
||||
def determine_day(last, current):
|
||||
@@ -21,6 +28,32 @@ def determine_day(last, current):
|
||||
return current
|
||||
|
||||
|
||||
def decrypt_backup(database, key, output):
|
||||
if not support_backup:
|
||||
return False
|
||||
if len(key) != 158:
|
||||
raise ValueError("The key file must be 158 bytes")
|
||||
if len(database) < 191:
|
||||
raise ValueError("The database file must be at least 191 bytes")
|
||||
t1 = key[30:62]
|
||||
t2 = database[15:47]
|
||||
if t1 != t2:
|
||||
raise ValueError("The signature of key file and backup file mismatch")
|
||||
|
||||
iv = database[67:83]
|
||||
db_ciphertext = database[191:]
|
||||
main_key = key[126:]
|
||||
cipher = AES.new(main_key, AES.MODE_GCM, iv)
|
||||
db_compressed = cipher.decrypt(db_ciphertext)
|
||||
db = zlib.decompress(db_compressed)
|
||||
if db[0:6].upper() == b"SQLITE":
|
||||
with open(output, "wb") as f:
|
||||
f.write(db)
|
||||
return True
|
||||
else:
|
||||
raise ValueError("The plaintext is not a SQLite database. Did you use the key to encrypt something...")
|
||||
|
||||
|
||||
def contacts(db, data):
|
||||
# Get contacts
|
||||
c = db.cursor()
|
||||
|
||||
Reference in New Issue
Block a user