Java 如何解密Whatsapp数据库文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22314416/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 14:53:19  来源:igfitidea点击:

How to decrypt Whatsapp Database File?

javadatabaseencryptionwhatsapp

提问by ali.turan

I was trying to decrypt Whatsapp database file (msgstore.db.crypt) with java.

我试图msgstore.db.crypt用java解密Whatsapp数据库文件()。

I found some python code and tried to do same thing with java. Probably its not that hard thing to do but I had some problems with handling decryption key.

我找到了一些 python 代码并尝试用 java 做同样的事情。可能这并不难,但我在处理解密密钥时遇到了一些问题。

But finally did it. So I wanted to share the code for people who need it.

但最终做到了。所以我想为需要它的人分享代码。

回答by ali.turan

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;


public class Crypto {

    public FileInputStream mIn;
    public FileOutputStream mOut;
    public Crypto(String fileIn, String fileOut) {
        try {
                mIn = new FileInputStream(new File(fileIn));
                mOut = new FileOutputStream(new File(fileOut));
                decryptAES(mIn, mOut);
        } catch (Exception e) {
                e.printStackTrace();
        }
    }

    public static void decryptAES(InputStream in, FileOutputStream out) throws Exception {
        final String string = "346a23652a46392b4d73257c67317e352e3372482177652c";
        byte[] hexAsBytes = DatatypeConverter.parseHexBinary(string);

        SecretKeySpec keySpec = new SecretKeySpec(hexAsBytes, "AES");
        Cipher cipher = Cipher.getInstance("AES"); 

        cipher.init(Cipher.DECRYPT_MODE, keySpec);

        in = new CipherInputStream(in, cipher);
        byte[] buffer = new byte[24]; 
        int bytesRead;
        while ((bytesRead = in.read(buffer)) != -1)
        {
            out.write(buffer, 0, bytesRead);
        }

    }


    public static void main(String[] args){    
        Crypto c = new Crypto("C:\msgstore.db.crypt", "D:\WhatsappDb");
        System.out.println("Decrypting Done");
    }
}

回答by Willem Hengeveld

An updated answer for .crypt12files:

.crypt12文件的更新答案:

These are compressed, and then encrypted using AES in GCM mode

这些被压缩,然后在 GCM 模式下使用 AES 加密

Here is some python code showing how:

这是一些显示如何操作的python代码:

"""
Example how to decrypt whatsapp msgstore backups with extension .crypt12.
Author: Willem Hengeveld <[email protected]>
"""
from Crypto.Cipher import AES
import zlib
import sys

datafile = keyfile = None

if len(sys.argv)==1:
    print("Usage: decrypt12.py <keyfile> <msgstore.db.crypt12>")
    print("  the key file is commonly found in /data/data/com.whatsapp/files/key")
    print("  the crypt file is commonly found in the directory: /data/media/0/WhatsApp/Databases/")
    exit(1)

for arg in sys.argv[1:]:
    if arg.find('crypt12')>0:
        datafile = arg
    elif arg.find('key')>0:
        keyfile = arg
    else:
        print("unknown arg", arg)

with open(keyfile, "rb") as fh:
   keydata = fh.read()
key = keydata[126:]

with open(datafile, "rb") as fh:
   filedata = fh.read()
iv = filedata[51:67]

aes = AES.new(key, mode=AES.MODE_GCM, nonce=iv)

with open("msg-decrypted.db", "wb") as fh:
    fh.write(zlib.decompress(aes.decrypt(filedata[67:-20])))

回答by SkateScout

here is an pure java routine for .db.crypt12 without bouncycastle, but only JDK.

这是 .db.crypt12 的纯 Java 例程,没有 bouncycastle,但只有 JDK。

public class Crypt12 {
    public static void main(final String[] args) {
        final String c12File         = "1/msgstore.db.crypt12"; // input file
        final String decryptedDbFile = "1/msgstore.db";         // sqlite3 db output file
        final String keyFile         = "1/key";
        try {
            final byte[] key; try(FileInputStream s = new FileInputStream(keyFile)) { key = s.readAllBytes(); }
            final byte[] buf; try(FileInputStream s = new FileInputStream(c12File)) { buf = s.readAllBytes(); }
            if(!Arrays.equals(key, 27, 78, buf, 0, 51)) { System.out.println("Wrong Key-File"); return; }
            final int available = buf.length - 67  - 20; // 67 Byte Header + 20 byte footer
            final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            final GCMParameterSpec iv = new GCMParameterSpec(128, buf, 51, 16);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, 126, 32, "AES"), iv);
            final int zipLen = cipher.doFinal(buf, 67, available, buf, 0);
            final Inflater unzip = new Inflater(false);
            try(FileOutputStream s = new FileOutputStream(decryptedDbFile)) {
                unzip.setInput(buf, 0, zipLen);
                final byte[] b = new byte[1024];
                while(!unzip.needsInput()) {
                    final int l = unzip.inflate(b, 0, b.length);
                    if(l > 0) s.write(b, 0, l);
                }
            }
        } catch (final Exception e) {
            e.printStackTrace(System.out);
        }
    }
}