tlambertz / seedvault_backup_parser

Decrypt, Modify and Reencrypt Seedvault Android Backups
Apache License 2.0
103 stars 15 forks source link

[Feature] V0 full encryption + support v1 + better arg handling + better logging + extra bip39 validation #16

Open crass opened 6 months ago

crass commented 6 months ago

This is a major upgrade and refactoring that adds support for full V0 backup encryption, V1 backup decryption, better logging, and argument parsing. Included are the changes from #10. This should be backwards compatible with existing decrypted backups. Major refactoring is done such that there are now a class for the decryptor and encryptors. The method naming scheme was left as is, but that leaves much to be desired. This fixes #14.

khimaros commented 6 months ago

this is exciting to see! i'll be testing this out and will report my experience here.

grote commented 6 months ago

Awesome contribution, thanks a lot! I just browsed through a bit and wondered if it would make sense to split the v0/v1 parts into separate files instead of mixing both into huge files.

crass commented 6 months ago

Awesome contribution, thanks a lot! I just browsed through a bit and wondered if it would make sense to split the v0/v1 parts into separate files instead of mixing both into huge files.

Yeah, was I thinking there might be utility in having it as one file, like just download the file and use it. Currently that doesn't work because of the protocol buffer modules, which I was thinking of adapting to be put inline in the file. But thinking more about it, even then there's still the non-builtin dependencies, makes it not as simple as downloading or transferring a single file. So yeah, it makes more sense to break it out. I'm not sure I'll get to this soon though.

khimaros commented 6 months ago

tested this out, unfortunately it aborts when running show

i've verified that golang seedvault-extractor extracts this backup correctly, though it does skip a number of packages in unsupported states.

here's the output of the failure:

  org.connectbot
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/tink/core/_tink_error.py", line 34, in wrapper
    return func(*args, **kwargs)
  File "/usr/local/lib/python3.9/dist-packages/tink/streaming_aead/_decrypting_stream.py", line 67
, in _read_from_input_stream_adapter
    return self._input_stream_adapter.read(size)
tink.cc.pybind.tink_bindings.PythonTinkException: INTERNAL: Authentication failed: 30594816:error:
1e000065:Cipher functions:OPENSSL_internal:BAD_DECRYPT:external/boringssl/src/crypto/fipsmodule/ci
pher/e_aes.c:1078:

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/tink/streaming_aead/_streaming_aead_wrapper.py", li
ne 96, in read
    data = self._attempting_stream.read(size)
  File "/usr/local/lib/python3.9/dist-packages/tink/streaming_aead/_decrypting_stream.py", line 98
, in read
    data = self._read_from_input_stream_adapter(size)
  File "/usr/local/lib/python3.9/dist-packages/tink/core/_tink_error.py", line 36, in wrapper
    raise TinkError(e)
tink.core._tink_error.TinkError: INTERNAL: Authentication failed: 30594816:error:1e000065:Cipher f
unctions:OPENSSL_internal:BAD_DECRYPT:external/boringssl/src/crypto/fipsmodule/cipher/e_aes.c:1078
:

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/srv/seedvault_backup_parser/parse.py", line 1126, in <module>
    main()
  File "/srv/seedvault_backup_parser/parse.py", line 1114, in main
    kv_parsed = SeedVaultBackupDecryptor(args.backupfolder, password=args.password).decrypt()
  File "/srv/seedvault_backup_parser/parse.py", line 581, in decrypt
    return self.parse_backup(self.backupdir, self.targetdir)
  File "/srv/seedvault_backup_parser/parse.py", line 894, in parse_backup
    self.parse_apk_backup(pkg_name, pkg_metadata, key, salt)
  File "/srv/seedvault_backup_parser/parse.py", line 736, in parse_apk_backup
    self.parse_apk_data_backup(pkg_name, pkg_metadata, key, salt)
  File "/srv/seedvault_backup_parser/parse.py", line 692, in parse_apk_data_backup
    bytes_read = dec_stream.read()
  File "/usr/local/lib/python3.9/dist-packages/tink/streaming_aead/_streaming_aead_wrapper.py", li
ne 109, in read
    raise core.TinkError(
tink.core._tink_error.TinkError: No matching key found for the ciphertext in the stream

seems to fail while attempting to extract org.connectbot. perhaps a hint is that seedvault-extractor skips this package with the reason:

skipping "org.connectbot" (unsupported state "WAS_STOPPED")
crass commented 6 months ago

seems to fail while attempting to extract org.connectbot. perhaps a hint is that seedvault-extractor skips this package with the reason:

skipping "org.connectbot" (unsupported state "WAS_STOPPED")

This is odd. I thought I'd read that STOPPED apps do not get backed up. So there shouldn't be a backup data file for this app. Yet the code path taken indicated that there is such a file. I understand you to be saying that seedvault-extractor just skips this backup. It could be that there should be a backup, but that there has been some corruption of the encrypted file. I think that would produce a similar error.

I've added a change that will catch the exception you're hitting, output an error message, and continue on. The error message will be of the form Error: Failure to decrypt base64string: ..., where base64string should be the name of a file in the encrypted backup. Can you tell me the size of that file?

Also please tell me what versions you are running for python and the various modules. Here's mine:

absl-py      2.1.0
protobuf      4.25.3
pybip39       0.1.0
pycryptodome  3.20.0
tink          1.10.0

And I'm running Python 3.10.12 on an ubuntu derivative, and have tested on Python 3.11.2. tink version 1.9.0 is working for me as well.

If you versions do not match, please update them to those versions (perhaps in a virtual env if needed) and retest. Also, note that multiple -v options can be given to increase the verbosity level (up to two currently).

crass commented 6 months ago

@khimaros Looking at this again, I have many apps in the WAS_STOPPED state that have backup data that is successfully decrypted. Its unclear why seedvault-extractor skips all apps with a state that is not the empty string, but that seems unnecessary in my experience.

grote commented 6 months ago

Could it be that an app was backed up, then later entered the stopped state, so it is in WAS_STOPPED, but still has historic backup data available? Would be nice to figure this one out as it may point to a bug in Seedvault.