androidgradlegoogle-playqt-creatorandroid-app-signing

A file not protected by signature. Unauthorized modifications to this JAR entry will not be detected


I get the following messages while signing my Android app package:

Signing file D:/dev/repos/examples/src/MyApp/build-MyAppQt-Android_Qt_6_6_0_arm64_v8a_release_Clang_arm64_v8a-Release/android-build//build/outputs/bundle/release/android-build-release.aab
Verifies
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true
Verified using v3 scheme (APK Signature Scheme v3): true
Verified using v3.1 scheme (APK Signature Scheme v3.1): false
Verified using v4 scheme (APK Signature Scheme v4): false
Verified for SourceStamp: false
Number of signers: 1
WARNING: META-INF/com/android/build/gradle/app-metadata.properties not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.activity_activity.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.annotation_annotation-experimental.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.appcompat_appcompat-resources.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.appcompat_appcompat.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.arch.core_core-runtime.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.browser_browser.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.core_core-ktx.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.core_core.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.cursoradapter_cursoradapter.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.customview_customview.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.datastore_datastore.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.drawerlayout_drawerlayout.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.fragment_fragment.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.interpolator_interpolator.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.lifecycle_lifecycle-livedata-core.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.lifecycle_lifecycle-livedata.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.lifecycle_lifecycle-runtime.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.lifecycle_lifecycle-service.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.lifecycle_lifecycle-viewmodel.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.loader_loader.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.privacysandbox.ads_ads-adservices-java.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.privacysandbox.ads_ads-adservices.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.recyclerview_recyclerview.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.room_room-runtime.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.savedstate_savedstate.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.sqlite_sqlite-framework.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.sqlite_sqlite.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.startup_startup-runtime.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.tracing_tracing.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.transition_transition.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.vectordrawable_vectordrawable-animated.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.vectordrawable_vectordrawable.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.versionedparcelable_versionedparcelable.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.viewpager2_viewpager2.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.viewpager_viewpager.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/androidx.work_work-runtime.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/com.google.dagger_dagger.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
WARNING: META-INF/kotlinx_coroutines_core.version not protected by signature. Unauthorized modifications to this JAR entry will not be detected. Delete or move the entry outside of META-INF/.
Android package built successfully in 97.909 ms.
-- File: D:/dev/repos/examples/src/MyApp/build-MyAppQt-Android_Qt_6_6_0_arm64_v8a_release_Clang_arm64_v8a-Release/android-build//build/outputs/apk/release/android-build-release-signed.apk

Is it safe to ignore them and publish the app on Google Play?

Why aren't this files signed?

My build.gradle:

buildscript {
    ext.kotlin_version = '1.8.0'
    repositories {
        google()
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.4.1'
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
    }
}

repositories {
    google()
    mavenCentral()
}

apply plugin: 'com.android.application'

dependencies {
    // implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
    implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
    implementation 'com.yandex.android:mobileads:6.2.0'
    implementation 'com.yandex.ads.mediation:mobileads-google:22.4.0.0'
    // implementation 'com.google.android.gms:play-services-ads:21.5.0'
    implementation "com.android.billingclient:billing:6.0.1"
    // From the template
    implementation 'androidx.core:core:1.10.1'
}

android {
    /*******************************************************
    * The following variables:
    * - androidBuildToolsVersion,
    * - androidCompileSdkVersion
    * - qtAndroidDir - holds the path to qt android files
    *                   needed to build any Qt application
    *                   on Android.
    *
    * are defined in gradle.properties file. This file is
    * updated by QtCreator and androiddeployqt tools.
    * Changing them manually might break the compilation!
    *******************************************************/

    //androiddeployqt.exe fails without package attribute in the mainifest.
    //namespace 'net.geographx.LinesGame'
    compileSdkVersion androidCompileSdkVersion.toInteger()
    buildToolsVersion androidBuildToolsVersion
    ndkVersion androidNdkVersion

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = [qtAndroidDir + '/src', 'src', 'yandex-ad-src', 'java']
            aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl']
            res.srcDirs = [qtAndroidDir + '/res', 'res']
            resources.srcDirs = ['resources']
            renderscript.srcDirs = ['src']
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
    }
    }

    tasks.withType(JavaCompile) {
        options.incremental = true
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    // From the template
    // Extract native libraries from the APK
    packagingOptions.jniLibs.useLegacyPackaging true

    lintOptions {
        abortOnError false
    }

    // Do not compress Qt binary resources file
    aaptOptions {
        noCompress 'rcc'
    }

    defaultConfig {
        minSdkVersion qtMinSdkVersion
        targetSdkVersion qtTargetSdkVersion
        ndk.abiFilters = qtTargetAbiList.split(",")
        //For debug builds native-debug-symbols.zip size is 432MB.
        //Use SYMBOL_TABLE to upload debug builds.
        ndk.debugSymbolLevel "FULL"
    }

    //The build type becomes release when we sign the bundle,
    //otherwize the build type is debug with both Debug and RelWithDebInfo.
    //With SYMBOL_TABLE we have .sym in native-debug-symbols.zip and
    //with FULL we have .dbg.
    /*
    buildTypes {
        release {
            //Full debug for uploading production and beta builds.
            ndk.debugSymbolLevel "FULL"
        }

        debug {
            //Small debug info for uploading internal testing builds.
            ndk.debugSymbolLevel "SYMBOL_TABLE"
        }
    }
    */
}

I am not sure what is exact signing command because QT creator does not show it in build logs.


Solution

  • Summary

    The warning you have encountered only applies to the APK signature v1, but as the APK file contains also a v2 and v3 signature you can safely ignore this message as every modification on the APK file can be detected by the newer signature schemes.

    However even if the signature can be verified it does not mean that the APK file is genuine. It still could be resigned after modification, therefore you should carefully compare the certificate digests (shown when verifying it using apksigner verify --verbose --print-certs) of the APK to be verified and compare it to other APK files of the same app developer. See this answer of How can I verify the authenticity of an APK file I downloaded? for details how to compare the certificate digest of an APK.

    Detailed explanation

    First of all as you can see what you get is a WARNING not an ERROR. If relevant file(s) of the APK file would have been modified the verification would fail and you would get an ERROR message.

    To understand the warning message you need a little understanding of Java and how Java signatures (APK signature v1) work. This old signature is stored inside the JAR in two files: META-INF/CERT.SF and META-INF/CERT.RSA. Of course a signature can not sign the files it is written into , hence those files are excluded by the signature.

    Additionally the META-INF directory is location of the MANIFEST.MF - a file that is only relevant for Java on Desktop but not used by Android at all.

    There can be additional files in the META-INF directory, considering the standard Java directory layout no code should be stored inside files within the META-INF directory.

    Because of all this Sun as the original inventor of Java decided to exclude the META-INF directory from the Java code signature at all. Several years later Google just used the Java signature for APK files which is now known as APK signature v1.

    Therefore for the APK signature v1 the files inside the META-INF directory are not covered by the signature and hence can be modified without being recognized if you only verify

    Because of several attacks on the APK signature itself (such as including the same file multiple times with different content in the APK Google decided to develop a completely new APK signature that does not apply on the APK content but on the overall APK file itself. This was the beginning of APK signature v2 and it's successors.

    These new APK signature schemes do sign the complete APK content at once, not excluding a single file that is stored inside the APK file.

    Back to ypur APK. You have posted the apksigner output:

    Signing file D:/dev/repos/examples/src/MyApp/build-MyAppQt-Android_Qt_6_6_0_arm64_v8a_release_Clang_arm64_v8a-Release/android-build//build/outputs/bundle/release/android-build-release.aab
    Verifies
    Verified using v1 scheme (JAR signing): true
    Verified using v2 scheme (APK Signature Scheme v2): true
    Verified using v3 scheme (APK Signature Scheme v3): true
    Verified using v3.1 scheme (APK Signature Scheme v3.1): false
    Verified using v4 scheme (APK Signature Scheme v4): false
    Verified for SourceStamp: false
    Number of signers: 1
    ...
    

    As you can see the APK file is signed not only by an v1 signature but also a v2 and v3 signature. This means that the WARNING only applies to the signature created by the v1 scheme. You can easily verify that by modifying a single character inside a file that is located in the META-INF directory. Those files are usually stored uncompressed within the APK file. You can simple open the APK file in an hex editor, modify a character in the section that belongs to that file (it is the first ZIP entry within the APK) and then again verify the APK. You will get something like this:

    java -jar apksigner.jar verify --verbose "modified_android-build-release.aab"
    DOES NOT VERIFY
    ERROR: APK Signature Scheme v3 signer #1: APK integrity check failed. CHUNKED_SHA256 digest mismatch. Expected: <ac8a15569352655a22f13d3c565c2c0e5c62dc70c8f6f8c10f6fbfa63decb19b>, actual: <aa5622cd904500c38424562ef4b5be9e5716d10a85985a41f35e4ed834cee8fe>
    ERROR: APK Signature Scheme v3 signer #1: APK integrity check failed. VERITY_CHUNKED_SHA256 digest mismatch. Expected: <56eeebd545733fd6408cd6a30b8bcf98a557076167902b6d9502b5aca86b78e89b42220000000000>, actual: <c37e1e1436cfd62f89592c48211ffb6ad2f1dff0f69d2203072f1e6c3872a5919b42220000000000>
    

    As you can see now the APK signature is considered invalid. The complete APK signature verification system is documented by Google e.g. here: Google Android APK signature v3.0 Verification Scheme

    From my understanding all signatures except v1 should fail on the modified APK file. So if you would check the APK using old jarsigner from JDK it will pass the verification test.