WhatsApp backup conversation files are now saved with the .crypt8
extension. This means that WhatsApp has once again changed (do they ever stop??!!) the encryption algorithm used to generate the chat history message backups that are saved on the SD card.
Changes between crypt7 and crypt8
As far as the encryption algorithm is concerned, there are no changes between crypt7
and crypt8
files. For crypt8
, an additional step has been introduced – gunzip the decrypted output file.
With the crypt8
update, WhatsApp has also disabled the Android ADB backup feature. This method was used previously to extract the keys on a non-rooted phone. So, what this means, is that the key
file that holds the encryption keys cannot be retrieved anymore unless your phone is rooted. We can confirm that the android:allowBackup
feature has been turned off by running aapt (Android Asset Packing Tool) on the latest WhatsApp APK file.
1 2 |
$ aapt dump xmltree com.whatsapp.apk AndroidManifest.xml | grep allowBackup A: android:allowBackup(0x01010280)=(type 0x12)0x0 |
Extract Key File
To decrypt the crypt8
files, you will need the key file. The key file stores two sets of decryption keys – the actual encryption key,K and an initialisation vector called IV . WhatsApp stores the key file in a secure location.
1 |
/data/data/com.whatsapp/files/key |
Using a rooted phone, launch ADB shell, switch to root and copy the key file to the SD card.
1 2 3 4 5 |
$ adb shell android$ su android# cp /data/data/com.whatsapp/files/key /sdcard android# exit android$ exit |
Once the file has been copied to the SD card, use ADB again to copy it to your computer.
1 |
$ adb pull /sdcard/key |
Extract crypt8 Backup File
Pull the encrypted WhatsApp messages file from your phone using ADB.
1 |
$ adb pull /sdcard/WhatsApp/Databases/msgstore.db.crypt8 |
Extract Decryption Keys
The encryption method being used is AES with a key length of 256 bits and an initialisation vector size of 128 bits. The 256-bit AES key is saved from offset 0x7E till 0x9D in the file. Offsets start from 0x00. Extract the AES key with hexdump and assign the value to variable $k
. You can choose either one of the two commands below. Both will give the same result.
1 |
$ k=$(hexdump -ve '2/1 "%02x"' key | cut -b 253-316) |
1 |
$ k=$(dd if=key bs=1 skip=126 count=32 2>/dev/null | hexdump -ve '2/1 "%02x"') |
The $k
variable will hold a 64-digit hexadecimal value in ASCII that is actually 256 bits in length.
Next, extract the IV or the initialisation vector and assign the value to variable $iv
. For WhatsApp version before v2.12.38
, the IV value is saved from offset 0x6E till 0x7D in the key file. Again, you can choose either one of the two commands below. Both will give the same result.
1 |
$ iv=$(hexdump -ve '2/1 "%02x"' key | cut -b 221-252) |
1 |
$ iv=$(dd if=key bs=1 skip=110 count=16 2>/dev/null | hexdump -ve '2/1 "%02x"') |
For WhatsApp version from v2.12.38
onwards, the IV value is saved from offset 0x33 till 0x42 in the crypt8 file and not in the key
file. Use one of the following commands to extract IV.
1 |
$ iv=$(hexdump -n 67 -ve '2/1 "%02x"' msgstore.db.crypt8 | cut -b 103-134) |
1 |
$ iv=$(dd if=msgstore.db.crypt8 bs=1 skip=51 count=16 2>/dev/null | hexdump -ve '2/1 "%02x"') |
The $iv
variable will hold a 32-digit hexadecimal value in ASCII that is actually 128 bits in length.
Strip Header in crypt8 File
Before we start the decryption process, we will need to strip the 67 byte header from the crypt8
file.
1 |
$ dd if=msgstore.db.crypt8 of=msgstore.db.crypt8.nohdr ibs=67 skip=1 |
The above command will strip the the first 67 bytes from the crypt8
file and save it to a file with extension crypt8.nohdr
. If you look at the contents of the header, the IV value is actually stored there – between offset 0x33 till 0x42.
The file size of the header stripped file must be divisible by 128 bits or 16 bytes. For example, the size of my output file is 16216176
bytes – a number that is divisible by 16. If the file size is not in multiples of 16 bytes, then most probably your file is corrupted.
1 2 |
$ ls -l msgstore.db.crypt8.nohdr -rw-r--r--+ 1 ibrahim users 16216176 Dec 17 18:35 msgstore.db.crypt8.nohdr |
Decrypt crypt8 File
Now we have the necessary parameters to decrypt the crypt8.nohdr
file using the openssl
utility.
1 |
$ openssl enc -aes-256-cbc -d -nosalt -nopad -bufsize 16384 -in msgstore.db.crypt8.nohdr -K $k -iv $iv | gunzip > msgstore.db |
1 |
$ openssl enc -aes-256-cbc -d -nosalt -bufsize 16384 -in msgstore.db.crypt8.nohdr -K $k -iv $iv | gunzip > msgstore.db |
The $k
and $iv
variables hold the AES encryption key and IV values that we retrieved using hexdump
earlier. A non encrypted SQLite database file will be generated and saved to a file called msgstore.db
.
I got the following warning message from gunzip
utility when using the openssl
command with the -nopad
option. I assume that the warning can be safely ignored.
1 |
"gzip: stdin: decompression OK, trailing garbage ignored" |
Updated (28-Dec-2014): openssl
command has been modified to prevent gzip
warning.
Updated (18-May-2015): Method updated to extract IV from crypt8 file. Credit to TripCode @ XDA for the method.
Updated (18-May-2015): Force hexdump
to print all input data by using -v
option, else hexdump
could print identical data with asterisk instead.
Related: Extract WhatsApp Password on Android