# Binary Artifact Analysis ## Tangem Android Wallet — Official Release APK vs. Build from Audited Source --- | | | |---|---| | **Subject** | Comparison of Tangem's official v6.1.2 release APK against a build produced from the audited source | | **Companion to** | [AUDIT.md](./AUDIT.md) — static source review of commit `358144ee61a` | | **Analysis date** | 17 August 2026 | | **Analysis type** | Static binary inspection (manifest, signing, package structure). No decompilation, no execution | | **Objective** | Determine whether the officially distributed binary can be confirmed to originate from the audited source | --- ## 1. Executive Summary **The official APK cannot be verified as originating from the audited source, and no available technique would allow it.** This is a structural property of how Tangem builds and hardens its release artifact, not a deficiency of this analysis or an indication of wrongdoing. What *can* be established is weaker but not worthless: every externally observable property of the official binary that could be compared against a build from the audited source **matches**. That rules out crude substitution or repackaging. It does not, and cannot, rule out a targeted modification concealed beneath the protection layer. The comparison additionally surfaced **two factual errors in AUDIT.md**, both of which overstate the security posture of the shipped application. They are recorded in §5 and have been corrected in the audit report. ### Verdict > **UNVERIFIABLE — CONSISTENT.** Provenance of the official binary cannot be established by any > means available to a third party. All comparable attributes are consistent with the audited > source. Absence of contradiction is not evidence of correspondence. --- ## 2. Artifacts Compared | | Official release | Build from audited source | |---|---|---| | Filename | `app-release-protected-1819-6.1.2.apk` | `app-google-debug.apk` | | Origin | `github.com/tangem/tangem-app-android` releases, tag `v6.1.2` | `./gradlew :app:assembleGoogleDebug` at `358144ee61a` | | Size | 134,544,995 bytes | 176,908,283 bytes | | SHA-256 | `6ed4ac317f2f5bdccd5bb1cec9d6733207261e6b4f823a4de883e646872166a1` | `5df4c81755bc423ed39e92499830d789b309561211c62091585fa9038adfe5cd` | | Package | `com.tangem.wallet` | `com.tangem.wallet.debug` | | Version | `6.1.2` (code `1819`) | `1.0.0-SNAPSHOT` (code `1`) | | Build type | `release`, minified, DexProtector-hardened | `debug`, unminified, unprotected | | Signer | `L=Zug, O=Tangem AG` | Committed dummy debug keystore | | Archive entry dates | 2026-08-13 | 2026-08-17 | The size difference is expected and runs counter to intuition: the debug build is *larger* because it is not minified by R8, despite carrying no protection layer. --- ## 3. Why Provenance Cannot Be Established Four independent obstacles apply. Any one alone would be sufficient to defeat verification. ### 3.1 The release is commercially hardened The official APK ships Licel DexProtector: ``` lib/arm64-v8a/libdexprotector.so 446,117 bytes lib/armeabi-v7a/libdexprotector.so 394,517 bytes assets/assets.dat 229,499 bytes assets/ict.dat 10,853 bytes ``` DexProtector encrypts and obfuscates DEX bytecode. The transformation is keyed per build and is explicitly designed to prevent the analysis that verification would require. Comparing bytecode between the two artifacts is not merely impractical — it is precluded by design. ### 3.2 The compared artifacts are different build types The official build passes through R8 minification, obfuscation, and resource shrinking. The reference build does not. Class names, method signatures, and the DEX file layout diverge for reasons entirely unrelated to source content: 54 DEX files versus 68. ### 3.3 The source tree does not correspond to the released version The repository carries **no version of its own**. `AppConfig.versionCode` is `1`, and `VersionNameProvider` derives the name from the current git branch, falling back to `1.0.0-SNAPSHOT`. Both values are injected by CI via `-PversionCode` / `-PversionName`. Consequently nothing in the tree identifies which release a given commit produced. The evidence indicates the audited commit is **newer** than v6.1.2: archive entries in the official APK are dated 2026-08-13, whereas the audited commits are dated 2026-08-14. The two artifacts therefore do not represent the same source state, and could not be expected to match even in principle. ### 3.4 The build is not reproducible by a third party Independent of the above, an outside party cannot reconstruct the official build: - `core/ui/ds-tokens` is a submodule gitlink with **no `.gitmodules` mapping anywhere in the repository's 16,087-commit history**, so it cannot be resolved (see AUDIT.md O-3) - All third-party API keys in `config_prod.json` are `PLACEHOLDER`; the official build embeds real values, compiled in at build time by `GenerateEnvironmentConfigTask` - Release signing requires a keystore that is deliberately not published Tangem publishes no reproducible-build attestation, and the artifact's construction is incompatible with one. --- ## 4. Consistency Findings The following were compared and **match**. Each is a property an attacker repackaging or substituting the application would find difficult to preserve. ### 4.1 Permission set — identical Both APKs declare **exactly 23 permissions**. After normalising the debug package prefix, a sorted diff of the two sets is **empty**. This is the most informative single result. The comparison was made against a binary built from the audited source, so any permission present in Tangem's distributed build but not produced by that source would be a direct indicator of divergence. There is none. Both sets also **exclude** location and microphone permissions, confirming that the `tools:node="remove"` stripping described in AUDIT.md §3.6 is genuine and survives into the shipped artifact. ### 4.2 Native libraries — identical, plus protection runtime | | Count | Detail | |---|---|---| | Build from audited source | 14 | see below | | Official release | 16 | the same 14, plus `libdexprotector.so` and `libalice.so` | ``` libTrustWalletCore.so · libsecp256k1-jni.so · libTrezorCrypto.so · libargon2.so libblst.so · libsqlcipher.so · libuniffi_yttrium.so · libtoolChecker.so libtensorflowlite_jni.so · libbarhopper_v3.so · libjnidispatch.so libimage_processing_util_jni.so · libandroidx.graphics.path.so · libsurface_util_jni.so ``` The audited source reproduces the official release's native library set exactly. The only additions are the protection layer. `libalice.so` was not independently identified; it appears only in the protected build alongside `libdexprotector.so`, which is consistent with it forming part of the DexProtector runtime, but this was not confirmed. ### 4.3 Build configuration and identity - `targetSdkVersion` 36 and `compileSdkVersion` 36 in both, matching the source configuration - Package `com.tangem.wallet` (reference build carries the expected `.debug` suffix) - Official APK signed by `L=Zug, O=Tangem AG`, certificate SHA-256 `e0fe798927cf94709b9d439c9ce728a90a2891698cdff31a4c4d63435b946748`, coherent with Tangem AG's registration in Zug, Switzerland **Note on the signing certificate:** this establishes only that the holder of that key signed the artifact. It is a first-observation baseline, not an identity proof. Its value is comparative — future releases can be checked against this digest to detect a signing-key change. --- ## 5. Discrepancies Against AUDIT.md Both findings below arise from the same root cause: the audit examined the **source tree**, and its conclusions were phrased as though they described the **shipped application**. Neither indicates malicious behaviour. Both have been corrected in AUDIT.md. ### D-1 — Permission set understated (AUDIT.md §3.6) The audit lists nine permissions as the "complete permission set across all manifests" and states that external storage and `RECEIVE_BOOT_COMPLETED` are **absent**. The nine are accurate for the hand-written manifests (`app/src/main/` and `app/src/huawei/`), which were verified to declare exactly that set. However the **merged** manifest — in Tangem's release and in the build from the audited source alike — contains 23. The fourteen not accounted for: ``` READ_EXTERNAL_STORAGE · WRITE_EXTERNAL_STORAGE · WRITE_SETTINGS RECEIVE_BOOT_COMPLETED · FOREGROUND_SERVICE · USE_FINGERPRINT · POST_NOTIFICATIONS BIND_GET_INSTALL_REFERRER_SERVICE · ACCESS_ADSERVICES_ATTRIBUTION ACCESS_ADSERVICES_AD_ID · c2dm.RECEIVE · DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION com.samsung.android.mapsagent.permission.READ_APP_INFO com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA ``` These are introduced by manifest merging from bundled third-party SDKs — the same mechanism the audit correctly credits Tangem for defending against with `tools:node="remove"`. The characterisation "permissions MINIMISED" and "the set contains nothing a wallet does not require" is not supported by the artifact as shipped. `WRITE_SETTINGS` and `RECEIVE_BOOT_COMPLETED` in particular warrant explanation rather than omission. ### D-2 — "No native code" is true of the repository, false of the application (AUDIT.md §3.1) The audit states "No `.so` libraries, no JNI, no NDK build inputs," and answers **No** to the methodology question *"Does it ship native binaries or opaque blobs?"* This is correct for the source tree — no `.so` file is committed. It is incorrect for the application, which bundles fourteen native libraries even in the unprotected build (§4.2). The distinction is material because several are security-critical: `libTrustWalletCore.so`, `libsecp256k1-jni.so`, and `libTrezorCrypto.so` perform key derivation and signing; `libargon2.so` provides key-stretching; `libsqlcipher.so` provides at-rest database encryption. These arrive through the pre-built Maven dependencies that AUDIT.md §6.1 places outside the review's scope, so the audit's scope statement does technically cover them. But a reader reaching "ships native binaries: **No**" in the summary table will draw the opposite conclusion about the application they are installing. --- ## 6. What This Analysis Does and Does Not Establish **Does establish:** - The official v6.1.2 APK is signed by Tangem AG and structured as the audited source predicts - Its permission surface and native library set are exactly reproduced by building the audited source, with no unexplained additions - Gross tampering — repackaging, permission injection, substitution of a different application — is ruled out - The privacy hardening claimed in AUDIT.md §3.6 is present in the distributed artifact **Does not establish:** - That the official APK was built from the audited source, or from any particular source - That the DEX bytecode is free of modification. DexProtector renders this unexaminable - Anything about the pre-built Tangem SDKs, which perform mnemonic encryption and at-rest key storage and remain unreviewed (AUDIT.md §6.1) - That any *future* release will share these properties A user installing the official APK is extending trust to Tangem's build pipeline and signing key. Nothing available to a third party can substitute for that trust. This analysis narrows the range of undetected substitutions; it does not eliminate it. --- ## 7. Method All inspection used Android SDK build-tools 36.0.0. ```bash # Manifest, version, permissions aapt2 dump badging # Signing certificate apksigner verify --print-certs # Package structure, native libraries, DEX count unzip -l ``` Permission sets were extracted, normalised for the debug package prefix, sorted, and compared with `diff`. Native library sets were compared with `comm` after stripping ABI directory components. No decompilation, deobfuscation, or execution was performed. No attempt was made to defeat DexProtector. --- ## 8. Limitations 1. **Static inspection of archive metadata only.** Application behaviour was not observed. 2. **Version mismatch.** The reference build derives from a commit dated one day after the official artifact. Differences attributable to intervening source changes cannot be distinguished from differences attributable to anything else. 3. **Reference build was not fully faithful.** It was produced with `verifyDesignTokens` skipped (the `ds-tokens` submodule is unresolvable) and with `PLACEHOLDER` API keys. Neither affects the manifest or native library comparisons on which the findings rest. 4. **Single point in time.** Applies to v6.1.2 build 1819 only. Re-verification is required for every subsequent release, and the certificate digest in §4.3 is the recommended anchor. --- *Binary analysis of `app-release-protected-1819-6.1.2.apk` against a reference build of commit `358144ee61a`. Companion to AUDIT.md; findings D-1 and D-2 have been applied to that report.*