feat(bundle): App Bundle (AAB) bundle-mode integrity + relicense to CC BY-ND 4.0 - #5
Merged
Conversation
Adds two v3 fields to both the plugin and runtime Fingerprint data class (bundleMode: Boolean, bundleEntryHashes: Map<String,String>) and wires them into the binary codec. v1/v2 blobs remain decodable; MIN_SUPPORTED_FORMAT_VERSION stays at 1. Includes three round-trip JUnit 5 tests (TDD: RED → GREEN).
…tryDecompressedHash
…ompressed
I-1: Replace single-shot vector inflate + one-shot sha256 with fixed 64 KiB
output buffer streaming inflate loop + incremental Sha256Ctx (init/update/final)
added to sha256.{h,cpp}; existing one-shot sha256() routed through it.
Peak memory O(64 KiB) independent of entry size. inflateEnd called on every path.
I-2: Reject comp > kMaxInflateBytes before handing to zlib (symmetric with
existing uncomp cap).
M-2: Explicit body_off narrowing guard — reject if body_off > apk.size() or
body_off + comp > apk.size() before any size_t cast, preventing silent 32-bit
truncation on armeabi-v7a.
M-1: Post-inflateEnd total_out read dropped; completeness tracked via
accumulated total_inflated inside the loop.
M-3: New test6 — valid-shaped DEFLATED ZIP entry with garbage body bytes;
asserts hash_entry_decompressed returns false and does not crash.
…+ decompressed entry diff
…nify signer-mismatch detail keys
…, guards, temp cleanup, const T1: replace inline FQCNs in DeviceIntelligenceExtension with proper imports. T2a: add rawV2BlobDecodesWithNoBundleFields test proving formatVersion>=3 guard handles real v2 blobs. T2b: add readNonNegative guard for bundleEntryCount in plugin FingerprintCodec v3 decode block. T3a: add key.size==32 require in BundleFingerprintBuilder.build (symmetric with task-level check). T3b: wrap AabSigner sign+rename in try/catch to delete stale temp on failure. T4b: promote BUNDLE_ASSET_PATH to const val with literal value; drop unused Fingerprint import.
…pk_entry_removed Play delivers only the device-ABI config split; other ABIs baked into the fingerprint are legitimately absent and must not emit apk_entry_removed. A present-but-patched .so still fires apk_entry_modified (tamper detection preserved). Non-ABI entries (e.g. classes*.dex) continue to flag removal.
Replace Apache-2.0 with Creative Commons Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0), matching the hydra project. Updates LICENSE, the README badge + license section, and the Maven POM license metadata in both the library and Gradle-plugin modules.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
App Bundle (AAB) bundle-mode integrity
Adds a parallel bundle-mode integrity path so the build-baked tamper detection works when an app ships as an Android App Bundle through Google Play. Previously the integrity layer was APK-only: an AAB build never injected the fingerprint, pinned the upload key (Play re-signs with the app-signing key), and hashed compressed bytes (Play re-encodes) — so it silently broke / false-positived under Play delivery.
How it works
deviceIntelligence { appBundle { enabled = true; playSigningCertSha256("AB:CD:…") } }(opt-in; default off — APK consumers unaffected).bundleMode+bundleEntryHashes;MIN_SUPPORTED_FORMAT_VERSIONstays 1, so v1/v2 blobs still decode and the APK path is byte-for-byte unchanged.BundleIntegrityTask(wired toSingleArtifact.BUNDLE) bakes the fingerprint into the.aaband re-signs it (JDKJarSigner; no bundletool dependency).classes*.dex+lib/<abi>/*.so(stable across Play's re-encode), keyed by installed-entry name.hash_entry_decompressed) + aapkEntryDecompressedHashJNI — bounds-checked, fail-closed, 64 KiB peak memory.base.apk + splitSourceDirs; mismatch →apk_entry_modified(CRITICAL), dex absent →apk_entry_removed(HIGH). An absent ABI-split.sois treated as conditionally-delivered (not flagged).Validation
AabHashernormalization + decompressed-hash,BundleFingerprintBuilderencrypt/decrypt, a native host C++ suite (STORED/DEFLATED/garbage), and the runtime decision logic (membership + modified/removed/skip).bundletoolsplit delivery —base.apk+split_config.arm64_v8a.apk): a clean install reportsintegrity.apkok with zero false positives; a tampered device.sois caught asapk_entry_modifiedCRITICAL.Also in this PR
Spec + plan under
docs/superpowers/.