9

WhatsApp stores all messages in an sqlite file which is first zlib compressed and then AES encrypted.

Decryption/decompression can be done quite easily like that:

def decrypt(db_file, key_file):
    """ Function decrypt Crypt12 Database """
    try:
        with open(key_file, "rb") as fh:
            key_data = fh.read()

        key = key_data[126:]
        with open(db_file, "rb") as fh:
            db_data = fh.read()

        iv = db_data[51:67]
        aes = AES.new(key, mode=AES.MODE_GCM, nonce=iv)
        with open("msgstore.db", "wb") as fh:
            fh.write(zlib.decompress(aes.decrypt(db_data[67:-20])))

        print db_file + " decrypted, msgstore.db created."
    except Exception as e:
print "An error has ocurred decrypting the Database:", e

But if you wanted to reverse the process, you would have to generate the header, footer and IV. At first I thought you could just copy them from another already existing crypt12 file like this:

def encrypt(db_file, key_file, db_cript):
    """ Function encrypt msgstore Database """
    try:
        with open(key_file, "rb") as fh:
            key_data = fh.read()

        key = key_data[126:]

        with open(db_cript, "rb") as fh:
            db_cript_data = fh.read()

        header = db_cript_data[:51]
        iv = db_cript_data[51:67]
        footer = db_cript_data[-20:]

        with open(db_file, "rb") as fh:
            data = fh.read()

        aes = AES.new(key, mode=AES.MODE_GCM, nonce=iv)
        with open("msgstore.db.crypt12", "wb") as fh:
            fh.write(header + iv + aes.encrypt(zlib.compress(data)) + footer)

        print "Encrypted msgstore.db created."
    except Exception as e:
        print "An error has ocurred encrypting the Database:", e

But that does not appear to be the case. The .crypt12 files headers and footers are different for every file.

Example 1 header hexdump:

0000000    0100    5802    ee46    bcaf    8968    d43b    bfaf    ca5d
0000010    a774    6b66    53ec    dbae    af60    a09c    3ad2    ba5e
0000020    7341    d224    22e7    55c3    c944    cf77    2c71    9c29
0000030    3a58    3798    d10f    897c    6ffa    f27a    e788    4d7b
0000040    24a7    43a0    f1d3    5f7c    5c74    d64d    58c9    21a4
0000050    771c    7fdc    2e14    ca93    0848    758a    c184    9058
0000060    b7d9    d847    604f    cadf    05a2    a678    4994    b711
0000070    2641    9170    8965    f6a7    9ff3    95a0    860d    aca1
0000080    214c    d644    faa7    ....    ....    ....    ....    ....

Example 2 header hexdump:

0000000    0100    5802    ee46    bcaf    8968    d43b    bfaf    ca5d
0000010    a774    6b66    53ec    dbae    af60    a09c    3ad2    ba5e
0000020    7341    d224    22e7    55c3    c944    cf77    2c71    9c29
0000030    3a58    1898    1435    4cc9    bdbf    e506    f138    41a6
0000040    32a0    71c5    faa9    2499    36f7    d2be    d7a8    bf28
0000050    f3ea    1571    ed80    da14    addb    63b6    1d8e    2de5
0000060    0a9c    bc31    8d86    cb42    b4ce    b603    af7c    c295
0000070    d67f    b787    1ad8    eb69    3180    1c9d    8106    1f98
0000080    e880    edd5    c285    ....    ....    ....    ....    ....

You can see the first 25 bytes are always equal, but the rest is completely different. The last 16 bytes are the IV (nonce) btw.

For the footer you can see the last two bytes are equal and the rest is completely different.

Example 1 footer hexdump:

1464cd0    ....    2feb    12d8    a2bc    92bd    ca30    a99f    621c
1464ce0    9e87    88df    dc82    f7ea    2cfd    3e0b    ecd4    03b1
1464cf0    7720    8d3d    2dcb    382d    0031

Example 2 footer hexdump:

1474330    ....    d4e9    80de    d0e8    9786    4fd3    8bf2    957c
1474340    fdf5    2e24    c4f2    1b55    121a    4410    014d    c516
1474350    7531    7f0a    2d71    382d    0031

So how do I generate those?

Forivin
  • 14,780
  • 27
  • 106
  • 199
  • 3
    *The footer contains an md5 hash of the encrypted backup file (minus header / footer) and --nn (last two digits of cell number / whatsapp jid).* https://github.com/EliteAndroidApps/WhatsApp-Crypt12-Decrypter/issues/2#issuecomment-261606684 if it helps at all. – Jacques Gaudin May 13 '19 at 16:49

1 Answers1

0

The paper Chat-App Decryption Key Extraction Through Information Flow Analysis analyzes the crypt12 format:

67-byte header:

  • cipher-header preamble (2 bytes): 0x0, 0x1;
  • key version (1 byte): 0x2;
  • server salt (32 bytes): the stored pseudo-random salt from WhatsApp server;
  • Google account-name salt (16 bytes): the salt used to produce Google account- name hash, which is to be sent to WhatsApp server (more on this below);
  • IV (16 bytes): the initialization vector value.

20-byte trailer:

  • MD5 hash value (16 bytes): the MD5 hash value of the encrypted database file;
  • Phone no’s suffix (4 bytes): which is derived from the last few digits of the device's phone number.

I was unable to reconstruct the 16-bytes MD5 hash so I am wondering if this information is correct. Maybe there is some padding.

DurandA
  • 1,095
  • 1
  • 17
  • 35