Signal is the go free and open source messenger app for privacy conscious people, but it there are some issues and limitations. One criticism is that it doesn’t integrate its backup system well with cloud storage. For instance, WhatsApp will more easily allow you to store backups on Google Drive. Apart from that, usage of the Signal backup restore function is not particularly well explained and crashes are very common due to a fairly simple issue. I went down the rabbit hole to analyze the root cause.
When moving to a different device or freshly setting up an existing one, you probably want to keep your chat history. I had that use case recently, when I installed GrapheneOS on my Pixel 6. A while beforehand I had already heard from a friend that restoring a Signal backup is buggy. They were experiencing crashes and had to give up on restoring their old messages, since backups can only be restored when newly setting up the app. Later on, restoring isn’t possible. There is also a feature to directly transfer chat history from one device to another, but that also didn’t work for them and wasn’t even an option for me, since I was using only a single device.
What’s the issue?
Backups can be enabled and scheduled in the Signal settings. When you first do that you’ll get a 30-digit passphrase that you will need to restore the backup. Once that is done two Signal backups will always be available in the specified directory. When you want to restore them, you have to newly install Signal on the respective device. Next choose the restore option and the file. Enter your passphrase and confirm. If it works, it should be pretty quick. When I finally got it to work, it only took about 3 minutes to restore a 5GB backup including all media. The problem is that for me and a lot of users, the app just crashes after a few moments.
So why does this happen?
Signal is open source, so it’s possible to just debug the code to find the cause. Also researching online will yield multiple user reports about this happening. And finally you can look at the logcat of the app. On the first startup screen of a newly installed Signal app, you can also just tap the icon about ten times. That will show you the app logs. If you do that after experiencing such a crash, there will be one of two exceptions with relevant stack traces. One indicates a negative array length being used when initializing an array. The other one being an out of memory error. There is a third possibility to that will probably result in an ArrayIndexOutOfBoundsException, however I haven’t been able to observe this since it’s rare.
Looking at the relevant code, you can see that Signal stores the backed up data in multiple chunks, but in a single file. However when decrypting the backup, the app doesn’t even know how large each chunk is. That information is also encrypted inside the backup file. Later that information is used to allocate a buffer. If that buffer is thus too large or the size is negative the app will crash. The third option can happen when the decrypted buffer size is reasonable, but the restoration process will still fail.
What causes the buffer size to have such random values?
Well apparently the app (currently) has no way of checking whether the passphrase you enter for decryption is correct. Because of this, it will simply decrypt it even with an incorrect passphrase and take the value as a number from where the chunk size (=buffer size) WOULD be if the file was decrypted correctly. That’s why entering different wrong passphrases can yield different stack traces. So yeah, that’s it. If Signal crashes for you when restoring a Signal backup, you’re probably entering a wrong passphrase.
And that’s indeed what I and some other users were doing. I was entering my Signal PIN, another user was entering an old passphrase. The UI IMO does not give sufficient information or a reminder to a user that a 30 digit passphrase needs to be entered. Thus, there are two issues: First are the crashes when entering a wrong phrase, due to insufficient error handling and because Signal doesn’t know the chunk size at that time. Second, the UX is very imperfect, possibly causing users to enter the wrong value.
How can the Signal backup functionality be fixed?
I proposed these improvements be made to solve this issue:
- The text should be adjusted to remind the user that the 30-digit backup passphrase is required. I forgot this, and many users will forget it, thus entering the Signal PIN or something else, causing confusion.
- The error should be caught properly. If the chunk size is unreasonable, immediately display a message stating that the passphrase isn’t correct, or just catch any exception with a reasonable message. This would be a quick fix to prevent crashes and confusion.
- When activating backups the passphrase is shown. IIRC you just have to check a box that you wrote it down. I think it would be better to have the user write it back. Maybe using words would be more memorable, too. Given the number of people who are reporting here, a lot of users may have forgotten the passphrase, so UX improvements may be necessary.
- Review if it makes sense or is necessary to even encrypt the chunk size. Can it not be in plain in the file header or be a fixed value?
- It should be more clear how to change the passphrase. When I switch my phone I may remember to check if I have a recent backup and look at the Chat Backup menu. If I then realize I don’t have the passphrase anymore, it’s not immediately clear how to proceed.
At least I had fun debugging…