[GH-ISSUE #190] Reproducible re-encryption stopped working #79

Open
opened 2026-03-02 03:59:54 +03:00 by kerem · 4 comments
Owner

Originally created by @Esokrates on GitHub (Sep 26, 2025).
Original GitHub issue: https://github.com/ElDavoo/wa-crypt-tools/issues/190

First of all thanks for the great tool! I do regular backups of my Databases, where I decrypt the databases and store the relevant data to re-encrypt the databases again.
I built an automatic test, that always checks whether the re-encrypted database has the same hash as the originally exported database. That worked fine until recently.

It seems WhatsApp changed something recently, as I am unable to obtain the exact same file when re-encrypting.
My last working database had the following:

Key type: 1
WhatsApp version: 2.25.18.80
Backup version: 1
Features: [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39]
Max feature number: 39

With the following it does not work anymore:

Key type: 1
WhatsApp version: 2.25.21.82
Backup version: 1
Features: [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39]
Max feature number: 39

Decryption works without errors, but the re-encrypted database is no longer the same.

Originally created by @Esokrates on GitHub (Sep 26, 2025). Original GitHub issue: https://github.com/ElDavoo/wa-crypt-tools/issues/190 First of all thanks for the great tool! I do regular backups of my Databases, where I decrypt the databases and store the relevant data to re-encrypt the databases again. I built an automatic test, that always checks whether the re-encrypted database has the same hash as the originally exported database. That worked fine until recently. It seems WhatsApp changed something recently, as I am unable to obtain the exact same file when re-encrypting. My last working database had the following: ``` Key type: 1 WhatsApp version: 2.25.18.80 Backup version: 1 Features: [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39] Max feature number: 39 ``` With the following it does not work anymore: ``` Key type: 1 WhatsApp version: 2.25.21.82 Backup version: 1 Features: [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39] Max feature number: 39 ``` Decryption works without errors, but the re-encrypted database is no longer the same.
Author
Owner

@code-consensus commented on GitHub (Nov 10, 2025):

Apart from the hashes, have you checked the file size of the original and re-encrypted crypt files?

From what I gather, it seems as if the WhatsApp application when it creates msgstore.db.crypt14/crypt15 is now using a different compression level and/or also the compression algorithm has diverged.

You can see in the @ElDavoo waencrypt.py code that it uses zlib with compression level 1.

In Python v3.13, for me the re-encrypted msgstore.db.crypt is about 5% larger than the original nowadays. But if I adjust waencrypt.py manually to zlib.compress(data, 9), it actually gets to within 2 bytes of the original file size. But there is still no exact match.

And note that in the recently-released Python v3.14, the implementation of zlib has changed, which results in significantly different file sizes: "It is worth noting that zlib.Z_BEST_SPEED (1) may result in significantly less compression than the previous implementation, whilst also significantly reducing the time taken to compress.". I noticed that waencrypt with the default "1" compression, for me Python 3.14 now results in a ~20% greater file size than the original .db.crypt file.

@Esokrates regardless of the different hash, have you tried to restore your database that had a different hash?

<!-- gh-comment-id:3510504916 --> @code-consensus commented on GitHub (Nov 10, 2025): Apart from the hashes, have you checked the file size of the original and re-encrypted crypt files? From what I gather, it seems as if the WhatsApp application when it creates msgstore.db.crypt14/crypt15 is now using a different compression level and/or also the compression algorithm has diverged. You can see in the @ElDavoo [waencrypt.py code](https://github.com/ElDavoo/wa-crypt-tools/blob/0c92577e3b40a5468ab49551bec84ea3adafcd33/src/wa_crypt_tools/waencrypt.py#L97) that it uses zlib with compression level _1_. In Python v3.13, for me the re-encrypted msgstore.db.crypt is about 5% larger than the original nowadays. But if I adjust waencrypt.py manually to zlib.compress(data, 9), it actually gets to within 2 bytes of the original file size. But there is still no exact match. And note that in the recently-released **Python v3.14**, the [implementation of zlib](https://docs.python.org/3/whatsnew/3.14.html#zlib) **has changed**, which results in _significantly different file sizes_: "It is worth noting that zlib.Z_BEST_SPEED (1) may result in significantly less compression than the previous implementation, whilst also significantly reducing the time taken to compress.". I noticed that waencrypt with the default "1" compression, for me Python 3.14 now results in a ~20% greater file size than the original .db.crypt file. @Esokrates regardless of the different hash, have you tried to restore your database that had a different hash?
Author
Owner

@ElDavoo commented on GitHub (Jan 4, 2026):

Hello, thank you for your report and for the detailed investigation.

note that in the recently-released Python v3.14, the implementation of zlib has changed, which results in significantly different file sizes:

The implementation changed on Windows only. I see no difference in Linux (in the test suite).
Do we really need to maintain a multiplatform build for a simple Python application? In 2026?
How do we even solve this problem? Is it actually a problem? Because, if zlib can decompress this stream, whatsapp shouldn't see any change.

wa-crypt-tools defaults to low compression because there are three different zlib magic signatures (low, default and high), so using a compression level mismatched with whatsapp's would have given issues.
With python 3.14 the test suite seems to pass (I will try to take a look to recent backups to see if code-consensus is right.)

<!-- gh-comment-id:3708282592 --> @ElDavoo commented on GitHub (Jan 4, 2026): Hello, thank you for your report and for the detailed investigation. > note that in the recently-released **Python v3.14**, the [implementation of zlib](https://docs.python.org/3/whatsnew/3.14.html#zlib) **has changed**, which results in _significantly different file sizes_: The implementation changed on Windows only. I see no difference in Linux (in the test suite). Do we really need to maintain a multiplatform build for a simple Python application? In 2026? How do we even solve this problem? Is it actually a problem? Because, if zlib can decompress this stream, whatsapp shouldn't see any change. wa-crypt-tools defaults to low compression because there are three different zlib magic signatures (low, default and high), so using a compression level mismatched with whatsapp's would have given issues. With python 3.14 the test suite seems to pass (I will try to take a look to recent backups to see if code-consensus is right.)
Author
Owner

@Esokrates commented on GitHub (Jan 6, 2026):

@code-consensus Thanks for your insights. I tried to restore the database that had a different hash and it looks alright.
@ElDavoo Does the test suite also check for matching hashes like I do?

<!-- gh-comment-id:3715260214 --> @Esokrates commented on GitHub (Jan 6, 2026): @code-consensus Thanks for your insights. I tried to restore the database that had a different hash and it looks alright. @ElDavoo Does the test suite also check for matching hashes like I do?
Author
Owner

@code-consensus commented on GitHub (Feb 2, 2026):

Do we really need to maintain a multiplatform build for a simple Python application?

I actually didn't notice in the documentation it mentioned on Windows only, and you make a very valid point -- isn't Python supposed to be cross-platform, so why a different implementation in Windows??

How do we even solve this problem?

I actually tried all the zlib compression levels (1 to 9) in Python v3.14 on Windows, and none of those ended up with a file size matching the original crypt file. So, the internal zlib implementation is just different now compared to before, so even if one wanted to, is there anything to even be done anyway?

Is it actually a problem? Because, if zlib can decompress this stream, whatsapp shouldn't see any change.

Well, that is exactly the point. From the last comment seems maybe not -- @Esokrates which Python version did you use to create the crypt file for the database you were able to restore in the application? Other than a different hash for the crypt files, was the file size any different? And did you leave waencrypt.py code as is with zlib level 1? What version of WhatsApp were you using?

wa-crypt-tools defaults to low compression because there are three different zlib magic signatures (low, default and high), so using a compression level mismatched with whatsapp's would have given issues.

So, in at least now Windows, the low level results in a 20% larger file size than before (so I suppose Linux would be 20% smaller than Windows), so there would be a mismatch. But calling zlib.decompress() doesn't ask for the input file's compression level at all, it just decompresses any input all the same. So if WhatsApp is just calling zlib, does it even matter?

<!-- gh-comment-id:3836457359 --> @code-consensus commented on GitHub (Feb 2, 2026): > Do we really need to maintain a multiplatform build for a simple Python application? I actually didn't notice in the documentation it mentioned on Windows only, and you make a very valid point -- isn't Python supposed to be cross-platform, so why a different implementation in Windows?? > How do we even solve this problem? I actually tried all the zlib compression levels (1 to 9) in Python v3.14 on Windows, and none of those ended up with a file size matching the original crypt file. So, the internal zlib implementation is just different now compared to before, so even if one wanted to, is there anything to even be done anyway? > Is it actually a problem? Because, if zlib can decompress this stream, whatsapp shouldn't see any change. Well, that is exactly the point. From the last comment seems maybe not -- @Esokrates which Python version did you use to create the crypt file for the database you were able to restore in the application? Other than a different hash for the crypt files, was the file size any different? And did you leave waencrypt.py code as is with zlib level 1? What version of WhatsApp were you using? > wa-crypt-tools defaults to low compression because there are three different zlib magic signatures (low, default and high), so using a compression level mismatched with whatsapp's would have given issues. So, in at least now Windows, the low level results in a 20% larger file size than before (so I suppose Linux would be 20% smaller than Windows), so there would be a mismatch. But calling zlib.decompress() doesn't ask for the input file's compression level at all, it just decompresses any input all the same. So if WhatsApp is just calling zlib, does it even matter?
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/wa-crypt-tools#79
No description provided.