How to Decrypt WhatsApp crypt12 Database Messages

WhatsApp backup conversation files are now saved with the .crypt12 extension. From crypt9, they seem to be using a modified version of Spongy Castle – a cryptography API library for Android.

All the findings below are based on reverse engineering work done on WhatCrypt and Omni-Crypt. I would like to highlight that IGLogger proved to be a very useful tool when it came to smali code debugging.

Extract Key File

To decrypt the crypt12 files, you will first need the key file. The key file stores the encryption key, K. WhatsApp stores the key file in a secure location: /data/data/com.whatsapp/files/key.

If your phone is rooted, extracting this file is easy. I will not go through the steps again, as it’s already mentioned in the crypt8 decryption article. If your phone is not rooted, refer to instructions from WhatCrypt and Omni-Crypt for details on extracting the key file. The idea is to install an older version of WhatsApp, where Android ADB backup was still working and extract the key file from the backup.

Extract crypt12 Backup File

Pull the encrypted WhatsApp messages file from your phone using ADB.

$ adb pull /sdcard/WhatsApp/Databases/msgstore.db.crypt12

Decryption Keys

This section is just for your information and you can skip this section.

The encryption method being used is AES with a key (K) length of 256 bits and an initialisation vector (IV) size of 128 bits. The 256-bit AES key is saved from offset 0x7E till 0x9D in the file. Offsets start from 0x00. You can extract the AES key with hexdump and assign the value to variable $k.

$ k=$(hexdump -ve '2/1 "%02x"' key | cut -b 253-316)

The $k variable will hold a 64-digit hexadecimal value in ASCII that is actually 256 bits in length.

The IV or the initialisation vector is saved from offset 0x33 till 0x42 in the crypt12 file. The IV value will be different for every crypt12 file.

$ iv=$(hexdump -n 67 -ve '2/1 "%02x"' msgstore.db.crypt12 | cut -b 103-134)

The K and IV extraction method is similar to what we have done for crypt8 files before.

Strip Header / Footer in crypt12 File

Again, this section is just for your information and you can skip this section.

Before we start the decryption process, we will need to strip the 67 byte header and 20 byte footer from the crypt12 file.

$ dd if=msgstore.db.crypt12 of=msgstore.db.crypt12.enc ibs=67 skip=1
$ truncate -s -20 msgstore.db.crypt12.enc

The above dd command will strip the the first 67 bytes from the crypt12 file and save it to a file with extension crypt12.enc. The truncate command will strip the last 20 bytes from the crypt12 file.

Decrypt crypt12 File

As the WhatsApp AES cryptography API library seems to be a modified version, we will no longer be able to use openssl to decrypt the crypt12 file. I have yet to determine what has been modified.

To decrypt crypt12 files, I have written a simple Java program that will use the modified cryptography API library instead. For the cryptography API library, I have extracted the modified Spongy Castle cryptography class files from the Omni-Crypt APK file using dex2jar. You can find the Java program and crypto library over here at GitLab.

The Java program will create 3 output files:

  • msgstore.db.crypt12.enc – encrypted file with header and footer stripped.
  • msgstore.db.zlib – decrypted file in zlib format.
  • msgstore.db – decrypted sqlite3 database file.

Below is how you can compile and run the Java program.

$ git clone https://gitlab.com/digitalinternals/whatsapp-crypt12.git

$ cd whatsapp-crypt12/

$ javac -classpath "lib/whatsapp_spongycastle.jar:." crypt12.java

$ cp ../whatsapp.data/key .

$ cp ../whatsapp.data/msgstore.db.crypt12 .

$ java -cp "lib/whatsapp_spongycastle.jar:." crypt12

K:XXXXXXXXXX
IV:YYYY
creating encrypted file with header/footer stripped: msgstore.db.crypt12.enc
creating zlib output file: msgstore.db.zlib
creating sqlite3 output file: msgstore.db

$ ls -l
total 136724
-rw-r--r-- 1 ibrahim staff     4339 Oct  9 16:05 crypt12.class
-rw-r--r-- 1 ibrahim staff     5459 Oct  9 16:05 crypt12.java
-rw-r--r-- 1 ibrahim staff      158 Oct  9 16:05 key
drwxr-xr-x 2 ibrahim staff     4096 Oct  9 16:05 lib
-rw-r--r-- 1 ibrahim staff     1089 Oct  9 16:05 LICENSE
-rw-r--r-- 1 ibrahim staff 62692352 Oct  9 16:06 msgstore.db
-rw-r--r-- 1 ibrahim staff 25757610 Oct  9 16:05 msgstore.db.crypt12
-rw-r--r-- 1 ibrahim staff 25757523 Oct  9 16:05 msgstore.db.crypt12.enc
-rw-r--r-- 1 ibrahim staff 25757507 Oct  9 16:06 msgstore.db.zlib
-rw-r--r-- 1 ibrahim staff     1376 Oct  9 16:05 README.md

$ file *
crypt12.class:           compiled Java class data, version 52.0 (Java 1.8)
crypt12.java:            C source, ASCII text
key:                     Java serialization data, version 5
lib:                     directory
msgstore.db:             SQLite 3.x database, user version 1
msgstore.db.crypt12:     raw G3 data, byte-padded
msgstore.db.crypt12.enc: data
msgstore.db.zlib:        zlib compressed data

Final Words

To use the Java decryption tool, you will need to use OpenJDK. Oracle require JCE Provider libraries to be signed. OpenJDK does not have this requirement. If you try running the Java program on Oracle JDK, you will most likely get the following exception.

Exception in thread "main" java.lang.SecurityException: JCE cannot authenticate the provider SC

There are some workarounds to bypass the error, but it has not worked for me so far.

Decryption failed when using the modified cryptography API library from WhatsApp and WhatCrypt. Only Omni-Crypt library is working. I have yet to determine the reason for this. If you have any further information on this, leave a comment.

Ibrahim is a technology enthusiast with a keen interest in *NIX (Unix, Linux) systems, Android, open source and other tech related stuff. When his cpu load is low, you can probably find him online playing on his Xbox or PlayStation.

  • Craig

    Very good. Crypt12 currently has several variations. Default and variations A-F. Default you strip the 20 byte footer as per your guide. Variations A-F require a sum to be performed on the last 4 bytes which contains digits belonging to the device cell number. This will reveal the offset for mid-padding that also needs to be stripped before decryption. Omnicrypt gets this right. I can confirm your solution will work with default crypt12 but not with any of the variations. Keep on cracking my friend. You’re half-way there.

  • Thanks for the tip!

  • Chris

    Thank you so much for sharing!
    I have been trying to decrypt crypt12 since it came out using C#.Net.
    Now I’ve found that my offsets are correct, but the issue is the modification of the AES-algorithm…

    If only we could figure that out… I’ll let you know if I find something.

  • pascalfree

    Thank you.
    I’ve been trying to figure this out for a while, also using java, but I did not succeed. Your solution worked perfectly on my most recent crypt12 backup.
    Let’s hope whatsapp keeps the format for a while 😉

  • Mali

    Hello! Thanks for the wonderful tool.

    Can you create an article on decrypting wa.db?

    Thank you.

  • Mali

    There is also this problem. WhatsApp is unable to decrypt the crypt12 file because of key file mismatch. The key is from the same account. I deleted the key file, installed whatsapp on a rooted device and the new key file didn’t work either.

    Is whatsapp creating a new key file for each backup?

    How to fix this? The keys are from the same whatsapp account and number.

    Thank you.

  • thanks 😉

  • Aamir

    Dude help me out… My galaxy s4 was troubling and had to reset to factory settings. Before that, I had saved the “msgstore-201….1.db.crypt12” files (total 7 to 8 files are of same filename). After resetting my cellphone, I installed whatsapp again but cannot restore these msgs. I tried to copy those 7 files into device storage in whatsapp folder. Please tell me how to restore those msgs with these files. Thanks

  • Brendan

    Do you have any more information on the variations of crypt12? I haven’t been able to find anything and can’t figure out how the sum of the last 4 bytes reveals the offset for mid-padding.

  • tsing80

    How could I reencrypt the files? I have a corrupt sqlite database .After fixing the corruption, i need to reencrypt it to let whatsapp restore it

  • You will just need to reverse the order to encrypt it back, but I have not tried it yet.