Skip to content

Latest commit

 

History

History
246 lines (223 loc) · 13.2 KB

apk-signing-guide.md

File metadata and controls

246 lines (223 loc) · 13.2 KB

APK Signing Guide

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/.

Disclaimers

  • 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.

Prerequisites

  • Ensure that JDK and Android SDK Build Tools are installed and properly configured.

Process

  1. Generate keystore containing a key pair compatible with the target Android API Levels.
  2. Align the APK using zipalign.
  3. Use apksigner to sign the APK using the keystore.

Definitions

  • 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.

Keystore Generation

  • 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.

Keytool

  • 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.
    • 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.
  • Genkeypair also accepts a "v" flag that enables verbose output.
  • Defaults may change between keytool versions; they should not be relied upon.

Public Key Algorithm

  • 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.

Hash Functions

  • 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

Android Keystore System Support for Cryptographic Keys and Hash Functions

  • 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

Keytool Sigalg Argument

  • 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

Keysize

  • 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.

Validity

  • 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.

Storetype

  • 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.

Recommended Keytool Genkeypair Settings

  • 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

  • APK alignment reduced the amount of ram consumed by an app.

Zipalign

  • 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.

Recommended Zipalign Settings

  • Flags: -f -v
  • Alignment: 4

APK Signing

  • 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

  • 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.
    • apk: Apk to be signed.

APK Signature Schemes

  • 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.

Recommended Apksigner Sign Settings

  • signer_options: --v --out <output_file> where output_file is an unused filename ending in .apk