SoFunction
Updated on 2025-04-09

Android's APK application signature mechanism and method of reading signature

Friends who have published Android applications should know that the release of Android APK requires signatures. The signature mechanism plays a very important role in Android applications and frameworks. For example, the Android system prohibits updating APKs with inconsistent installation signatures; if the application needs to use system permissions, it is necessary to ensure that the APK signature is consistent with the Framework signature, etc.

What is a signature
First of all, we need to know what a digest is. A digest refers to a fixed-length Hash value generated by using a one-way Hash function to calculate the data. The digest algorithm includes Md5, Sha1, etc. The Hash value generated by Md5 is a 128-bit number, that is, 16 bytes, which is 32 characters in hexadecimal, and the Hash value generated by Sha1 is a 160-bit number, that is, 20 bytes, and 40 characters in hexadecimal. We cannot calculate the data used to calculate the digest through the digest. If the data is modified, its digest will definitely change (in fact, this sentence is not correct, it is just that it is difficult to find different data, and their digest values ​​are exactly equal). Summary is often used to verify the integrity of data. Many download websites list the md5 or sha1 values ​​of the download file.
The summary has nothing to do with the signature. It is wrong to confuse the summary and signature online. Signature and digital signature are the same concept, which means that the sender of the information uses his own private key to encrypt the message digest to generate a string. The encryption algorithm ensures that others cannot forge and generate this string. This digital string is also an effective proof of the authenticity of the information sent by the sender of the information. Other senders use their private key to encrypt the same message digest and will get different signatures. The receiver can only get the message digest by decrypting the signature data using the public key corresponding to the private key used by the sender's signature, otherwise the correct message digest will not be obtained.
Digital signature is a combination of asymmetric key encryption technology + digital digest technology.
Digital signature technology encrypts the information digest with the sender's private key and transmits it to the receiver together with the original text and the public key. The receiver can only decrypt the encrypted information digest using the sender's public key, and then the receiver uses the same Hash function to generate an information digest for the received original text and compare it with the decrypted information digest. If the same is true, it means that the received information is complete and has not been modified during the transmission process; it means that the information has been modified, so the digital signature can ensure the integrity of the information. And since only the sender has the private key to encrypt the digest, we can be sure that the information must be sent by the sender.
Another concept needs to be understood: digital certificates. A digital certificate is a file digitally signed by a certificate authorization center that contains the public key and its owner information. The format of digital certificates generally adopts the X.509V3 international standard. A standard X.509 digital certificate contains the following contents: Certificate version information:
1) The serial number of the certificate, each certificate has a unique certificate serial number;
2) The signature algorithm used by the certificate;
3) The name of the issuing agency of the certificate, and the naming rules generally use X.500 format;
4) The validity period of the certificate. Common certificates generally use UTC time format, and their timing range is 1950-2049;
5) The name of the certificate owner, the naming rules generally use X.500 format;
6) The public key of the certificate owner;
7) The certificate issuer's signature on the certificate.
It contains digital signatures and developer's digital certificates. The digital signature in the source refers to the data encrypted by the private key. When the Android system installs the apk, it will calculate the digest, and then use the digital signature in the public key pair to decrypt it to get a digest. By comparing these two digests, you can know whether the apk has the correct signature. In other words, if someone modifies the apk and does not re-sign it, it will be checked.
It should be noted that the certificates of the Android platform are self-signed, which means that they do not need to be issued by an authoritative organization. The issuing agency of the digital certificate is the same as the owner, and they are all developers themselves. After the developer generates the public and private key pair, they do not need to submit it to the authoritative organization for verification.

Read the signature
Sometimes you need to obtain the signature information of a specific apk (installed or not installed), such as program self-detection, trustworthy third-party detection (application market), and system-limited installation.
There are two ways to implement this
You can use the API that comes with Java (the main ones are JarFile, JarEntry, and Certificate) to obtain it. Another method is to use the system hidden API PackageParser to use the corresponding API through reflection.
However, due to the excessive split versions of the Android system and the many modifications made by different manufacturers, the method of relying on reflection and hiding API cannot guarantee compatibility and universality, so it is recommended to use JAVA's own API for obtaining:
  

 
  /**
    * Read signature from APK
    * @param file
    * @return
    * @throws IOException
    */ 
  private static List<String> getSignaturesFromApk(File file) throws IOException { 
    List<String> signatures=new ArrayList<String>(); 
    JarFile jarFile=new JarFile(file); 
    try { 
      JarEntry je=(""); 
      byte[] readBuffer=new byte[8192]; 
      Certificate[] certs=loadCertificates(jarFile, je, readBuffer); 
      if(certs != null) { 
        for(Certificate c: certs) { 
          String sig=toCharsString(()); 
          (sig); 
        } 
      } 
    } catch(Exception ex) { 
    } 
    return signatures; 
  } 

 /**
    * Loading signature
    * @param jarFile
    * @param je
    * @param readBuffer
    * @return
    */ 
  private static Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer) { 
    try { 
      InputStream is=(je); 
      while((readBuffer, 0, ) != -1) { 
      } 
      (); 
      return je != null ? () : null; 
    } catch(IOException e) { 
    } 
    return null; 
  } 
 
/**
    * Convert the signature to visible string
    * @param sigBytes
    * @return
    */ 
  private static String toCharsString(byte[] sigBytes) { 
    byte[] sig=sigBytes; 
    final int N=; 
    final int N2=N * 2; 
    char[] text=new char[N2]; 
    for(int j=0; j < N; j++) { 
      byte v=sig[j]; 
      int d=(v >> 4) & 0xf; 
      text[j * 2]=(char)(d >= 10 ? ('a' + d - 10) : ('0' + d)); 
      d=v & 0xf; 
      text[j * 2 + 1]=(char)(d >= 10 ? ('a' + d - 10) : ('0' + d)); 
    } 
    return new String(text); 
  }