Copyright 2017 Robert M. V. Gaines
This work is licensed under the Creative Commons Attribution 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/.
- The author of this document does not profess to be an expert on cryptography or APK Signature Schemes; this document may contain errors or omissions.
- This document is geared towards Windows users. Some steps may need to be modified for other operating systems.
- Only those aspects of the tools and concepts discussed here that apply to APK signing will be discussed.
- Ensure that JDK and Android SDK Build Tools are installed and properly configured.
- Generate keystore containing a key pair compatible with the target Android API Levels.
- Align the APK using zipalign.
- Use apksigner to sign the APK using the keystore.
- Digital Signature: A hash, generated by a hash function then encrypted with public-key cryptography, used to verify the source of data and the data's integrity.
- Public-Key Cryptography: Public key cryptography, or asymmetric cryptography, is a cryptosystem that uses a key pair to encrypt data, verify the source of the data, and verify the data's integrity.
- Cryptosystem: A collection of cryptographic algorithms.
- Keystores: A keystore is an encrypted container for cryptographic certificates and keys.
- Cryptographic key: A value supplied to a cryptographic algorithm when encrypting or decrypting data.
- Key Pair: A pair of unique mathematically linked cryptographic keys, public and private.
- Public Key: A cryptographic key that is shared publicly. Data encrypted by a public key can be decrypted using a matched private key. A public key can be derived from a private key.
- Private Key: A key that is kept private. Data encrypted by a private key can be decrypted using a matched public key. A private key cannot be derived from a public key.
- Hash Function: Converts data into a "hash" that can be used to verify data integrity.
- Collision Attack: Maliciously crafting two pieces of data that have the same hash.
- Preimage attack: Maliciously crafting data that generates the same hash as legitimate data.
- Birthday Attack: A collision attack that performs random manipulations to find a collision.
- A key pair is required for APK signing.
- Key pairs are usually generated in, or placed in to, keystores.
- The keystore must be generated using an application such as Java Keytool.
- The public key algorithm and hash function must be compatible with the target APK signature schema and Android API level.
- Java Keytool is a command line application that generates keystores.
- Other applications may be used to generate keystores.
- The genkeypair command, passed as a flag, adds a key pair, that can be used to sign APKs, to a keystore.
- Genkey is a depreciated alias for genkeypair.
- The key pair consists of a public-key certificate, a public key wrapped in a self-signed certificate, and a private key.
- The public-key certificate is stored as a single-element certificate chain.
- A keystore will be generated if one does not exist.
- During generation, passwords must be provided for both the keystore and the key pair.
- Genkeypair accepts the following arguments, set via flags:
- keystore: Keystore filename.
- If unspecified, .keystore is used as a default.
- validity: Number of days until the key pair becomes invalid.
- If unspecified, 90 days is used as a default.
- The number of days, when added to the current date, must not result in a date after the end of year 9999.
- Keytool will accept up to 9223372036854775807 days, however they result in invalid dates.
- keysize: Number of bits in a key.
- If unspecified, the default is chosen based on keyalg.
- 1024 bits is used as the default with DSA.
- 2048 bits is used as the default with RSA.
- The maximum length supported for DSA is 2048
- keyalg: Public key algorithm used for key generation.
- If unspecified, DSA is used as a default.
- sigalg: Signature algorithm used to sign the certificate containing the public key.
- Follows the format HASHFNCwithKEYALG, where HASHFNC is a hash function and KEALG is a key algorithm i.e. SHA1withRSA
- Must be compatible with the key algorithm.
- If unspecified, the default is chosen based on keyalg.
- SHA1withDSA is used as the default with DSA
- SHA256withRSA is used as the default with RSA
- dname: X.500 Distinguished Names
- Follows the format:
CN=cName, OU=orgUnit, O=org, L=city, S=state, C=countryCode
- CN: Common Name, i.e. first and last name
- OU: Organization Unit, i.e. department
- O: Organization Name
- L: Locality Name, i.e. city or town
- S: State Name, i.e. state or province
- C: Country Code, i.e. a two-letter country code
- Fields may be omitted.
- If unspecified, the user will be prompted.
- Follows the format:
- storetype: Keystore format.
- If unspecified, the default is based on system wide settings, usually set to JKS.
- alias: Name used to identify generated key pair.
- Capped at 8 characters.
- If unspecified, mykey is used as a default.
- storepass: Password used to unlock the keystore.
- Must be at least 6 characters in length.
- If unspecified, the user will be prompted.
- keypass: Password used to unlock the key pair.
- Must be at least 6 characters in length.
- If unspecified, the user will be prompted.
- keystore: Keystore filename.
- Genkeypair also accepts a "v" flag that enables verbose output.
- Defaults may change between keytool versions; they should not be relied upon.
- DSA and RSA have equivalent security, but DSA validation is slower.
- Although DSA is secure, some DSA implementations are not. Many experts have recommended that DSA be depreciated.
- Google recommends RSA.
- Android API Level < 18 is compatible with SHA1.
- Android API Level >= 18 is compatible with SHA1, SHA256, SHA384*, and SHA512.
- MD5 compatibility is unclear.
- SHA1 is depreciated by NIST, but recommended by Google for signing APKs.
- MD5 is potentially insecure and has been depreciated by several groups.
- SHA1 is more secure than MD5.
*See section on APK Signature Schemes
- The following has no impact on signing. It is provided for informational purposes.
- Termination of DSA support in Android API Level > 22, may strengthen the case for not using DSA for APK signing
- DSA Support: Android API Level = [19, 22]
- RSA Support: Android API Level >= 18
- MD5 Support: Android API Level >= 18
- MD5 is only supported with RSA
- SHA1 Support: Android API Level >= 18
- SHA224 Support: Android API Level >= 20
- SHA256 Support: Android API Level >= 18
- SHA384 Support: Android API Level >= 18
- SHA512 Support: Android API Level >= 18
- Google recommends MD5withRSA, but this recommendation may be outdated.
- SHA1withRSA should be used for Android API Level < 18
- Sha512withRSA should be used for Android API Level >= 18
- Any keysize >= 2048 is acceptable, but 4096 for RSA and 3072 for DSA are more secure.
- When using keytool, it is appropriate to use 2048-bit DSA, since keytool does not support 3072-bit DSA.
- Larger keysizes slow validation, consider 2048 for large apps.
- NIST has depreciated 1024-bit RSA
- Google recommends 2048 or greater.
- Google recommends 10000 days (27.39726 years) or greater.
- Google will not accept APKs signed with a key that expires less than 25 years after the APKs initial release.
- JKS
- The default keystore used by keytool.
- Designed specifically for use with Java, but may be supported by other providers.
- Cannot store secret keys, but this is not applicable to APK signing.
- Uses the .jks file extension.
- JCEKS
- Uses the .jceks file extension.
- Designed specifically for use with Java, but may be supported by other providers.
- May be incompatible with some older Java products.
- Features stronger encryption than JKS.
- Currently, Google does not support signing APKs with a JCEKS keystore.
- PKCS12
- May be used as the default storetype, once Java 9 is released.
- Designed to be more portable than JKS.
- Features stronger encryption than JKS.
- Uses the .p12 or .pfx file extension.
- Currently, Google does not support signing APKs with a PKCS12 keystore.
- Windows-MY
- Stores key pairs in the system wide windows keystore.
- Cannot store secret keys, but this is not applicable to APK signing.
- Currently, Google does not support signing APKs with a Windows-MY keystore.
- KeychainStore
- Stores key pairs in the system wide OSX keychain.
- It is unknown if Google accept APKs signed with a KeychainStore keystore.
- BKS
- Must be installed before use with keytool.
- Features strong keystore encryption.
- Uses the .bks file extension.
- Currently, Google does not support signing APKs with a BKS keystore.
- keystore: appName.jks, where appName is replaced with the app's name
- validity: 365000 (1000 years)
- keysize: 4096
- keyalg: RSA
- sigalg: SHA1withRSA for Android API Level < 18 or SHA512withRSA for Android API Level >= 18
- storetype: JKS
- dname: Appropriate X.500 distinguished name
- alias: App name abbreviated to 8 characters
- APK alignment reduced the amount of ram consumed by an app.
- Zipalign is a command line application that aligns archives, including APKs.
- If apksigner is used, alignment must occur before apksigner is executed.
- If jarsigner is used, alignment must occur after jarsigner is executed.
- Zipalign accepts arguments in the following format :
[flags] <alignment> <input_file> <output_file>
- flags:
- f: If a file exists with the same name as the output file, overwrite it.
- v: Enable verbose output.
- p: Use the same alignment for all shared object files within the input file.
- c: Validate alignment without modification.
- alignment: Integer defining byte-alignment boundaries
- Alignment must always be 4 when aligning APKs. This results in 32-bit alignment.
- input_file: APK to be aligned
- output_file: Filename for aligned APK
- If unspecified, the unaligned APK is replaced.
- flags:
- Flags: -f -v
- Alignment: 4
- Before an APK can be installed on devices or accepted by Google Play, it must be signed.
- During testing, APKs can be signed with a debug keystore.
- Debug kystores are provided by most tools and IDEs.
- Google play will not accept APKs signed with a debug keystore.
- Apksigner is a command line application that signs APKs
- Other applications, such as jarsigner, may be used to sign APKs, however they will only apply APK Signature Scheme v1, which is the same as a standard JAR signature.
- The sign command is used to sign an APK.
- The sign command accepts arguments in the following format:
--ks <keystore> [signer_options] <apk>
- keystore: Keystore to use for signing.
- signer_options: Options passed as flags, i.e.
--out
- out: Filename for signed APK.
- If unspecified, the unsigned APK is replaced.
- min-sdk-version: The lowest Android API level apksigner will validate against.
- If unspecified, the default is extracted from the APK's manifest.
- Apksigner will not implement security features that are incompatible with the Android API Level specified by min-sdk-version.
- max-sdk-version: The highest Android API level apksigner will validate against.
- If unspecified, the default is extracted from the APK's manifest.
- v1-signing-enabled: Forces or prevents implementation of APK Signature Scheme v1
- If unspecified, the default is based on min-sdk-version.
- v2-signing-enabled: Forces or prevents implementation of APK Signature Scheme v2
- If unspecified, the default is based on min-sdk-version.
- ks-key-alias: Alias under which the signing key pair is stored within the keystore
- If unspecified and only one alias is found in the keystore, that alias is used as the default.
- If multiple aliases are found within the keystore, this option must be specified.
- ks-pass: Password used to unlock the keystore.
- If unspecified, the user will be prompted.
- v: Enable verbose output.
- out: Filename for signed APK.
- apk: Apk to be signed.
- APK Signature Scheme v1 is based on JAR signing.
- APK Signature Scheme v1 does not authenticate the entire APK nor does it validate the integrity of the entire APK.
- APK Signature Scheme v1 supports all major key algorithms and hash functions discussed in this document.
- APK Signature Scheme v1 does not restrict key size.
- APK Signature Scheme v2 both authenticates the entire APK and validates it's integrity.
- APK Signature Scheme v2 is faster than v1.
- APK Signature Scheme v2 support was added in Android API Level 24
- It is unclear if MD5, SHA1, and SHA384 are supported by Android API Level >= 24 when using APK Signature Scheme v2.
- RSA Key sizes Supported by APK Signature Scheme v2: 1024, 2048, 4096, 8192, 16384
- DSA Key sizes Supported by APK Signature Scheme v2: 1024, 2048, 3072
- Apps targeting all versions of Android can sign with both Signature Scheme v1 and Signature Scheme v2.
- signer_options:
--v --out <output_file>
where output_file is an unused filename ending in .apk