It is time to update to a stronger signing key for your Android app! The old default RSA 1024-bit key is weak and officially deprecated.
The Android OS requires that every application installed be signed by a digital key. The purpose behind this signature is to identify the author of the application, allow this author and this author alone to make updates to the app, as well as provide a mechanism to establish inter-application trust. The Android security model defines an app by two things: the package name (aka
package) and the signing key. If either of those are different, then Android considers it a different app. When the package name and signing key of one APK match an installed app, then the APK is considered an update and Android will replace the installed app with the APK. If the APK is signed by a different key, then Android will prevent installing and updating.
First thing is to see what the current signing key is. Check any app’s signing key using our free utility app Checkey:
The official Android docs have tons of useful information about what the signing keys are good for, how to generate them, and how to use them. Unfortunately, it doesn’t provide any instructions for migrating, and for many years, 1024-bit RSA was the default. But first, why would you want or need to migrate?
Depending on when you created your signing key, you might have a particularly weak key. The primary danger of a weak key is that an adversary could break your key in order to generate fake APK signatures. Then those malicious APKs can be installed as updates to your app. There are other nefarious purposes depending on how you use the signing key in your apps. Or if you are unfortunate enough to have suffered a loss of your private key material, then it is definitely time for a new signing key.
According to our friends at the Android Observatory, over 64% of Android apps in their data store use 1024-bit signing keys (RSA or DSA).
There are several good reasons to migrate off of 1024-bit RSA keys, even though there is no public proof of a 1024 prime factorization required to generate any 1024-bit key at will. The evidence has been mounting for a decade.
NIST’s official guidelines (PDF, page 64 and 67) deprecated 1024-bit RSA keys at the end of 2013. This deprecation by NIST isn’t an indication that 1024-bit RSA is compromised, instead it is a preemptive move to stay ahead of attacks. Confidence in NIST might be shaken in light of recent revelations, but in this case increasing the RSA key size is unlikely to trigger any secret NSA backdoors. If anything, the deprecation year could have been extended slightly to allow the NSA a window where they had the capacity to factor 1024-bit keys and everyone was still using them. So, it’s time to move on.
For an example, a decade ago the cost of building special purpose hardware capable of breaking a single 1024-bit RSA key in one year was estimated at $10 million (Adi Shamir, Eran Tromer, On the cost of factoring RSA-1024, 2003). Presumably the techniques have improved by orders of magnatude, and the hardware value depreciated. It is conceivable the cost has fallen enough to be affordable not only by nation-state actors, but by large criminal enterprises too.
For a comprehensive talk on the state of the art (as of December 2012) when it comes to breaking 1024-bit RSA, check out the 29C3 talk FactHacks: RSA factorization in the real world with the cryptographers Daniel J. Bernstein, Nadia Heninger, and Tanja Lange (watch recording)
Migrating to a strong key for an Android app is, unfortunately, not so simple. If you are publishing a new app to the app store, then simply generate a new strong signing key and you’re done. Congratulations! However, there exists no easy way to update your signing key for an existing application, because an installed application can only take updates from an APK signed with the same key.
Here we outline a basic method with which you can use to fake an update to your signing key. This is not as user friendly as we would like. Some of the hard facts of performing this process is that for most app stores including Google Play, you will lose ratings and reviews since the app will show up with a new package name, and the app store will treat it like an entirely new app. Also, the user will have to manually uninstall the original app once they finish the procedure. Here is a rough outline of the process:
- generate the new signing key, RSA 4096
- Update the first app, App1, with a mechanism for exporting private data, using TrustedIntents with a signature pin of the new key, RSA 4096, which Checkey will generate for you
- Create a new version of the app with a different package name, App2
- sign App2 with new key, RSA 4096
- Add method to App2 for receiving user data from App1, including a signature pin of the old signing key, RSA 1024, for use with TrustedIntents
- Publish App2 to the app stores
- From App1, prompt user to install App2
- runs and imports data from App1
- App2 prompts user to uninstall App1
For F-Droid, there will be some easier tools for handling this. The F-Droid system is already used to multiple signing keys per app since F-Droid uses its own signing key for many of the apps it releases, and that F-Droid signing key is different from the signing key that the original developer used in their Google Play uploads. F-Droid will likely be able to support APKs with the same package name but with multiple signing keys.
A Note on Compatibility
There is security vs compatibility trade off a few might be interested in. Pre-4.3, Android did not support any signature algorithms except SHA1. With Android >= 4.3, SHA256 support was fixed, and SHA384, SHA512, and ECDSA were added (source). There are still android 2.3.3 (
android-10) devices being sold, so anyone interested in backwards compatibility will have to heed this.
Also, the larger the keysize and hashsize used, the longer it takes to install and update the application. So extremely large values might be unsuitable for slower hardware. The following probably doesn’t buy you a tremendous amount of additional security but cranks the paranoia to 11. It does so at the cost of compatibility and performance.
keytool -genkey -v -keystore test.keystore -alias testkey -keyalg RSA -keysize 4096 -sigalg SHA512withRSA -dname "cn=Test,ou=Test,c=CA" -validity 10000
jarsigner -verbose -sigalg SHA512withRSA -digestalg SHA512 -keystore test.keystore test.apk testkey
We have some scripts that we use to generate keys in our smartcard-apk-signing repo. It is also possible to generate an Android signing key using openssl or other libraries. It is often wise to use different software than standard for doing things like generating keys. Since the Java
keytool approach that is the standard, recommended method for Android, that makes it a target for adversaries that are interested in breaking keys. If a key was generated using
openssl or GNU TLS instead, for example, then that key would not be affected if
keytool had a bug like Debian’s CVE-2008-0166.