17

I'm currently developing a .AAR android library and I would like to sign the released artifacts with my own key, so that I can determine if a fake aar with the same name and functionality has been released by mine or not.

Notice 1 :

I want to be able to check the authenticity of my library programmatically, even if a fakely-cooked one, is forging just part of the functionality of my aar file.

Notice 2 :

I am not going to publish this aar into maven, sonatype or any other public repository. So I'm going to sign it for a typical release flow like signing an apk file.

Farhad
  • 12,178
  • 5
  • 32
  • 60
  • "so that I can determine if a fake aar with the same name and functionality has been released by mine or not" -- but if you are not distributing the AAR, how would they ever get it to make a fake one? – CommonsWare Apr 03 '17 at 23:23
  • @CommonsWare we are publishing this library to some of our business partners and they are going to integrate it in their apps and publish them to public markets. – Farhad Apr 04 '17 at 06:32
  • @FarhadFaghihi , Have you find the answer for your question? I'm also trying to achieve the same in my AAR library.I can sign my AAR with Jar signer but how to check integrity of the AAR during runtime? – MohanRaj Feb 26 '20 at 10:07

5 Answers5

27

You can use jarsigner to sign you aar library, and you can use keytool to generate the signing keys. Both tools are located in the embedded JDK that comes with Android Studio. Do the following to sign your library.

Signing

Generate a keystore with a key pair. You'll need to provide the certificate fields:

keytool -genkeypair -alias aarsign -keypass mypassword -keystore aarsign.keystore -storepass mypassword -v

Export the generated certificate into a PEM file:

keytool -exportcert -rfc -alias aarsign -file aarsign-public.pem -keystore aarsign.keystore -storepass mypassword -v

Create a keystore containing the certificate:

keytool -importcert -alias aarsign -file aarsign-public.pem -keystore aarsign-public.keystore -storepass mypassword -v

Sign the library:

jarsigner -keystore aarsign.keystore -storepass mypassword -keypass mypassword -signedjar lib-signed.aar -verbose lib.aar aarsign

Verifying

Anyone who wishes to attest the authenticity of the library needs to obtain your certificate (or the keystore with it) in a reliable way, and enter this command:

jarsigner -keystore aarsign-public.keystore -storepass mypassword -verify -verbose -certs lib-signed.aar aarsign

It will give the message

jar verified.

with some warnings about certificate expiration and signature timestamp. You can get rid of these warnings by creating a stricter certificate. Refer to keytool and jarsigner documentation.

There are two ways in which you can find out whether your library has been tampered: unmatching digests or unmatching certificate. If someone generates an aar from a different source code or with different resources, the digest won't match and jarsigner will warn, for example:

jarsigner: java.lang.SecurityException: invalid SHA-256 signature file digest for <file>

And, if someone provides a different certificate than your own, jarsigner will warn:

Warning: 
This jar contains entries whose certificate chain is not validated.
This jar contains signed entries which are not signed by the specified alias(es).
This jar contains signed entries that are not signed by alias in this keystore.
nandsito
  • 3,782
  • 2
  • 19
  • 26
  • Thanks for your insightful answer. :) I would like to be more connected. join me on twitter, if you'd like. – Farhad Apr 04 '17 at 06:50
  • 3
    After integrating the signed AAR file in to the parent App, How to check the signature of the AAR at runtime ? I managed to take the SHA-256 of the parent app, But I need to check the SHA-256 of my AAR file. – MohanRaj Feb 26 '20 at 09:56
  • So from this answer it seems that the digital signature of an android `aar` library is not done within android's toolset like for an `apk` which uses Android's `apksigner.jar`. Hence, I can sign an `aar` using gpg or openssl etc. – daparic Mar 05 '20 at 18:30
  • @MohanRaj - I am in the same situation as yours. Did you find out a way to verify the signature of the AAR at runtime from within the parent app? Any input is appreciated. Thanks! – learner Oct 21 '20 at 05:05
  • I tried for long and decided to encrypt my APK with AES encryption and stored it as file on the memory, During runtime, I decrypt it then with help of reflection I call all the critical methods and classes inside the Dex file. This is the best way available as on date. – MohanRaj Dec 07 '20 at 04:19
  • Would it be possible for a aar to verify that the aar hasn't been tempered at runtime? – sinek Jul 12 '21 at 09:26
1

Because variant.signingConfig doesn't work for me I have used

apply plugin: 'com.android.library'

...

android {
    ...

    signingConfigs {
        release {
            storeFile file("${rootProject.projectDir}/keystore.jks")
            storePassword "XXXX"
            keyAlias "alias"
            keyPassword "XXXX"
        }
    }

    ...
}

tasks.whenTaskAdded { task ->
    if (task.name == 'assembleRelease') {
        def aarPath = "${project.buildDir}/outputs/aar/XXX-release.aar"

        task.doLast {
            ant.signjar(
                    alias: android.signingConfigs.release.keyAlias,
                    jar: aarPath,
                    keystore: android.signingConfigs.release.storeFile,
                    storepass: android.signingConfigs.release.storePassword,
                    keypass: android.signingConfigs.release.keyPassword,
                    preservelastmodified: 'true')

            ant.verifyjar(
                    alias: android.signingConfigs.release.keyAlias,
                    jar: aarPath,
                    keystore: android.signingConfigs.release.storeFile,
                    storepass: android.signingConfigs.release.storePassword,
                    keypass: android.signingConfigs.release.keyPassword)
        }
    }
}
CAMOBAP
  • 5,523
  • 8
  • 58
  • 93
  • 1
    before I start a new question: how do you capture the output message from `verifyJar` task? Otherwise, it seems to me that task never fails, so there's no way to actually check if .AAR has been successfully signed. – superjos Jun 06 '19 at 14:53
  • @superjos I thought that it throws some exception if the verification failed. Doesn't it work in a such way? – CAMOBAP Aug 19 '21 at 11:05
  • @CAMOBAP is there any way to verify the aar in the library consumer app? – tronku Aug 20 '21 at 11:31
  • @tronku I think yes you can [loop through a list of dependencies](https://docs.gradle.org/current/userguide/declaring_dependencies.html#sub:file_dependencies), and get their paths. so you can filter out the exact AAR's path which you need. And then feed it for `ant.verifyjar` task – CAMOBAP Aug 20 '21 at 13:54
0

You can generate it by execute:

./gradlew assembleRelease

Or from gradle menu, on the right side of the Android Studio, select YourLibraryProject->Tasks->Build->AssembleRelease.

But of course you need to add the signing key in your library project. Please read at Sign Your App

ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
0

I haven't tried but this "should" work:

Create a block like this in your gradle config file for the aar you're going to create:

signedAar {
    signedConfig{
        storeFile file("path/to/keystore")
        storePassword "Password"
        keyAlias "Alias"
        keyPassword "AliasPassword"
    }
}

then add this to the buildTypes -> release block of the same config file:

signingConfig  signedAar.signedConfig

Let us know if this works

Javad Arjmandi
  • 331
  • 1
  • 3
  • 12
-1

Why don't you sha-256 hash your aar file? even if someone messed around, the hash of the aar changes and you'll get to know. it works for me ;)

Milad Bahmanabadi
  • 946
  • 11
  • 27
Neha
  • 17
  • 1
  • 2
  • 1
    How to get the sha-256 of the AAR at runtime ? When I try to extract signed info from my package it gives me only the signatures of App not the integrated AAR. – MohanRaj Feb 26 '20 at 09:51