Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Please provide build instructions for reproducing the apk from Google Play #7

Open
Giszmo opened this issue May 3, 2021 · 7 comments

Comments

@Giszmo
Copy link

Giszmo commented May 3, 2021

I tried to reproduce the app I got from Google Play to make sure it matches the published source code but failed. My findings will be public on WalletScrutiny. The short version of the analysis is:

After running

mkir /tmp/testbitcoinorg
cd /tmp/testbitcoinorg
podman run --rm --volume $PWD:/app --interactive --tty frolvlad/alpine-glibc
apk update
apk add --no-cache openjdk8 git yarn
export ANDROID_SDK_ROOT="/home/appuser/app/sdk"
export ANDROID_HOME="/home/appuser/app/sdk"
export NODE_ENV="production"
mkdir -p "/home/appuser/app/sdk/licenses" "/home/appuser/app/bitcoinorg/"
printf "\n24333f8a63b6825ea9c5514f83c2829b004d1fee" > "/home/appuser/app/sdk/licenses/android-sdk-license"
cd /app
git clone https://github.com/bitcoin-dot-org/BitcoinWalletMobile/
cd BitcoinWalletMobile
git checkout v1.0
yarn install --frozen-lockfile --production
cd android
sed -i '/org.gradle.jvmargs/s/^#//g' gradle.properties
./gradlew assembleRelease
./gradlew bundleRelease
cp app/build/outputs/apk/release/app-release.apk .

The diff with what I get from Google Play is huge:

$ unzip /path/to/Bitcoin\ Wallet\ 1.0\ \(org.bitcoin.wallet\).apk -d fromGoogle
$ unzip BitcoinWalletMobile/android/app-release.apk -d fromBuild
$ diff --recursive --brief from*
Files fromBuild/AndroidManifest.xml and fromGoogle/AndroidManifest.xml differ
Only in fromGoogle/assets: index.android.bundle
Only in fromBuild: lib
Only in fromGoogle/META-INF: BNDLTOOL.RSA
Only in fromGoogle/META-INF: BNDLTOOL.SF
Only in fromBuild/META-INF: CERT.RSA
Only in fromBuild/META-INF: CERT.SF
Files fromBuild/META-INF/MANIFEST.MF and fromGoogle/META-INF/MANIFEST.MF differ
Only in fromBuild/res: drawable-anydpi-v21
Only in fromBuild/res: drawable-hdpi-v4
Files fromBuild/res/drawable-ldpi-v4/ic_launcher_foreground.png and fromGoogle/res/drawable-ldpi-v4/ic_launcher_foreground.png differ
Only in fromBuild/res: drawable-ldrtl-hdpi-v17
Only in fromBuild/res/drawable-ldrtl-mdpi-v17: abc_spinner_mtrl_am_alpha.9.png
Only in fromBuild/res: drawable-ldrtl-xhdpi-v17
Only in fromBuild/res: drawable-ldrtl-xxhdpi-v17
Only in fromBuild/res: drawable-ldrtl-xxxhdpi-v17
Only in fromBuild/res/drawable-mdpi-v4: abc_btn_check_to_on_mtrl_000.png
Only in fromBuild/res/drawable-mdpi-v4: abc_btn_check_to_on_mtrl_015.png
Only in fromBuild/res/drawable-mdpi-v4: abc_btn_radio_to_on_mtrl_000.png
Only in fromBuild/res/drawable-mdpi-v4: abc_btn_radio_to_on_mtrl_015.png
Only in fromBuild/res/drawable-mdpi-v4: abc_cab_background_top_mtrl_alpha.9.png
Only in fromBuild/res/drawable-mdpi-v4: abc_ic_star_black_48dp.png
Only in fromBuild/res/drawable-mdpi-v4: abc_ic_star_half_black_48dp.png
Only in fromBuild/res/drawable-mdpi-v4: abc_list_pressed_holo_dark.9.png
Only in fromBuild/res/drawable-mdpi-v4: abc_list_selector_disabled_holo_dark.9.png
Only in fromBuild/res/drawable-mdpi-v4: abc_popup_background_mtrl_mult.9.png
Only in fromBuild/res/drawable-mdpi-v4: abc_scrubber_control_off_mtrl_alpha.png
Only in fromBuild/res/drawable-mdpi-v4: abc_scrubber_control_to_pressed_mtrl_000.png
Only in fromBuild/res/drawable-mdpi-v4: abc_scrubber_control_to_pressed_mtrl_005.png
Only in fromBuild/res/drawable-mdpi-v4: abc_scrubber_primary_mtrl_alpha.9.png
Only in fromBuild/res/drawable-mdpi-v4: abc_scrubber_track_mtrl_alpha.9.png
Only in fromBuild/res/drawable-mdpi-v4: abc_spinner_mtrl_am_alpha.9.png
Only in fromBuild/res/drawable-mdpi-v4: abc_tab_indicator_mtrl_alpha.9.png
Only in fromBuild/res/drawable-mdpi-v4: abc_text_select_handle_left_mtrl_dark.png
Only in fromBuild/res/drawable-mdpi-v4: abc_text_select_handle_left_mtrl_light.png
Only in fromBuild/res/drawable-mdpi-v4: abc_text_select_handle_middle_mtrl_dark.png
Only in fromBuild/res/drawable-mdpi-v4: abc_text_select_handle_middle_mtrl_light.png
Only in fromBuild/res/drawable-mdpi-v4: abc_text_select_handle_right_mtrl_dark.png
Only in fromBuild/res/drawable-mdpi-v4: abc_text_select_handle_right_mtrl_light.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_arrow.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_camera.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_collectionfocus.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_collection.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_copy.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_create.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_currency.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_do_not_loose_it.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_exit.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_eye.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_forward.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_gearfocus.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_gear.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_keep_it_safe.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_language.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_laptop.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_link.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_qrcodeicon.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_receivedbutton.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_receivefocus.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_receive.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_refresh.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_restore.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_sendbutton.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_send.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_sent.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_swap.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_tick.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_warning.png
Only in fromBuild/res/drawable-mdpi-v4: assets_images_write_it_down.png
Only in fromBuild/res/drawable-mdpi-v4: common_google_signin_btn_icon_dark_normal_background.9.png
Only in fromBuild/res/drawable-mdpi-v4: common_google_signin_btn_icon_light_normal_background.9.png
Only in fromBuild/res/drawable-mdpi-v4: common_google_signin_btn_text_dark_normal_background.9.png
Only in fromBuild/res/drawable-mdpi-v4: common_google_signin_btn_text_light_normal_background.9.png
Only in fromBuild/res/drawable-mdpi-v4: design_ic_visibility_off.png
Only in fromBuild/res/drawable-mdpi-v4: design_ic_visibility.png
Only in fromBuild/res/drawable-mdpi-v4: googleg_disabled_color_18.png
Only in fromBuild/res/drawable-mdpi-v4: googleg_standard_color_18.png
Only in fromBuild/res/drawable-mdpi-v4: ic_launcher_foreground.png
Only in fromBuild/res/drawable-mdpi-v4: node_modules_reactnavigation_stack_src_views_assets_backicon.png
Only in fromBuild/res/drawable-mdpi-v4: notification_bg_low_normal.9.png
Only in fromBuild/res/drawable-mdpi-v4: notification_bg_low_pressed.9.png
Only in fromBuild/res/drawable-mdpi-v4: notification_bg_normal.9.png
Only in fromBuild/res/drawable-mdpi-v4: notification_bg_normal_pressed.9.png
Only in fromBuild/res/drawable-mdpi-v4: notify_panel_notification_icon_bg.png
Only in fromBuild/res: drawable-xhdpi-v4
Only in fromBuild/res: drawable-xxhdpi-v4
Only in fromBuild/res: drawable-xxxhdpi-v4
Only in fromGoogle/res/xml: splits0.xml
Files fromBuild/resources.arsc and fromGoogle/resources.arsc differ
Only in fromGoogle: stamp-cert-sha256

The diff ignoring what was only in my build and not in the Google version and the META-INF lines is still huge, with index.android.bundle being obfuscated (minified) code.

$ diff --recursive --brief from* | grep -v "$Only in fromBuild" | grep -v META-INF
Files fromBuild/AndroidManifest.xml and fromGoogle/AndroidManifest.xml differ
Only in fromGoogle/assets: index.android.bundle
Files fromBuild/res/drawable-ldpi-v4/ic_launcher_foreground.png and fromGoogle/res/drawable-ldpi-v4/ic_launcher_foreground.png differ
Only in fromGoogle/res/xml: splits0.xml
Files fromBuild/resources.arsc and fromGoogle/resources.arsc differ
Only in fromGoogle: stamp-cert-sha256
@emanuelb
Copy link

emanuelb commented May 3, 2021

it's INCORRECT to compare apk generated from ./gradlew assembleRelease to apk downloaded from google-play if appbundle is used, in such case a apk generated with bundletool from the aab file generated by ./gradlew bundleRelease need to be done.

steps are (all commands to run in the Containerfile I written in: https://gitlab.com/walletscrutiny/walletScrutinyCom/-/issues/208):

  1. download bundletool latest release (currently it's 1.6.0):
cd /home/appuser/app/sdk/; \
wget https://github.com/google/bundletool/releases/download/1.6.0/bundletool-all-1.6.0.jar; \
echo "fdabaa9137dd9d346a3571d010ee4404a4bae3f1641ebe2236ed4b74ee73bf6f  bundletool-all-1.6.0.jar" | sha256sum -c;
  1. Build universal apk (this is done to compare against published apks which built this way, some providers do for apk uploaded to github, which is aked in issue Use github releases and publish .apk & .ipa files in them #8)
cd /home/appuser/app/bitcoinorg; \
java -jar /home/appuser/app/sdk/bundletool-all-1.6.0.jar build-apks --bundle=/home/appuser/app/bitcoinorg/BitcoinWalletMobile/android/app/build/outputs/bundle/release/app-release.aab --mode=universal --output=/home/appuser/app/bitcoinorg/bitcoinorg-universal.apks; \
unzip /home/appuser/app/bitcoinorg/bitcoinorg-universal.apks

The universal apk will be located at: /home/appuser/app/bitcoinorg/universal.apk

  1. Build matched apk to compare against apk downloaded from google-play
cd /home/appuser/app/bitcoinorg;
java -jar /home/appuser/app/sdk/bundletool-all-1.6.0.jar build-apks --bundle=/home/appuser/app/bitcoinorg/BitcoinWalletMobile/android/app/build/outputs/bundle/release/app-release.aab --output=/home/appuser/app/bitcoinorg/bitcoinorg-all.apks; \

Which will generate bitcoinorg-all.apks file, using it in below command bundletool extract-apks with matched --device-spec argument to the device used to download apk from google-play is needed.

For example, Create file /home/appuser/app/sdk/pixel2.json with content:

{
  "supportedAbis": ["arm64-v8a", "armeabi-v7a", "armeabi"],
  "supportedLocales": ["en-US"],
  "screenDensity": 560,
  "sdkVersion": 30
}

Then run:

java -jar /home/appuser/app/sdk/bundletool-all-1.6.0.jar extract-apks --apks=/home/appuser/app/bitcoinorg/bitcoinorg-all.apks --output-dir=/home/appuser/app/bitcoinorg/bitcoinorg-pixel2-apks --device-spec=/home/appuser/app/sdk/pixel2.json

which will generate apks in directory /home/appuser/app/bitcoinorg/bitcoinorg-pixel2-apks that should be compared to what downloaded from google-play.

This are the steps to create apk that is matched to what downloaded from google-play when appbundles are used, unfortunately while writing this the google-play url return "We're sorry, the requested URL was not found on this server.", opened issue about it in: #9

if you have apk downloaded from google-play, create the apk from appbundle as described above (The json file need to match the spec used to download app from google-play) and publish the results.

@Cobra-Bitcoin
Copy link
Contributor

Thanks for looking at the wallet. Please keep in mind for now that the only reason the wallet was on the app store was to monitor and test live usage patterns. It's not actually fully "released" as I'm not 100% confident about pushing users towards it.

@emanuelb: Good catch on figuring out how to get a reproducible build. I'm going to use your response as a template for general build instructions on how to reproduce.

@Giszmo
Copy link
Author

Giszmo commented May 4, 2021

@emanuelb what's it with the "INCORRECT"? Absent build instructions, it's as correct as any other attempt at building this app, so please don't shout at me.

Reproducible builds make little sense when there is a custom build for every user or even only a huge combinatory variety of possible builds. The approach can't be to build them all. At WalletScrutiny we attest that app X with version Y and hash Z is indeed built from the source but that's really only helpful for users of the app with hash Z. All the others might have a rogue app.

@Cobra-Bitcoin please provide build instructions for reproducibility. Given an apk, how can I reproduce it from the code here?

@Giszmo
Copy link
Author

Giszmo commented May 4, 2021

@emanuelb in other words, if somebody shares his apk with me, I cannot reproduce the apk without knowing how he got it from Google Play? That's pretty sick. (I'll further investigate this part, too.)

@emanuelb
Copy link

emanuelb commented May 4, 2021

That's how appbundle works, not sure there is a way for provider to turn them off when it's was enabled on google-play, also google is pushing hard for appbundles (might be mandatory for new apps), appbundle & splitting is fine (except the part where signing keys are uploaded to google, this part is very bad... shame on google for adding this additonal not-needed evil requirement...)

My intent is not to shout, I wrote in related gitlab issue that the missing step for verification is appbundle compare, probably wasn't clear enough about it... was planning to test it myself after they fixed the other issues I reported (or some of them) and publish newer version, anyway the instructions are in my previous comment here...

reproducible-builds makes lots of sense for appbundle as well, they just require different verification routine:

  1. either downloading the bundle (aab file) from google-play if possible
  2. testing 1 apk with device-spec and mention it in the review.
  3. (optional) verify more apks by downloading with script that change device-id/spec, for example like visiting https://apk.support/download-app/org.bitcoin.wallet and choosing other config, not "default"-"default".

if the app on google-play use appbundles, using bundletool to create the apk with device-spec that match what was used to download the apk is needed... that's how it's work... comparing it to universal apk (created from appbundle or by assembleRelease) is incorrect and will show diffs in XML files & missing files, etc... it's wrong comparison...

When appbundle is enabled on google-play, different devices will receive different APK depending on several factors like screen size, the arch of the device, etc...

Even if app don't use appbundles, the fact that you verified 1 apk doesn't mean another user will receive it, vendor can send another apk on google-play for other android versions, or for users in other countries etc... so enumeration is still needed for coverage, for full coverage "binary transparency" is needed.

The first step in verification is to ensure reproducible-builds is possible for 1 tested apk, increasing coverage is other issue (will require downloading more apks...)

I would have showed end-to-end diff/diffoscope for this app, but I can't download it as google-play return 404 (was removed temporary)
The bitcoin paper-wallet is using appbundle: https://github.com/ValleZ/Paper-Wallet/ will test it later & publish the results in the related issue in the repo...

@Giszmo
Copy link
Author

Giszmo commented May 4, 2021

That's how appbundle works, not sure there is a way for provider to turn them off when it's was enabled on google-play,

It's impossible to opt out after opting in.

also google is pushing hard for appbundles (might be mandatory for new apps),

Not yet but I agree it's likely to happen.

The rest of your comment is more for the WalletScrutiny issue tracker than for here. We knew AAB is coming. You consider it to be on us to figure out. I consider it on the provider to figure it out as he can't really make any guarantees about an app if he can't reproduce stuff neither but the provider probably has access to the app bundle which the end user almost certainly does not.

@emanuelb
Copy link

emanuelb commented May 4, 2021

The provider can upload .aab file in github releases, some of them do, I consider it useless as it's not helpful for users (as .aab installation not possible on device directly) and require first to extract apk from it using bundletool build-apks or installing with bundletool install-apks commands.

for reproducible-builds downloading .aab file it's not needed either, as published universal-apk built from it is useful to users and can be verified by creating it the same way (aab -> bundletool --mode=universal -> unzip > verify "universal.apk")

for testing apk downloaded from google-play, same device-spec should be used (for downloading, and in bundletool)

so I see no reason to publish .aab in github releases, publishing .ipa is useful as it's like .apk & the apple server-side mechanism which is like bundletool is not open-source and even available... so knowing what's the provider uploaded is useful to compare against.

It make sense and should be done for the provider to reproduce .aab on different environments before uploading it to google-play

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants