How to sign and re-sign Android's APK program _android

Source: Internet
Author: User
Tags base64 sha1


Use of the Signing tool
the Signapk.jar of the Android source code can either be signed by the APK or signed by the ROM. Use format:


Java–jar Signapk.jar [W] publickey.x509[.pem] privatekey.pk8 Input.jar Output.jar
    • -W refers to the parameters that need to be used when signing a ROM
    • PUBLICKEY.X509[.PEM] is a public key file
    • PRIVATEKEY.PK8 refers to the private key file
    • Input.jar APK or ROM to be signed.
    • APK or ROM generated by Output.jar signature


Signapk.java



1) Main function
The main function generates a public key object and a private key object and invokes the SignFile signature after calling the Adddigeststomanifest function to generate the manifest object manifest.


 public static void Main (string[] args) {//... boolean signwholefile = false;
 int argstart = 0;
  /* If the ROM signature needs to be passed-w parameter/if (Args[0].equals ("W")) {Signwholefile = true;
 Argstart = 1;
  }//... try {file Publickeyfile = new file (args[argstart+0]);
  X509Certificate PublicKey = Readpublickey (publickeyfile);
  Privatekey Privatekey = Readprivatekey (new File (args[argstart+1)); 
  Inputjar = new Jarfile (new File (args[argstart+2)), false);
  outputfile = new FileOutputStream (args[argstart+3]); /* to the ROM signature, the reader can analyze, and apk hungry signature similar, but it will add otacert file * * * (signwholefile) {signapk.signwholefile (Inputjar, Publickeyfile, Pub
  Lickey, Privatekey, outputfile);
   else {Jaroutputstream Outputjar = new Jaroutputstream (outputfile);
   Outputjar.setlevel (9); 
   /*adddigeststomanifest generates the manifest object and then invokes the SignFile for signature */SignFile (Adddigeststomanifest (Inputjar), Inputjar,
   Publickeyfile, PublicKey, Privatekey, Outputjar);
  Outputjar.close (); } catch (Exception e) {e.printsTacktrace ();
 System.exit (1);
 Finally {//...}}Public static void main(String[] args) {
 //...
 Boolean signWholeFile = false;
 Int argstart = 0;
 /* If you are signing the ROM, you need to pass the -w parameter */
 If (args[0].equals("-w")) {
  signWholeFile = true;
  Argstart = 1;
 }
 // ...
 Try {
  File publicKeyFile = new File(args[argstart+0]);
  X509Certificate publicKey = readPublicKey(publicKeyFile);
  PrivateKey privateKey = readPrivateKey(new File(args[argstart+1]));
  inputJar = new JarFile(new File(args[argstart+2]), false);
  outputFile = new FileOutputStream(args[argstart+3]);
  /* Sign the ROM, the reader can analyze it himself, similar to the Apk hungry signature, but it will add the otacert file*/
  If (signWholeFile) {
   SignApk.signWholeFile(inputJar, publicKeyFile, publicKey,
    privateKey, outputFile);
  }
  Else {
   JarOutputStream outputJar = new JarOutputStream(outputFile);
   outputJar.setLevel(9);
   /*addDigestsToManifest will generate a Manifest object and then call signFile to sign */
   signFile(addDigestsToManifest(inputJar), inputJar,
   publicKeyFile, publicKey, privateKey, outputJar);
   outputJar.close();
  }
 } catch (Exception e) {
  e.printStackTrace();
  System.exit(1);
 } finally {
  //...
 }
}


2) Adddigeststomanifest
First we have to understand the structure of the manifest file, the manifest file is divided into segments with empty lines, each segment is composed of several attributes, the first section of the property set called the Main property collection, the other segments called normal property collection, the normal property collection will generally have the Name property, As the name of the segment where the property collection is located. The Android Manifeset file creates a segment for all zip files, and the value of the Name property of the segment is the file's path+ file name, plus a sha1-digest attribute. The value of this property is a string of base64 encoded for the SHA1 summary of the file.
Manifest Example:


manifest-version:1.0
CREATED-BY:1.6.0-RC (Sun Microsystems Inc.)
 
Name:res/drawable-hdpi/user_logout.png
sha1-digest:zkqszbt3tqc9myevuxc1dzmdpcs=
 
name:res/drawable-hdpi /contacts_cancel_btn_pressed.png
sha1-digest:msvzvkpvkpmguj9oxdjatwzhdic=
 
name:res/drawable/main_head_ Backgroud.png
sha1-digest:fe1yzadfdgzvr0cyidnpgf/ysio=


The Manifest-version property and created-by segment are the main collection of properties, and the collection of other attributes is a collection of common properties that have the name attribute as their first names.
Adddigeststomanifest Source code:


Private static Manifest addDigestsToManifest(JarFile jar)
   Throws IOException, GeneralSecurityException {
 Manifest input = jar.getManifest();
 Manifest output = new Manifest();
 Attributes main = output.getMainAttributes();
 If (input != null) {
  main.putAll(input.getMainAttributes());
 } else {
  main.putValue("Manifest-Version", "1.0");
  main.putValue("Created-By", "1.0 (Android SignApk)");
 }
 MessageDigest md = MessageDigest.getInstance("SHA1");
 Byte[] buffer = new byte[4096];
 Int num;
 // We sort the input entries by name, and add them to the
 // output manifest in sorted order. We expect that the output
 // map will be deterministic.
 TreeMap<String, JarEntry> byName = new TreeMap<String, JarEntry>();
  
 For (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements(); ) {
  JarEntry entry = e.nextElement();
  byName.put(entry.getName(), entry);
 }
  
 For (JarEntry entry: byName.values()) {
  String name = entry.getName();
  If (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) &&
   !name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) &&
   !name.equals(OTACERT_NAME) &&
   (stripPattern == null ||
    !stripPattern.matcher(name).matches())) {
   InputStream data = jar.getInputStream(entry);
   /*Compute sha1*/
   While ((num = data.read(buffer)) > 0) {
    Md.update(buffer, 0, num);
   }
   Attributes attr = null;
   If (input != null) attr = input.getAttributes(name);
   Attr = attr != null ? new Attributes(attr) : new Attributes();
   /*base64 encodes the sha1 value to get the value of the SHA1-Digest attribute*/
   attr.putValue("SHA1-Digest",
       New String(Base64.encode(md.digest()), "ASCII"));
   output.getEntries().put(name, attr);
  }
 }
 Return output;
}


3)  signfile
Copies all inputjar files to the Outputjar and then generates MANIFEST.MF,CERT.SF and Cert.rsa


public static void SignFile (Manifest Manifest, Jarfile Inputjar, File publickeyfile, X509Certificate publickey, Privatek
 EY privatekey, Jaroutputstream Outputjar) throws Exception {//Assume the certificate is valid to at least a hour.
 Long timestamp = Publickey.getnotbefore (). GetTime () + 3600L * 1000;
 Jarentry JE;
 Copy files CopyFiles (manifest, Inputjar, Outputjar, timestamp);
 Generate Manifest.mf JE = new Jarentry (jarfile.manifest_name);
 Je.settime (timestamp);
 Outputjar.putnextentry (JE);
 Manifest.write (Outputjar);
 Call Writesignaturefile to generate cert.sf JE = new Jarentry (cert_sf_name);
 Je.settime (timestamp);
 Outputjar.putnextentry (JE);
 Bytearrayoutputstream BAOs = new Bytearrayoutputstream ();
 Writesignaturefile (Manifest, BAOs);
 byte[] Signeddata = Baos.tobytearray (); 
 Outputjar.write (Signeddata); A very critical step in generating CERT.
 RSA JE = new Jarentry (cert_rsa_name);
 Je.settime (timestamp);
 Outputjar.putnextentry (JE);
      Writesignatureblock (New Cmsprocessablebytearray (Signeddata),PublicKey, Privatekey, Outputjar);
 }


4)  writesignaturefile
generates CERT.SF, in fact, the SHA1 summary is CERT.SF for each segment of the MANIFEST.MF.


Private static void writeSignatureFile(Manifest manifest, OutputStream out)
  Throws IOException, GeneralSecurityException {
 Manifest sf = new Manifest();
 Attributes main = sf.getMainAttributes();
 / / Add attributes
 main.putValue("Signature-Version", "1.0");
 main.putValue("Created-By", "1.0 (Android SignApk)");
 MessageDigest md = MessageDigest.getInstance("SHA1");
 PrintStream print = new PrintStream(
   New DigestOutputStream(new ByteArrayOutputStream(), md),
   True, "UTF-8");
 // Add the sha1 summary of Manifest.mf
 Manifest.write(print);
 Print.flush();
 main.putValue("SHA1-Digest-Manifest",
     New String(Base64.encode(md.digest()), "ASCII"));
 / / Calculate the sha1 summary for each segment of MANIFEST.MF
 Map<String, Attributes> entries = manifest.getEntries();
 For (Map.Entry<String, Attributes> entry : entries.entrySet()) {
  // Digest of the manifest stanza for this entry.
  Print.print("Name: " + entry.getKey() + "\r\n");
  For (Map.Entry<Object, Object> att : entry.getValue().entrySet()) {
   Print.print(att.getKey() + ": " + att.getValue() + "\r\n");
  }
  Print.print("\r\n");
  Print.flush();
  
  Attributes sfAttr = new Attributes();
  sfAttr.putValue("SHA1-Digest",
      New String(Base64.encode(md.digest()), "ASCII"));
  sf.getEntries().put(entry.getKey(), sfAttr);
 }
 CountOutputStream cout = new CountOutputStream(out);
 Sf.write(cout);
 // A bug in the java.util.jar implementation of Android platforms
 // up to version 1.6 will cause a spurious IOException to be thrown
 // if the length of the signature file is a multiple of 1024 bytes.
 // As a workaround, add an extra CRLF in this case.
 If ((cout.size() % 1024) == 0) {
  Cout.write('\r');
  Cout.write('\n');
 }
}


5)  writesignatureblock
uses the SHA1WITHRSA algorithm to compute a summary of the CERT.SF and encrypts the digital signature, using a private key that is privatekey, and then storing the digital signature and the public key in the Cert.rsa. Here we use the Open Source Library Bouncycastle to sign.


private static void Writesignatureblock (Cmstypeddata data, X509Certificate publickey, Privatekey Privatekey, OUTPUTSTR Eam out) throws IOException, Certificateencodingexception, Operatorcreationexception, cmsexception {ArrayList& Lt
 x509certificate> certlist = new arraylist<x509certificate> (1);
 Certlist.add (PublicKey); 
 Jcacertstore certs = new Jcacertstore (certlist);
 Cmssigneddatagenerator Gen = new Cmssigneddatagenerator (); The signature algorithm is Sha1withrsa contentsigner sha1signer = new Jcacontentsignerbuilder ("Sha1withrsa"). Setprovider (
 Sbouncycastleprovider). Build (Privatekey); Gen.addsignerinfogenerator (New Jcasignerinfogeneratorbuilder (), New Jcadigestcalculatorproviderbuilder (). SetProvid
 ER (sbouncycastleprovider). Build ()). Setdirectsignature (True)-build (Sha1signer, PublicKey));
 Gen.addcertificates (certs);
 
 Cmssigneddata Sigdata = gen.generate (data, false);
 Asn1inputstream ASN1 = new Asn1inputstream (sigdata.getencoded ()); Deroutputstream dos = new Deroutputstream (out);
Dos.writeobject (Asn1.readobject ());

 }


re-sign APK
with the command line APK, there is also the simplest way to download a signed tool Re-sign.jar, the apk dragged into the tool's window generates a re-signed apk. Let me talk about the complex way to re-sign: using command-line methods.
First, configure the environment, you need to install JDK,SDK
Two, in the directory of the successful installation of JDK found Jarsigner.exe files, the directory of this machine is as follows: C:\Program Files\java\jdk1.8.0_20\bin
Three, Removes the signature of the APK itself that is ready to be re-signed (fantongyo.apk)
Opens the apk winrar, deletes the Meta-inf folder, and copies the apk file to C:\Program files\java\jdk1.8.0_ 20\bin Directory
APK Package content resolution:
1.meta-inf Directory: Signed cert and manifest files to identify software signatures and version information
2.rest directory: Storage of all kinds of Android raw resources, Includes: Animated anim, Picture drawable, layout layout, menus, XML, and so on
3.androidmanifest.xml encoded Android Project description file, including the name, edition limit, program component description of the Android project, etc. The
4.classes.dex compiled class is converted by a DX program into an executable bytecode file for a Dalvik virtual machine
5.RESOURCES.ARSC The compiled product of all the text resources, which contains the corresponding string resources for each location
Four , re-sign the APK file
method One: Re-sign the ANDROIDAPK package signing certificate after the command and then re-sign the APK file
1. Switch to the JDK bin directory in cmd: CD C:\Program files\java\jdk1.8.0_ 20\bin carriage return
2. Then enter the following command:


Keytool-genkey-alias fantongyo.keystore-keyalg rsa-validity 20000-keystore fantongyo.keystore/
* Explanation: The Keytool tool is the Java JDK's own certificate tool
-genkey parameter indicates: to generate a certificate (copyright, Identity Security certificate)
-alias parameter indicates that the certificate has an alias,-alias Fantongyo.keystore indicates that the certificate alias is: Fantongyo
-keyalg RSA represents the encryption type, and RSA represents the need for encryption to prevent others from stealing
-validity 20000 indicates a valid time of 20,000 days (K3
-keystore Fantongyo.keystore indicates that the certificate name to be generated is fantongyo
*/

After entering return, the screen displays:
Enter keystore password: [password does not echo] (generally recommended to use 20-bit, it is best to write down the back to use)
Enter the new password again: [Password not echo] (o ' ^$ _ (F) (k& I0
What is your first and last name?
[Unknown]:fantongyo
What is your organizational unit name?
[Unknown]:fantong
What is your organization's name?
[Unknown]:life
What is the name of your city or region? ) l# V ' |. E0 F; {
[Unknown]:shenzhen
What is the name of your state or province?
[Unknown]:guangdong
What is the two-letter country code for that unit?
[UNKNOWN]:CN
Cn=fantongyo, U=fantong, O=fantong team, L=shenzhen, St=guangdong, C=CN right?
[No]:y
Enter the master password for < mine.keystore>
(press ENTER if same as KeyStore password):
View the C:\Program Files\java\jdk1.8.0_20\bin directory to generate a signed certificate file Fantongyo.keystore
3. Re-sign the APK document
Enter in cmd: Jarsigner–verbose–keystore fantongyo.keystore–signedjar fantongyo_signed.apk fantongyo.apk Fantongyo.keystore
/* Explanation: * ^, {& K1 Z. m* p/m+ K5 N5 Hjarsigner is the Java Signature Tool # K8 ~% s# Y. @6 P
-verbose parameter representation: Displays the signature details
-keystore represents the use of Fantongyo.keystore signed certificate files in the current directory.
-signedjar fantongyo_signed.apk represents the APK name generated after the signature,% v! A7 E2 v4 w#];

 gfantongyo.apk represents unsigned apk Android software, Fantongyo.keystore represents an alias
*/
After entering return, the screen displays:
The jar is signed.





fantongyo_signed.apk files have been regenerated under the C:\Program Files\java\jdk1.8.0_20\bin directory



Method two, with Android with the Debug.keystore to re-sign apk files
1. Open Eclipse, menu bar window->preferences->android->build->default Debug KeyStore directory (my editor shows: C:\Users\ Administrator\.android\debug.keystore)
2. Copy the Debug.keystore file to the C:\Program Files\java\jdk1.8.0_20\bin directory
3. Switch to JDK's Bin directory in cmd: cd C:\Program files\java\jdk1.8.0_20\bin carriage return
4. Then enter the following command:


Copy Code code as follows:
Jarsigner-digestalg sha1-sigalg md5withrsa-keystore debug.keystore-storepass android-keypass android fantongyo.apk an Droiddebugkey
Enter
5. Find the Zipalign file in the SDK, My Computer directory is: E:\SoftWare\adt-bundle-windows-x86-20140702\sdk\build-tools\android-4.4W
In cmd, switch to the directory where the SDK resides in the Zipalign.exe file:




CD E:\SoftWare\adt-bundle-windows-x86-20140702\sdk\build-tools\android-4.4W


6. Re-enter: Zipalign 4 fantongyo.apk fantongyo_signed.apk (fantongyo_signed.apk is a re-signed apk file)


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.