signalapp / Signal-Android

A private messenger for Android.
https://signal.org
GNU Affero General Public License v3.0
25.47k stars 6.1k forks source link

Unable to restore encrypted backup - Bad MAC #8355

Closed mike-edel closed 2 years ago

mike-edel commented 5 years ago

Bug description

Unable to restore signal backup on new phone. Similar to #7637 but I don't have xposed installed. Signal stable closing without error after reading 11401 messages. Signal beta giving error message about incorrect passphrase after reading 11401 messages. I am certain the passphrase and the backup are correct as they are working fine using https://github.com/xeals/signal-back

Steps to reproduce

Actual result:

Expected result: Backup is successfully restored.

Screenshots

beta error (in German due to phone language) _20181110_121218

Device info

Device: Nokia 7 Plus Dual-Sim Android version: 9 Kernel version: 4.4.146-perf+ Signal version: Beta: 4.30.2 also tested on stable: 4.29.7

Link to debug log

Working on grabbing a logcat log but struggling with it. Will add through edit. Logcat for version 4.29.7:

--------- beginning of crash
11-08 22:32:10.330  4472  6987 E AndroidRuntime: FATAL EXCEPTION: AsyncTask #3
11-08 22:32:10.330  4472  6987 E AndroidRuntime: Process: org.thoughtcrime.securesms, PID: 4472
11-08 22:32:10.330  4472  6987 E AndroidRuntime: java.lang.RuntimeException: An error occurred while executing doInBackground()
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at android.os.AsyncTask$3.done(AsyncTask.java:354)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at java.util.concurrent.FutureTask.run(FutureTask.java:271)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at java.lang.Thread.run(Thread.java:764)
11-08 22:32:10.330  4472  6987 E AndroidRuntime: Caused by: java.lang.NegativeArraySizeException: -1884239691
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at org.thoughtcrime.securesms.backup.FullBackupImporter$BackupRecordInputStream.readFrame(FullBackupImporter.java:310)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at org.thoughtcrime.securesms.backup.FullBackupImporter$BackupRecordInputStream.readFrame(FullBackupImporter.java:252)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at org.thoughtcrime.securesms.backup.FullBackupImporter.importFile(FullBackupImporter.java:81)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at org.thoughtcrime.securesms.RegistrationActivity$2.doInBackground(RegistrationActivity.java:394)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at org.thoughtcrime.securesms.RegistrationActivity$2.doInBackground(RegistrationActivity.java:386)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at android.os.AsyncTask$2.call(AsyncTask.java:333)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
11-08 22:32:10.330  4472  6987 E AndroidRuntime:    ... 4 more

logcat for version 4.30.2:

11-10 13:15:20.687 27588 31822 W RegistrationActivity: null
11-10 13:15:20.687 27588 31822 W RegistrationActivity: java.io.IOException: Bad MAC
11-10 13:15:20.687 27588 31822 W RegistrationActivity:  at org.thoughtcrime.securesms.backup.FullBackupImporter$BackupRecordInputStream.readAttachmentTo(FullBackupImporter.java:298)
11-10 13:15:20.687 27588 31822 W RegistrationActivity:  at org.thoughtcrime.securesms.backup.FullBackupImporter.processAttachment(FullBackupImporter.java:140)
11-10 13:15:20.687 27588 31822 W RegistrationActivity:  at org.thoughtcrime.securesms.backup.FullBackupImporter.importFile(FullBackupImporter.java:87)
11-10 13:15:20.687 27588 31822 W RegistrationActivity:  at org.thoughtcrime.securesms.RegistrationActivity$2.doInBackground(RegistrationActivity.java:396)
11-10 13:15:20.687 27588 31822 W RegistrationActivity:  at org.thoughtcrime.securesms.RegistrationActivity$2.doInBackground(RegistrationActivity.java:388)
11-10 13:15:20.687 27588 31822 W RegistrationActivity:  at android.os.AsyncTask$2.call(AsyncTask.java:333)
11-10 13:15:20.687 27588 31822 W RegistrationActivity:  at java.util.concurrent.FutureTask.run(FutureTask.java:266)
11-10 13:15:20.687 27588 31822 W RegistrationActivity:  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
11-10 13:15:20.687 27588 31822 W RegistrationActivity:  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
11-10 13:15:20.687 27588 31822 W RegistrationActivity:  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
11-10 13:15:20.687 27588 31822 W RegistrationActivity:  at java.lang.Thread.run(Thread.java:764)
samizdis commented 5 years ago

@bepaald thanks for sharing your code, is there any chance you could make it available on github, even in an incomplete state? The send.firefox links you share have a short expiration time.

I read in another thread that you're new to adding code to github, this link might be helpful and I'm happy to give pointers if you like. https://help.github.com/en/articles/adding-an-existing-project-to-github-using-the-command-line

spospartan104 commented 5 years ago

@bepaald Do you have time to upload the build steps? `$g++ -std=c++17 main.cc

/usr/bin/ld: /tmp/cc3nxgid.o: in function 'main': main.cc:(.text+0x436): undefined reference to 'SignalBackup::SignalBackup(std::cxx11::basic_string<char, std::char_traits, std::allocator > const&, std::cxx11::basic_string<char, std::char_traits, std::allocator > const&)' /usr/bin/ld: /tmp/cc3nxgid.o: in function 'SqliteDB::~SqliteDB()': main.cc:(.text._ZN8SqliteDBD2Ev[_ZN8SqliteDBD5Ev]+0x23): undefined reference to 'sqlite3_close' /usr/bin/ld: /tmp/cc3nxgid.o: in function 'FileDecryptor::~FileDecryptor()': main.cc:(.text._ZN13FileDecryptorD2Ev[_ZN13FileDecryptorD5Ev]+0xf): undefined reference to 'vtable for FileDecryptor' collect2: error: ld returned 1 exit status ` Current error

bepaald commented 5 years ago

@spospartan104 Sorry for the late reply, it can get very busy for me sometimes. You should be able to compile the program with g++ -std=c++2a -Wall -Wextra -pedantic -O3 -march=native */*.cc main.cc -lcryptopp -lsqlite3 -o ./badmacinfo. Make sure you have sqlite3 and crypto++ installed. Depending on your setup, you might also need to add some -L flags to tell the linker where to look for certain libraries.

By the way, I thought you had already built the program earlier (when it didn't work), how did you run it? I f you didn't build it, but just used someone else's executable, that could very well be why it failed before.

@samizdis Yes I realize it's annoying. I do plan to make the code permanently available sometime in the future. It's just not in a presentable state right now, it's very quickly and heavily edited to provide a hint of functionality to the people in this thread. And it lacks many basic but important things (proper argument parsing and error checking). If in the meantime you (or anyone else) needs a re-upload, just let me know.

samizdis commented 5 years ago

@bepaald a re-upload would be great, thanks, I'm trying to work out which of my messages has a bad MAC, hopefully if I delete that message then I'll be able to create a restoreable backup :crossed_fingers:

bepaald commented 5 years ago

@samizdis Here you go: https://send.firefox.com/download/4cd0f08149728b5d/#ReaHOgiPoNaaI0NTQ-uXcw

spospartan104 commented 5 years ago

Thanks very much @bepaald. The one I had before had been a bit simpler but I don't recall which thread I pulled it from. I'll be. building this tonight and giving it a go.

Note: it doesn't need to be presentable to be in GitHub, most GitHub code isn't presentable, but tends to be seen as a see what you get kind of place with some safety in the download host not being malicious :)

On Thu, Jun 13, 2019, 15:20 bepaald notifications@github.com wrote:

@spospartan104 https://github.com/spospartan104 Sorry for the late reply, it can get very busy for me sometimes. You should be able to compile the program with g++ -std=c++2a -Wall -Wextra -pedantic -O3 -march=native /.cc main.cc -lcryptopp -lsqlite3 -o ./badmacinfo. Make sure you have sqlite3 and crypto++ installed. Depending on your setup, you might also need to add some -L flags to tell the linker where to look for certain libraries.

By the way, I thought you had already built the program earlier (when it didn't work), how did you run it? I f you didn't build it, but just used someone else's executable, that could very well be why it failed before.

@samizdis https://github.com/samizdis Yes I realize it's annoying. I do plan to make the code permanently available sometime in the future. It's just not in a presentable state right now, it's very quickly and heavily edited to provide a hint of functionality to the people in this thread. And it lacks many basic but important things (proper argument parsing and error checking). If in the meantime you (or anyone else) needs a re-upload, just let me know.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/signalapp/Signal-Android/issues/8355?email_source=notifications&email_token=AC7QU7FB7MLICZJ3BFZHRALP2KMWFA5CNFSM4GC73FNKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXUYOIQ#issuecomment-501843746, or mute the thread https://github.com/notifications/unsubscribe-auth/AC7QU7DDVMRKQ47MDRZS7YTP2KMWFANCNFSM4GC73FNA .

samizdis commented 5 years ago

Thanks @bepaald .

Just to echo what @spospartan104 said, code can definitely be work-in-progress and still hosted on GitHub.

ShiftedMr commented 5 years ago

@bepaald Got it working. And I have the frame info output. Now I need to hunt down what it was. I do see "pending_push: 1" So my guess is it's an attachment that failed to send? if that's what it means.

Quick Edit. Think I found it, giving it a go. This is good stuff. Thank you again

samizdis commented 5 years ago

Just to feed back that @bepaald 's code found two messages in my backups which had attachments with bad MACs. When I looked at these messages in the Signal app they'd both failed to either send or receive. After deleting these messages in the app I created a new backup which I was able to restore from on a different phone.

@bepaald your code is definitely useful enough and user-friendly enough to go on github, I'm sure other people would also find it useful even if you still plan on doing more work to it.

dcormier commented 5 years ago

Just to feed back that @bepaald 's code found two messages in my backups which had attachments with bad MACs. When I looked at these messages in the Signal app they'd both failed to either send or receive. After deleting these messages in the app I created a new backup which I was able to restore from on a different phone.

If Signal could just handle restoring backups that include such messages...

AJolly commented 5 years ago

@bepaald can you reupload the tool? I've got an issue where signal restores some, but not all messages.

bepaald commented 5 years ago

@samizdis Good, I'm glad it worked. I assume the messages had attachments? It is usually the attachment that is bad, not the message itself. Did the tool happen to dump the attachment data? The fact that both messages had problems with them makes it seem it might not be a coincidence, maybe the backup process does not deal with failed messages properly. If you happen to know how the messages ended up in this failed state I might even be able to reproduce it.

@dcormier I agree, though if it is a bug in Signal, it would be even better if it didn't create faulty backups to begin with. If you (or anyone) has the problem that the original signal installation is no longer available (so that broken messages found by my code can't be deleted), I can probably make my program delete the problematic messages for you. I had this functionality in a previous version of my program and can probably hack it back in if needed.

@AJolly Naturally: https://send.firefox.com/download/d68364b5ad37f916/#FdeE7ZMaGIL97jZ7N7_98A

griesenator commented 5 years ago

@bepaald I ran into the problem that I reinstalled my phone and I didnt expect the backup process to be a problem. I actually only need one picture from my backup. I had two backup files in Signal/Backups and both seem to fail at Frame 0. So i dont know if its this Bug or the files got corrupted. If its not too much work it would be very nice if you added the feature to delete problematic messages to your tool. Thank You :)

bepaald commented 5 years ago

@griesenator Well a bad mac on frame 0 seems very strange to me. Are you absolutely 100% positive you have the passphrase correct? If you are, I'm afraid chances of restoring that backup may be very low. The first frame is not an attachment frame, it is not even a message yet, it is only the frame that holds the database version. It is a very small frame and it seems unlikely Signal will write it incorrectly. If corruption has occurred it probably will affect other frames as well making recovery very difficult. I have updated the link in the last post, if you run that program as follows: badmacinfo --dontbreak [backupfile] [passphrase], does it get any good frames after the first bad one? If so, I could probably get the program to just dump all your attachments to disk. I don't think dropping the bad frames is a good idea given the special nature of frame 0, but if that is the only bad frame, and we know the database version, I could probably also hack the program to write a new proper frame 0. Let me know what the output of the program is and we'll see if there is any use in trying to fix your database.

PS. Forgive me for not always answering quickly in this thread, I have busy periods now and then...

griesenator commented 5 years ago

@bepaald Well what can I say it was my fault. Just found out i had two passphrases saved in my password manager. It really was just the wrong passphrase. Thank you!

santa-klaus commented 5 years ago

Hey, I ran into a problem with my backup as well. I encrypts until 7501 messages, then cancels with "Wrong passphrase" message. If I change the passphrase the restoration is rejected immediately. signal-back is able to restore the messages (and attachments). With this amount of data is was not able to check if all of them are restored, but some pretty recent ones are. If I use older backup files (that pre-date some of the attachments restored by signal-back) I run into the same error.

My old phone was a Samsung Galaxy S4 Mini running LineageOS 14.1 or 15.1. My new phone is a Fairphone 2 with Fairphone Open 19.05.2 (Android 7.1)

I am able to make a backup on my new phone and restore it.

Let me know if I can help in any way to find the problem. So far I never was able to restore a signal backup when I needed it, and I would really like this feature to finally work reliably.

Would it help to try to import the backup on my old phone again?

Edit: I first thought there were only broken links for @bepaald 's tool, but now I found a working one. However, I don't feel confident to build it on my own... Is there any possibility to share a working binary for Linux or Windows?

bepaald commented 5 years ago

@santa-klaus I've tried cross compiling a windows binary (again), but it doesn't seem to work. I get no errors during building, and it runs fine through wine, but when trying to run it on Windows 10 (in a VM) it just stops running before the programs natural end (without any errors).

Really, building is not that hard, I've added a little build script to this archive: https://send.firefox.com/download/00ff44f1a5ece664/#xFYQZ8JHGG0EyT7x6CBSKQ. For example, if you download and run the latest fedora live image (For example, this one), create a network connection and extract the files, you just have to run: sudo dnf install gcc-g++ cryptopp-devel sqlite-devel followed by sh BUILDSCRIPT.sh, and you are good to go. The same buildscript also works on my Arch machine (with deps installed), so it might work on other distro's as well.

If you manage to get it running, it would be interesting to see if it is the same message that has the bad mac on all your broken backups. Also, inspect the dumped file (I'm assuming it is some attachment) and compare it to the one in the signal install on your phone. And is there anything special about the message (as was the case for @samizdis' failed messages)?

santa-klaus commented 5 years ago

@bepaald Thank you very much for the instructions. Thanks to your tips and the script I was able to build it (but only on the Fedora live system, getting all the dependencies for my linux mint was a pain in the ass, so I gave up)!

The program indeed dumps an attachment. It is different for different backups, and I can't identify anything special about those messages. I cannot delete them or compare them to the originals, since my original install is gone. Can your tool write a backup file without the corrupted messages? I tried the new file optional arguments but it never wrote anything but the dump of the corrupted attachment. Also, is it possible to know if this is the only corrupt message, or does your tool stop after the first corrupt?

Anyway, thank you very much! Your help is much appreciated.

bepaald commented 5 years ago

@santa-klaus Try this: https://send.firefox.com/download/00ff44f1a5ece664/#xFYQZ8JHGG0EyT7x6CBSKQ.

It is hacked together in just 15 minutes and hardly tested, so it might need some more work, but I'll leave the testing to you ;-). The version you used would stop at the first bad frame (unless run with the hidden '--dontbreak' option), but this version will scan the entire file (don't add switches, they will be interpreted as input/output files in this version).

Too bad the original install is missing. Are the different backups incremental backups of the same installation (so newer ones contain at least the same messages as the older ones)? So some messages that are bad in one backup are ok in another? I think that would be some evidence against a bug in Signal and for some other source of data corruption on the phone.

Let me know if the program works. Others might be able to use it as well.

santa-klaus commented 5 years ago

@bepaald Wow, thanks for the black magic! Didn't have to do any testing, just needed to overcome my noobiness and figure out how to call it properly. Now Signal imports the repaired backup file smoothly! The corrupted attachments were two relatively large files, both over 25 mb - a video and a pdf. Interesting enough completely different ones than the corrupted files in the earlier backup file, where a couple of pictures were affected. Interesting enough all those attachments should be present in both backup files, but seem only to be corrupted in either one. So either the signal backup-routine messed up at different points, or the data got corrupted somehow else.

Please let me know if you need some further diagnostics. How should we follow up to improve Signal's behaviour? A meaningful errormessage would be nice for a start (wrong passphrase is not really helpful), but maybe they could include the functionality to reject entries with bad MAC. Would that be a feature request?

Ivoz commented 5 years ago

Sony Xperia X -> Sony Xperia XA2 Plus.

Tried Twice. Both times says it has processed thousands of messages before stopping and saying the password is invalid. Guess me mum is starting off with a blank slate of messages. Should I really be trying to evangelise this app, I wonder...

oneof3holes commented 5 years ago

@bepaald links are down again... a quick link refresh would be great. i ran an older version you had posted as a windows binary a month or 2 ago, got it to clean up some junk... but still wasn't working on my new phone. went through 39k messages and gave me the bogus wrong password thing. i've tried compiling an older link on ubuntu, just wasn't work out for me at all lol. could not figure out my dependency issues or where i needed flags. even tried building arch in a vmm to run it your way, bigger failure than the phone decryption. any assistance would be greatly appreciated.

bepaald commented 5 years ago

@santa-klaus Happy to hear it worked. If the attachments are really very important to you, we could probably extract the uncorrupted ones from one backup and insert them into the other to get a full complete and working backup (while I say this I'm realizing how busy I've been the last few weeks... It is definitely possible though). I can't think of anything else to test on your devices, it really looks like some sort of memory corruption in your case, but I'm not sure we'll ever be certain. Are there storage integrity checkers for android? That might provide some confirmation.

A meaningful error message is certainly a good idea. I don't know if I stated this before, but the chances of the password being incorrect after even 1 frame is decoded successfully are slim to none. If the hash check suddenly fails after dozens (or hundreds or thousands) of messages it is by any reasonable measure impossible that the passphrase is wrong, so I would actually consider that toast a bug. It say 'corruption in backup file' or something to that effect. Also, rejecting frames with a bad mac (basically the functionality of my tool inside signal itself) would be a good feature request in my opinion (just remember feature requests go on the community forums, not on github's issue tracker). Though it is somewhat tricky to implement properly (ie better than I have done). In a way we've been lucky (though statistics are on our side) that all problems have been in attachment data, if corruption occurs in earlier frames (building the sql database or even before that), just dropping the frame might not give desired results.

@Ivoz Obviously this isn't meant to affect your stance towards signal as it nothing official, but just in case you haven't followed all of this thread: it might be possible to retrieve (most of) your mums messages using the tool linked below.

@oneof3holes Of course: https://send.firefox.com/download/00ff44f1a5ece664/#xFYQZ8JHGG0EyT7x6CBSKQ I think the easiest building instruction are probably in this comment from 8 days ago. Good luck!

oneof3holes commented 5 years ago

@bepaald got fedora installed on virtualbox no problem. Installed dependencies and built via your script, super awesome of you to do that btw. However running the program i'm getting a segmentation fault while writing endframe that leads to a core dumping. The worst part is, your program absolutely identified the offending message, but I tried changing versions of signal on my old phone to try and work around the encryption issue long before i went online for answers. So I've lost access to my message and only have the backups I made. Can't re-register that phone since it's out of service and doesn't work on my new provider's bandwith lol, but i don't think the data itself was destroyed. I don't think i can root my old phone to dig deeper on it, could be wrong on that. I was able to get my texts and pics back with signal-back, but i really wish they were in the appropriate conversations.

Here's the message it ended on. If you have any thoughts or suggestions I'm willing to try it. I could just being shit out of luck here, so don't feel bad telling me that either. If I weren't so impatient and fiddling around on my old phone I could've solved it with your program by now.

Trying to dump decoded attachment to file 'attachment_4069.bin' FRAME 38283 (089.7%)... done! Removing 1 bad frames from database... Exporting backup to 'newbackup.backup' Dealing with table 'sms'...31522 entries... Dealing with table 'mms'...2760 entries... Dealing with table 'part'...1975 entries... Dealing with table 'thread'...0 entries... Dealing with table 'identities'...0 entries... Dealing with table 'drafts'...0 entries... Dealing with table 'push'...0 entries... Dealing with table 'groups'...0 entries... Dealing with table 'recipient_preferences'...0 entries... Dealing with table 'group_receipts'...0 entries... Dealing with table 'job_spec'...0 entries... Dealing with table 'constraint_spec'...0 entries... Dealing with table 'dependency_spec'...0 entries... Dealing with table 'sticker'...0 entries... Writing EndFrame... Segmentation fault (core dumped)

bepaald commented 5 years ago

@oneof3holes Whoops, well the segfault is certainly a bug. I'm afraid, looking at the output you pasted, I am guessing there is more corruption in the backup file than my tool can currently fix. The backup file is not read in its entirety (hence 0 'thread' entries, and segfaulting when trying to write the (unavailable) endframe). This probably means that not only frame data is corrupted, but also the byte in between the frames which holds the size of the next frame. Once this happens, no frame will be decoded properly anymore. To possibly confirm this, try this new version of the tool. It will not give better results, but might tell me why it stops decoding frames at 89.7% (and it hopefully will not segfault either).

I have a few possible fixes in mind already, for example, just guessing ('bruteforcing' in a way) the framesize, skipping it, and check if we get a valid frame after that (though more than just the next frame could be affected). But I will first need to try and recreate your situation on one of my own backups. Implementing will almost certainly take more than one sit down and I do not know when I will have time for even one programming session (though hopefully this weekend). How many backups do you have? Would you miss out on a lot if you use an older one, or do they have the same problem?

oneof3holes commented 5 years ago

Trying to dump decoded attachment to file 'attachment_4069.bin' FRAME 38283 (089.7%)... Failed to read next frame (951835245 bytes) done! Removing 1 bad frames from database... Exporting backup to 'newbackup.backup' Writing HeaderFrame... Writing DatabaseVersionFrame... Writing SqlStatementFrame(s)... Dealing with table 'sms'...31522 entries... Dealing with table 'mms'...2760 entries... Dealing with table 'part'...1975 entries... Dealing with table 'thread'...0 entries... Dealing with table 'identities'...0 entries... Dealing with table 'drafts'...0 entries... Dealing with table 'push'...0 entries... Dealing with table 'groups'...0 entries... Dealing with table 'recipient_preferences'...0 entries... Dealing with table 'group_receipts'...0 entries... Dealing with table 'job_spec'...0 entries... Dealing with table 'constraint_spec'...0 entries... Dealing with table 'dependency_spec'...0 entries... Dealing with table 'sticker'...0 entries... Writing SharedPrefFrame(s)... Writing EndFrame... Error: EndFrame not found

@bepaald this was the error notification this go. I wish it weren't such sensitive data, otherwise I'd just send you my backup to play with. I am most certainly willing to try all the upgrades and tinkering you do to your program and post my results. This is my only backup I have, unfortunately. I had a little more faith in signal than I should have.

bepaald commented 5 years ago

@oneof3holes Thanks. It is obvious the framesize is not correct here, it tries to read over 900mb of data for a single frame, which given the 100mb max for attachments should not be possible. I just realized it is also possible, though unlikely, that the previous frame size was already incorrect (causing both the bad Mac, and the next framesize to be read from a random file position). Can you get any info from the dumped attachment (it greatly depends on the filetype)? Does it seem unexpectedly large or small? Can you open it, and is there any corruption, and is that at the start or the end of the data?

I'll try to get started on a possible fix.

I had a little more faith in signal than I should have.

Just for the record, the location of the corrupted data in this case, outside of any encryption and not representing user data, just a single unencrypted byte written to memory, is another strong indication that no bug in Signal caused this. Still seems more likely corruption due to bad memory or something like that.

oneof3holes commented 5 years ago

@bepaald > Thanks. It is obvious the framesize is not correct here, it tries to read over 900mb of data for a single frame, which given the 100mb max for attachments should not be possible. I just realized it is also possible, though unlikely, that the previous frame size was already incorrect (causing both the bad Mac, and the next framesize to be read from a random file position). Total size of my backup file is only 436.9mb of data, so something is amiss. The .bin file is 350kb in size, looking my gallery the original picture was 3.75mb, but i'm sure it's getting compressed in signal.

Can you get any info from the dumped attachment (it greatly depends on the filetype)? Does it seem unexpectedly large or small? Can you open it, and is there any corruption, and is that at the start or the end of the data? Being that it's a picture, I have no idea what I'd be looking for in hex editor since it's a bin. That area is really out of my field of knowledge... other than I do have a gui hex editor on my virtual feodra.

Just for the record, the location of the corrupted data in this case, outside of any encryption and not representing user data, just a single unencrypted byte written to memory, is another strong indication that no bug in Signal caused this. Still seems more likely corruption due to bad memory or something like that. I'm almost 100% certain this was a picture message that got hung up and didn't send, even after multiple attempts, because I live in a highly rural area with spotty cell signal for data. That definitely doesn't go on signal. What all that has to do with things is unknown to me, but I see how it could cause errors, especially since it wasn't the first time I've had hung messages... or there is a reason i was replacing my phone. It was an s5, kinda ancient by cell phone standards. Almost 4 years for something bad to write itself. Been rocking it since textsecure days a couple phones ago.

bepaald commented 5 years ago

@oneof3holes Try this (don't get your hopes up yet, it's highly experimental): https://send.firefox.com/download/d6451062b7827b11/#o2JXjrFrGmnxrnRmIFW0_g

Please let me know if it works!

Being that it's a picture, I have no idea what I'd be looking for in hex editor since it's a bin.

You could try to just rename the .bin to jpg and open it and see... sometimes that works (if it fails to open at all it is probably corrupted from the very beginning): screenshot

It is interesting that the corruption first occurs in a message that (initially) failed to send, @samizdis also had bad macs on failed messages. I do not see how it could affect the integrity of the following messages (or even the bytesize marker) though.

oneof3holes commented 5 years ago

@bepaald no luck, back to ending with

Writing EndFrame... Segmentation fault (core dumped)

I did try renaming that .bin to pretty much every picture related file extension I knew, but to no avail.

bepaald commented 5 years ago

@oneof3holes Hm, that's unexpected. Could you give me a bit more of the output?

oneof3holes commented 5 years ago

@bepaald here's the entire display, excluding key info. I xxxxxx'd out the message body and recipient number as well.

COUNTER: 3458556959 Reading backup file... FRAME 38282 (089.7%)... WARNING: Bad MAC in frame: theirMac: (hex:) 2c 39 83 f5 9c 91 bc fe a5 bc ourMac: (hex:) 12 34 eb 14 44 e8 2c 33 71 74 b7 c6 a4 ed 1c 53 7b 68 b9 0b ec 38 34 a2 dd 02 db 45 e9 ab 70 03 WARNING: Bad MAC in frame, trying to print frame info: Frame number: 38283 Type: ATTACHMENT

Which belongs to entry in 'mms' table:

bepaald commented 5 years ago

@oneof3holes Thanks, I'll look into it. (For the future, just the output from the Trying to dump decoded attachment to file-line is fine.)

Just to be sure, you're not accidentally running the original, previous version are you? Because the output is completely the same (the segfault is back and even the FRAME 38283 (089.7%)... Failed to read next frame (951835245 bytes)-line is missing again) and I can't think why this would happen in the newer version.

Also maybe try this one, it should be the same as the last one, it just outputs a tiny bit more info (and fixes a typo): badmacinfo.zip

oneof3holes commented 5 years ago

@bepaald definitely got a file to spit out that signal would at least fully decrypt. Only problem is none of the messages actually show up inside signal. I can even create a back up, it enumerates the correct number of messages, but it stil comes up empty if I delete everything and trying using the newer signal created backup as my restore point.

Trying to dump decoded attachment to file 'attachment_4069.bin' FRAME 38283 (089.7%)... Failed to read next frame (951835245 bytes at filepos 411110199) Starting bruteforcing offset to next valid frame... Checking offset 107580 bytes GOT GOOD MAC AT OFFSET 107584 BYTES! Now let's try and find out how many frames we skipped to get here.... Checking if we skipped 0 frames... YEAH! Got frame, breaking FRAME 38284 (089.8%)... Failed to get valid frame from decoded data... done! Removing 1 bad frames from database... Exporting backup to 'newbackup.backup' Writing HeaderFrame... Writing DatabaseVersionFrame... Writing SqlStatementFrame(s)... Dealing with table 'sms'...31522 entries... Dealing with table 'mms'...2760 entries... Dealing with table 'part'...1975 entries... Dealing with table 'thread'...0 entries... Dealing with table 'identities'...0 entries... Dealing with table 'drafts'...0 entries... Dealing with table 'push'...0 entries... Dealing with table 'groups'...0 entries... Dealing with table 'recipient_preferences'...0 entries... Dealing with table 'group_receipts'...0 entries... Dealing with table 'job_spec'...0 entries... Dealing with table 'constraint_spec'...0 entries... Dealing with table 'dependency_spec'...0 entries... Dealing with table 'sticker'...0 entries... Writing SharedPrefFrame(s)... Writing EndFrame... Done!

bepaald commented 5 years ago

@oneof3holes Ok, that is too bad. NOTE, all of the following is speculation What happens is that we need to guess how many frames were skipped before we read a (possible) frame with a good MAC. But there is really no way of telling, except for just decoding the frame (the frame number is input for the decoder) and trying to see if it is a valid frame. It seems to me that the '0 zero frames skipped' scenario falsely passes the validation (after all, over a 100kb were skipped, that should be at least one frame). I am not at home right now, and do not have a computer at my disposal. I will try to make the validation more strict (if I can), but it won't be before tomorrow.

In the meantime, if you feel comfortable, you can try two things: SEE EDIT BELOW

If I'm wrong about any of this (and I could be), or it gets too complicated to fix (especially without direct access to the backup), it might be possible to work with the part you are able to get now, we just need to fill the thread table with proper values, but many of those could be derived from the message tables. But... That's for later, if all else fails (keeps failing). Good luck!

EDIT: I tried quickly changing the validation of the EndFrame-type (which I think is the problem), and also did step 1 already, so try this please: badmacinfo.zip. And please post the output. If it doesn't work, you could still try the second point I made above.

oneof3holes commented 5 years ago

@bepaald got another full decrypt, but no actual restoration in my app. Tried method 2, got a segmentation dump after a lot of output, couldn't even scroll back to my original command. So here's what I have about where things went sideways with option 2.

Nothing wrong here, just the only output I see that is different than got startype, bit32 type, or got endtype.

GOT STARTTYPE BIT32 TYPE BIT32 TYPE BIT32 TYPE GOT STARTTYPE GOT STARTTYPE nope! :( Checking if we skipped 2 frames... nope! :( Checking if we skipped 3 frames... nope! :( Checking if we skipped 4 frames... BIT32 TYPE GOT ENDTYPE

Here's the 10 or so entries before dumping.

GOT STARTTYPE GOT ENDTYPE GOT ENDTYPE GOT ENDTYPE BIT32 TYPE GOT ENDTYPE GOT ENDTYPE BIT32 TYPE GOT ENDTYPE BIT32 TYPE Segmentation fault (core dumped)

bepaald commented 5 years ago

@oneof3holes Sorry, this is getting frustrating.. Please try this new version, it will not fix anything, but I need some hint what's going on. I hope this will give some info (I've removed the STARTTYPE, BIT32 TYPE stuff as well, it never shows up in normal backups, because these types should not occur in them, but with the corruption of course any random data can appear), please post all output after Trying to dump decoded attachment.

Sorry this is progressing so slowly. I've created several backups and manually broke them in all the ways I guess yours may be broken and my program fixes all of them so far (except the one where I destroyed all the data from a certain point in the file, but at least the program then just exits normally and says it cant fix it...). I'm still hoping to make some progress, but I have to admit it is difficult.

badmacinfo.zip

EDIT I found tons of places where my code assumes correct input (it wasn't originally written to fix borken backups, so these are false assumptions in this case). It's going to take a long time tracking it all down and fixing them, so in the meantime, expect more segfaults... :)

oneof3holes commented 5 years ago

@bepaald

Sorry this is progressing so slowly.

I'm beyond ecstatic you haven't grown tired of it, so no need to apologize to me. You're the one doing me a favor here.

Here's the output on the newest version

Trying to dump decoded attachment to file 'attachment_4069.bin' FRAME 38283 (089.7%)... Failed to read next frame (951835245 bytes at filepos 411110199) Starting bruteforcing offset to next valid frame... Checking offset 107580 bytes GOT GOOD MAC AT OFFSET 107584 BYTES! Now let's try and find out how many frames we skipped to get here.... Checking if we skipped 0 frames... nope! :( Checking if we skipped 1 frames... nope! :( Checking if we skipped 2 frames... nope! :( Checking if we skipped 3 frames... nope! :( Checking if we skipped 4 frames... terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc Aborted (core dumped)

bepaald commented 5 years ago

@oneof3holes

I'm beyond ecstatic you haven't grown tired of it, so no need to apologize to me. You're the one doing me a favor here.

Well, trying anyway... No worries about growing tired of it, I'm quite determined to squeeze some useful bits out of your backup, just not sure how long it'll take.

So... the bad_alloc usually means running out of memory. I did find a small memory leak in the program, it shouldn't have been that bad after just 5 iterations of the loop.... but maybe things are worse because of the VM. Anyway, I hope I fixed that. Also fixed at least one segfault I was able to reproduce here by feeding the program random data. So try this one:

badmacinfo.zip

Again, output would be nice.

BenoMueller commented 5 years ago

Same happens for me:

Unfortunatly, I was not able to build badmacinfo on Kubuntu 19.04 (with g++, libcrypto++-dev libcrypto++-doc libcrypto++-utils, libsqlite3-dev installed):

ryptbase/getbackupkey.cc:28:15: error: ‘digest’ was not declared in this scope
   std::memcpy(digest, pass, passlength);
               ^~~~~~
cryptbase/getbackupkey.cc:28:15: note: suggested alternative: ‘_xtest’
   std::memcpy(digest, pass, passlength);
bepaald commented 5 years ago

@BenoMueller There surely was more to the error than you pasted... digest is defined in the line right above the line this error is generated from. The problem I believe is that Ubuntu for some reason is shipping with a very old version of cryptopp (5.6.4 I believe? Current version is 8.2.0), which does not define the CryptoPPnamespace. So I suggest you find some way to update it or run a different (I'm resisting the urge to say 'proper') distro, like Arch or Fedora (even just the live image would work, as I describe in this comment). A bit earlier in this thread, someone also had trouble with the sqlite version in Ubuntu, but I don't know the details about that.

I hope it works for you!

oneof3holes commented 5 years ago

@bepaald

Again, output would be nice.

No output this time... it officially worked. I can't even begin to express my gratitude, but thank you.

The problem I believe is that Ubuntu for some reason is shipping with a very old version of cryptopp (5.6.4 I believe? Current version is 8.2.0), which does not define the CryptoPPnamespace. So I suggest you find some way to update it or run a different (I'm resisting the urge to say 'proper') distro, like Arch or Fedora (even just the live image would work, as I describe in this comment). A bit earlier in this thread, someone also had trouble with the sqlite version in Ubuntu, but I don't know the details about that.

Hysterically i was one of the people having that compilation issue. Running fedora in virtualbox was a relative ease. Ubuntu was running running a lower versiion of cryptopp and wouldn't not upgrade any further, despite throwing sudo and -dev and all sorts of things on my command. It honestly took less than 20 minutes to install fedora and have your program downloaded and compiling. I did have to use dropbox to transfer my files from phone to virtualbox as i never quite figured out sharing a directory or enabling a usb port lol.

Again, thank you so much!

BenoMueller commented 5 years ago

Ok, with the 'proper' distro (I downloaded Fedora), it worked, thanks for the hint. I executed the following:

badmacinfo --dontbreak [backupfile] [passphrase]

Find attached the output: Output_Badmacinfo.txt

Then I ran the following to generate the new backupfile without the broken attachment: badmacinfo [backupfile] [passphrase] [newbackupfile]

And, YES, I could import the new backup file into Signal.

Many, many thanks for your help!

bepaald commented 5 years ago

@oneof3holes

No output this time... it officially worked. I can't even begin to express my gratitude, but thank you.

No problem! I'm happy it finally worked, yours was certainly the most problematic backup so far, so it feels a bit like a victory, and I needed that. I hope you haven't lost too many messages.

@BenoMueller Excellent, happy to help! Thanks for reporting your success back here.

For anybody following this, or coming here in the future: Code will now be at: https://github.com/bepaald/signalbackup-tools

oneof3holes commented 5 years ago

No problem! I'm happy it finally worked, yours was certainly the most problematic backup so far, so it feels a bit like a victory, and I needed that. I hope you haven't lost too many messages.

I lost the 1 offending picture message and i have a few weeks worth of picture messages that didn't transfer back into signal when i imported in from the default s10 messaging app, but other than we are good to go. And from my view point, huge win as well. I have maybe $40-50 usd in btc dust sitting in a wallet, I'd gladly send it your way. Probably crap pay for the work you did, but I'd feel like a jerk if I didn't offer you something for your time and effort.

bepaald commented 5 years ago

@oneof3holes Good, I take it you haven't been using Signal while we were working on your backup then? Cause locally, I've succesfully merged threads from two different backups into one. We could have tried that to get newer messages into the old backup.

I've put a bitcoin link on bottom of the project page's readme. Feel free to donate anything you like, but know that includes nothing! I do this as a hobby, and did not anticipate any donations. I would have done it, and will continue to do it without any compensation.

oneof3holes commented 5 years ago

@bepaald Exactly why I'd gladly give it. In case you're the nationality your name indicates, hit up a coffee shop for me or something. My chosen trade is construction, so I appreciate donating time for free to those who need it. But I only refuse money once from those I know can afford it.

Oh, I also emailed signal and informing them of your fix... and encouraging them to incorporate it lol. Nothing super important in my texts, but can't put a price on years of discussions. And I'll monitor this and your git if you upgrade and do fancier things, since my file was such a pain in the ass. Just tag me and I'll try to get back in under a day.

And honestly, may ditch ubuntu for fedora, really liking it. I aborted arch because a lot of the guis were fedora similar. Apparently I may have been wrong for not wanting to explore that further, but I've learned a lot thanks to this thread. For that and a fix to my backup, I'm eternally grateful.

santa-klaus commented 5 years ago

@bepaald I will try to write up a feature request for Signal to reject bad frames in the backup in the forum. As for fixing the bug (wrong error message), do you think we should open a new issue stating explicitely that?

Also, I might want to try to merge different backups. My Signal lost most attachments when I moved it from SD-card to internal storage (my SD card is behaving funky), so I am left with a new (working) backup without most pictures, but about three weeks of new messages, and the old backup your tool fixed with working messages. Don't know when I'll find the time to try it, and it's not super important for me since I have those pictures still in my desktop app, but I think I would give it a try if you need a tester. Just let me know what I should do :grin:

Thanks for sharing your tool on github, and thanks again for all the work!

bepaald commented 5 years ago

@santa-klaus Yeah, I think a new issue would be in order. Just because this one is so old and long, I don't think any dev is still subscribed to this one so they might not read it here.

I'll get to work on the merging part as soon as I have some time. Much code is already written, I just need to merge it into the current latest version (hopefully that's not too hard). And I need to write a proper argument parsing routine, as the tool is getting too much functionality for the simple parsing it's doing now. I don't know when I'll have time, but I'll let you know as soon as I have something to test.

mk121212 commented 5 years ago

I found this issue because I also encountered an 'Invalid Passphrase' error message when trying to restore a Signal backup on my new phone that was created with my old one. I tried to use the tools https://github.com/xeals/signal-back and https://github.com/bepaald/signalbackup-tools without success (more on this later; my situation is a bit different to the ones described above in the sense that not single bad frames were found but the backup file was just unreadable by the tools).

However, once I deactivated signal-backups on the old phone and re-enabled it (settings - chats and media - chat backups; don't forget to write down the new passphrase), Signal on the new phone was suddenly able to restore the backup successfully. Also the aforementioned tools where able to read the backup.

Since this might be of help, here is a short documentation.

Old phone: Moto G 4G (peregrine, LineageOS version 14.1.20190207-NIGHTLY-peregrine, Signal 4.43.8) New Phone: Moto G7 Plus (Android 9, Build number PPW29.98-66, Signal 4.43.8)

To run the two tools mentioned above, I installed Fedora Mate (Release 30 (MATE-Compiz) 64-bit) in a virtual box.

Here are the versions of several tools:

[user@localhost ~]$ gcc --version
gcc (GCC) 9.1.1 20190503 (Red Hat 9.1.1-1)
user@localhost ~]$ sqlite3 --version
3.26.0 2018-12-01 12:34:55 bf8c1b2b7a5960c282e543b9c293686dccff272512d08865f4600fb58238alt1
[user@localhost ~]$ yum info cryptopp | grep -C2 Version
Installed Packages
Name         : cryptopp
Version      : 8.2.0
Release      : 1.fc30
Architecture : x86_64
--
Available Packages
Name         : cryptopp
Version      : 8.2.0
Release      : 1.fc30
Architecture : i686
[user@localhost share-Fedora]$ ./signal-back_linux_amd64 --version
signal-back v0.1.7-alpha.2-dirty
proto commit: d6610f0
[user@localhost signalbackup-tools]$ git log --pretty=format:'%h' -n 1
53e58af

Output when I run signalbackup-tools on a backup that was created when I first enabled Signal-backups (I took a picture of the passphrase and check it several times):

[user@localhost signalbackup-tools]$ ./signalbackup-tools ../signal-2019-07-25-15-15-17.backup [passphrase]
IV: (hex:) 55 55 04 65 fa c7 4b 38 f2 3e ea ac 22 b3 9d 7c (size: 16)
SALT: (hex:) 4a 68 61 12 1b 19 75 98 a7 a2 10 74 e9 94 2e c4 9f a1 9d eb be ce ce aa 17 91 81 5b 59 34 d0 9e (size: 32)
BACKUPKEY: (hex:) 29 59 28 52 e0 d4 b1 a8 aa 35 d8 54 4a b8 46 64 c1 70 92 26 d0 29 68 22 65 05 c4 b8 0f ba 6d 81 (size: 32)
CIPHERKEY: (hex:) 72 32 f6 1b b8 ee 7b 5f 2d 1b db af e6 ed bd 8e 1d 89 66 47 b4 8e 0e 79 0c e3 38 a6 68 67 cc 7c (size: 32)
MACKEY: (hex:) bb f4 73 02 32 6a 16 d5 6d ce 65 89 17 c4 19 a8 6a 8c aa c4 76 2e fe 4f a9 cc 1c 5c 44 06 43 9a (size: 32)
COUNTER: 1431635045
Reading backup file...
FRAME 0 (000.0%)... 
WARNING: Bad MAC in frame: theirMac: (hex:) c3 e4 32 15 47 d5 c6 88 7c 4e
                             ourMac: (hex:) d9 70 16 25 db 07 45 2d 9d 33 55 dc b7 07 10 e6 e5 c3 6c 97 2d 6a 9a 85 a9 a7 a5 99 bd 85 7d 73
Failed to get valid frame from decoded data...
Data: (hex:) 60 f5 71 01
done!

Output with signal-back:

user@localhost share-Fedora]$ ./signal-back_linux_amd64 check signal-2019-07-25-15-15-17.backup 
Password: error: Encountered error while checking: failed to write raw: consume [attachment]: can't read attachment of length 0

Output of the tools when I once deactivated Signal backups on the old phone and re-enabled it:

[user@localhost signalbackup-tools]$ ./signalbackup-tools ../signal-2019-07-25-22-02-08.backup [passphrase]
IV: (hex:) 7c 0b 53 20 74 18 b3 cc 8e 58 d1 7d 7a 5a 4a 49 (size: 16)
SALT: (hex:) 2c 3d ae c5 2b d0 55 1d 71 aa a0 7c ca e6 eb 0b b3 23 a1 6f e1 a0 d2 f2 60 5e 7c a1 fd 02 d3 0c (size: 32)
BACKUPKEY: (hex:) 32 e5 ff d4 1d 0d 7e e6 79 89 0f 3a 8e 69 25 96 fd 8c 46 e3 8c fa ae 98 9c e0 da e6 46 68 ae 95 (size: 32)
CIPHERKEY: (hex:) 1c 0f 87 25 eb d4 f4 7e ba 94 d5 d5 55 c3 59 3c 68 d4 e6 05 eb c3 9b 73 50 04 fa be 61 8d c3 7e (size: 32)
MACKEY: (hex:) 39 e8 28 82 bd 57 fa 7e 5c 7c 1b 9a 17 58 a4 67 11 e0 d3 71 83 fb 5a b8 24 33 6c 6d 2c 3e ce 08 (size: 32)
COUNTER: 2081116960
Reading backup file...
FRAME 15660 (100.0%)... Read entire backup file...
done!
[user@localhost signalbackup-tools]$ cd ..
[user@localhost share-Fedora]$ ./signal-back_linux_amd64 check signal-2019-07-25-22-02-08.backup 
Password: 2019/07/28 22:34:13 Backup looks okay from here.