Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

py-tibade: Python Titanium Backup Decrypt

Author: Tet Woo Lee

This is a Python/pycryptodome-based implementation of TitaniumBackupDecrypt, which was originally authored by Brian T. Hafer. It will decrypt backups made by Titanium Backup for Android.

An alternative Python implementation is is TiBUdecrypter created by David O'Rourke.

Installation

This is available on both PyPi:

pip install pytibade
pytibade --version

and conda:

conda create -n pytibade -c twlee79 pytibade
cona activate pytibade
pytibade --version

Usage

positional arguments:
  inputfiles            Input file(s), either a list of filenames or as an
                        unexpanded glob wildcards that is expanded internally

optional arguments:
  -h, --help            show this help message and exit
  --version             show program's version number and exit
  -s SUFFIX, --suffix SUFFIX
                        Suffix to add to base filename of decrypted files,
                        appended to stem before any extensions (default:
                        -decrypted)
  -m MATCH_BASENAME, --match_basename MATCH_BASENAME
                        Regular expression to match base filename of a file,
                        applied to filename without directory; first capturing
                        group should be base filename; an error is produced if
                        files don't match this pattern, which can be ignored
                        with the `-c` option (default:
                        (^.*-[0-9\-]+)[.]([a-z]{3})([.a-z]{0,4}))
  -p PASSPHRASE, --passphrase PASSPHRASE
                        Passphrase used to encrypt the backup files, if not
                        present then user will be prompted to enter one; same
                        passphrase used for all files. (default: None)
  -c, --continue        Continue processing next file even if error
                        encountered; by default script will stop on first
                        error (default: False)
  -v, --verbose         Increase logging verbosity, available levels 1 to 3
                        with `-v` to `-vvv` (default: 0)

Simplest usage: pytibade com.my.favourite.app-20200426-111127.tar.gz

The script will then prompt for the passphrase.

The script can be used to decrypt a batch of files by specifying multiple inputfiles or wildcards in inputfiles. The same passphrase is used for all files. The --continue option is useful to persistently attempt to decrypt all specified files despite earlier failures (useful, for example, if there is a mixture of encrypted and unencrypted files).

Titanium Backup File Format

Information Source

This information was originally taken from a post on Christian Egger's G+ page that has now disappeared. It has been reformatted a little for markdown by David O'Rourke.

File Format

"TB_ARMOR_V1" '\n'
pass_hmac_key '\n'
pass_hmac_result '\n'
public_key '\n'
enc_privkey_spec '\n'
enc_sesskey_spec '\n'
data

Explanation of format

Each of the 5 "variables" (pass_hmac_key, pass_hmac_result, public_key, enc_privkey_spec, enc_sesskey_spec) is stored in Base64 format without linewraps (of course) and can be decoded with: Base64.decode(pass_hmac_key, Base64.NO_WRAP)

Then the user-supplied passphrase (String) can be verified as follows:

Mac mac = Mac.getInstance("HmacSHA1");
mac.init(new SecretKeySpec(pass_hmac_key, "HmacSHA1"));
byte[] sigBytes = mac.doFinal(passphrase.getBytes("UTF-8"));
boolean passphraseMatches = Arrays.equals(sigBytes, pass_hmac_result);

Then the passphrase is independently hashed with SHA-1. We append [twelve] 0x00 bytes to the 160-bit result to constitute the 256-bit AES key which is used to decrypt enc_privkey_spec (with an IV of [sixteen] 0x00 bytes). [Decrypt using AES-256 in CBC mode and perform PKCS7 unpadding with block size 16.]

Then we build the KeyPair object as follows:

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey2 = keyFactory.generatePrivate(
    new PKCS8EncodedKeySpec(privateKey)
);
PublicKey public_key2 = keyFactory.generatePublic(
    new X509EncodedKeySpec(public_key)
);
KeyPair keyPair = new KeyPair(public_key2, privateKey2);

Then we decrypt the session key as follows:

Cipher rsaDecrypt = Cipher.getInstance("RSA/NONE/PKCS1Padding");
rsaDecrypt.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(baos, rsaDecrypt);
cos.write(enc_sesskey_spec); cos.close();
byte[] sessionKey = baos.toByteArray();

And finally, we decrypt the data itself with the session key (which can be either a 128-bit, 192-bit or 256-bit key) and with a 0x00 IV. [Remember to PKCS7 unpad with block size 16].

While the "zero" IV is suboptimal from a security standpoint, it allows files to be encoded faster - because every little bit counts, especially when we store backups with LZO compression.


Author Tet Woo Lee
Created 2020-04-26
Copyright © 2020 Tet Woo Lee
License GPLv3
Dependencies pycryptodome, tested with v3.8.2

Change log

  • version 1.0.dev1 2020-04-26
    Working version

Metadata

Release files for pytibade 1.0.0.dev1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pytibade 1.0.0.dev1
File Size Uploaded Provenance Actions
pytibade-1.0.0.dev1.tar.gz 8.9 kB Without provenance Details for pytibade-1.0.0.dev1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pytibade 1.0.0.dev1
File Interpreter ABI Platform Actions
pytibade-1.0.0.dev1-py3-none-any.whl Python 3 none any Details for pytibade-1.0.0.dev1-py3-none-any.whl

Total release size: 21.3 kB

Release files / pytibade-1.0.0.dev1.tar.gz

Download URL pytibade-1.0.0.dev1.tar.gz
Size 8.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f548a0561889628401f88a05ef98fa151a2449688541717ce3ee53732c4d16cb
BLAKE2b-256 checksum
How to use checksums
af97237d286db3803f8e58c97f59242c754526adb2b4a3f2d1df7a5cb88dac02
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/46.1.3.post20200325 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.8.2

Release files / pytibade-1.0.0.dev1-py3-none-any.whl

Download URL pytibade-1.0.0.dev1-py3-none-any.whl
Size 12.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c74a894aedd954d73f5d6b19ac9d2999014a203400b680a2df52fc9de782f355
BLAKE2b-256 checksum
How to use checksums
d573d6b22d5f083587842f0f799019427090024e930b27aecf7f03a5af68e3da
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/46.1.3.post20200325 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.8.2

Security for pytibade 1.0.0.dev1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page