日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

java 1.8签名apk_给Android的APK程序签名和重新签名的方法

發布時間:2023/12/2 Android 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 1.8签名apk_给Android的APK程序签名和重新签名的方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簽名工具的使用Android源碼編譯出來的signapk.jar既可給apk簽名,也可給rom簽名的。使用格式:

java –jar signapk.jar [-w] publickey.x509[.pem] privatekey.pk8 input.jar output.jar

-w 是指對ROM簽名時需使用的參數

publickey.x509[.pem] 是公鑰文件

privatekey.pk8 是指 私鑰文件

input.jar 要簽名的apk或者rom

output.jar 簽名后生成的apk或者rom

signapk.java

1)?main函數

main函數會生成公鑰對象和私鑰對象,并調用addDigestsToManifest函數生成清單對象Manifest后,再調用signFile簽名。

public static void main(String[] args) {

//...

boolean signWholeFile = false;

int argstart = 0;

/*如果對ROM簽名需傳遞-w參數*/

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]);

/*對ROM簽名,讀者可自行分析,和Apk餓簽名類似,但是它會添加otacert文件*/

if (signWholeFile) {

SignApk.signWholeFile(inputJar, publicKeyFile, publicKey,

privateKey, outputFile);

}

else {

JarOutputStream outputJar = new JarOutputStream(outputFile);

outputJar.setLevel(9);

/*addDigestsToManifest會生成Manifest對象,然后調用signFile進行簽名*/

signFile(addDigestsToManifest(inputJar), inputJar,

publicKeyFile, publicKey, privateKey, outputJar);

outputJar.close();

}

} catch (Exception e) {

e.printStackTrace();

System.exit(1);

} finally {

//...

}

}

2)?addDigestsToManifest

首先我們得理解Manifest文件的結構,Manifest文件里用空行分割成多個段,每個段由多個屬性組成,第一個段的屬性集合稱為主屬性集合,其它段稱為普通屬性集合,普通屬性集合一般會有Name屬性,作為該屬性集合所在段的名字。Android的manifeset文件會為zip的所有文件各自建立一個段,這個段的Name屬性的值就是該文件的path+文件名,另外還有一個SHA1-Digest的屬性,該屬性的值是對文件的sha1摘要用base64編碼得到的字符串。

Manifest示例:

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=

Manifest-Version屬性和Created-By所在的段就是主屬性集合,其它屬性集合就是普通屬性集合,這些普通屬性集合都有Name屬性,作為該段的名字。

addDigestsToManifest源代碼:

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 byName = new TreeMap();

for (Enumeration 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);

/*計算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編碼sha1值得到SHA1-Digest屬性的值*/

attr.putValue("SHA1-Digest",

new String(Base64.encode(md.digest()), "ASCII"));

output.getEntries().put(name, attr);

}

}

return output;

}

3)?signFile

先將inputjar的所有文件拷貝至outputjar,然后生成Manifest.MF,CERT.SF和CERT.RSA

public static void signFile(Manifest manifest, JarFile inputJar,

File publicKeyFile, X509Certificate publicKey, PrivateKey privateKey,

JarOutputStream outputJar) throws Exception {

// Assume the certificate is valid for at least an hour.

long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000;

JarEntry je;

// 拷貝文件

copyFiles(manifest, inputJar, outputJar, timestamp);

// 生成MANIFEST.MF

je = new JarEntry(JarFile.MANIFEST_NAME);

je.setTime(timestamp);

outputJar.putNextEntry(je);

manifest.write(outputJar);

// 調用writeSignatureFile 生成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);

// 非常關鍵的一步 生成 CERT.RSA

je = new JarEntry(CERT_RSA_NAME);

je.setTime(timestamp);

outputJar.putNextEntry(je);

writeSignatureBlock(new CMSProcessableByteArray(signedData),

publicKey, privateKey, outputJar);

}

4)?writeSignatureFile

生成CERT.SF,其實是對MANIFEST.MF的各個段再次計算Sha1摘要得到CERT.SF。

private static void writeSignatureFile(Manifest manifest, OutputStream out)

throws IOException, GeneralSecurityException {

Manifest sf = new Manifest();

Attributes main = sf.getMainAttributes();

//添加屬性

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");

// 添加Manifest.mf的sha1摘要

manifest.write(print);

print.flush();

main.putValue("SHA1-Digest-Manifest",

new String(Base64.encode(md.digest()), "ASCII"));

//對MANIFEST.MF的各個段計算sha1摘要

Map entries = manifest.getEntries();

for (Map.Entry entry : entries.entrySet()) {

// Digest of the manifest stanza for this entry.

print.print("Name: " + entry.getKey() + "\r\n");

for (Map.Entry 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

采用SHA1withRSA算法對CERT.SF計算摘要并加密得到數字簽名,使用的私鑰是privateKey,然后將數字簽名和公鑰一起存入CERT.RSA。這里使用了開源庫bouncycastle來簽名。

private static void writeSignatureBlock(

CMSTypedData data, X509Certificate publicKey, PrivateKey privateKey,

OutputStream out)

throws IOException,

CertificateEncodingException,

OperatorCreationException,

CMSException {

ArrayList certList = new ArrayList(1);

certList.add(publicKey);

JcaCertStore certs = new JcaCertStore(certList);

CMSSignedDataGenerator gen = new CMSSignedDataGenerator();

//簽名算法是SHA1withRSA

ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA")

.setProvider(sBouncyCastleProvider)

.build(privateKey);

gen.addSignerInfoGenerator(

new JcaSignerInfoGeneratorBuilder(

new JcaDigestCalculatorProviderBuilder()

.setProvider(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());

}

采用命令行重新簽名APK重新簽名apk,其實也有最簡單的方法,即下載一個重新簽名的工具re-sign.jar,將apk拖進此工具的窗口就生成了重新簽名的apk了。下面我就來講講復雜的重新簽名的方式:采用命令行方法。

一、配置環境,需安裝jdk,sdk

二、在已成功安裝jdk的目錄中找到jarsigner.exe文件,本機的目錄如下:C:\Program Files\Java\jdk1.8.0_20\bin

三、去除準備重新簽名的apk本身的簽名(fantongyo.apk)

將apk以Winrar方式打開,刪除META-INF文件夾即可,并將此Apk文件拷貝至C:\Program Files\Java\jdk1.8.0_20\bin目錄中

Apk壓縮包內容解析:

1.META-INF目錄:存放簽名后的CERT和MANIFEST文件,用于識別軟件的簽名及版本信息

2.rest目錄:存放各種Android原始資源,包括:動畫anim、圖片drawable、布局layout、菜單、xml等等

3.AndroidManifest.xml編碼后的Android項目描述文件,包括了Android項目的名稱、版限、程序組件描述等等

4.Classes.dex編譯后Class被dx程序轉換成Dalvik虛擬機的可執行字節碼文件

5.Resources.arsc所有文本資源的編譯產物,里面包含了各Location對應的字符串資源

四、重新簽名Apk文件

方法一:通過命令重新生成AndroidApk包簽名證書后再重新簽名Apk文件

1.在cmd中切換到jdk的bin目錄中:cd C:\Program Files\Java\jdk1.8.0_20\bin 回車

2.再輸入以下的命令:

Keytool -genkey -alias fantongyo.keystore -keyalg RSA -validity 20000 -keystore fantongyo.keystore

/*解釋:keytool工具是Java JDK自帶的證書工具

-genkey參數表示:要生成一個證書(版權、身份識別的安全證書)

-alias參數表示:證書有別名,-alias fantongyo.keystore表示證書別名為:fantongyo

-keyalg RSA表示加密類型,RSA表示需要加密,以防止別人盜取

-validity 20000表示有效時間20000天( K3

-keystore fantongyo.keystore表示要生成的證書名稱為fantongyo

*/

輸入完回車后屏幕顯示:

輸入keystore密碼:[密碼不回顯](一般建議使用20位,最好記下來后面還要用)

再次輸入新密碼:[密碼不回顯]( o' ^$ _( F( K& I0

您的名字與姓氏是什么?

[Unknown]:fantongyo

您的組織單位名稱是什么?

[Unknown]:fantong

您的組織名稱是什么?

[Unknown]:life

您所在的城市或區域名稱是什么?) L# V' |. E0 f; {

[Unknown]:shenzhen

您所在的州或省份名稱是什么?

[Unknown]:guangdong

該單位的兩字母國家代碼是什么

[Unknown]:CN

CN=fantongyo, U=fantong, O=fantong team, L=shenzhen, ST=guangdong, C=CN正確嗎?

[否]:Y

輸入< mine.keystore>的主密碼

(如果和keystore密碼相同,按回車):

查看C:\Program Files\Java\jdk1.8.0_20\bin目錄下,生成了一個簽名用的證書文件 fantongyo.keystore

3.重新簽名Apk文件

在cmd中輸入:jarsigner –verbose –keystore fantongyo.keystore –signedjar fantongyo_signed.apk fantongyo.apk fantongyo.keystore

/*解釋:* ^, {& k1 Z. M* P/ M+ K5 n5 hjarsigner是Java的簽名工具# K8 ~% s# Y. @6 P

-verbose參數表示:顯示出簽名詳細信息

-keystore表示使用當前目錄中的fantongyo.keystore簽名證書文件。

-signedjar fantongyo_signed.apk表示簽名后生成的APK名稱,% v! a7 e2 v4 W# ]; Gfantongyo.apk表示未簽名 的APK Android軟件,fantongyo.keystore表示別名

*/

輸入完回車后屏幕顯示:

jar已簽名。

在C:\Program Files\Java\jdk1.8.0_20\bin目錄下已重新生成fantongyo_signed.apk文件

方法二、以android自帶的debug.keystore重新簽名Apk文件

1.打開eclipse,菜單欄Window—>Preferences—>Android—>Build—>Default debug keystore目錄(我的編輯器顯示:C:\Users\Administrator\.android\debug.keystore)

2.將debug.keystore文件拷貝至C:\Program Files\Java\jdk1.8.0_20\bin目錄下

3.在cmd中切換到jdk的bin目錄中:cd C:\Program Files\Java\jdk1.8.0_20\bin 回車

4.再輸入以下的命令:

jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore debug.keystore -storepass android -keypass android fantongyo.apk androiddebugkey回車

5.在sdk中找到zipalign文件,我電腦的目錄為:E:\SoftWare\adt-bundle-windows-x86-20140702\sdk\build-tools\android-4.4W

在cmd中切換到sdk的存放zipalign.exe文件的目錄中:

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

6.再輸入:zipalign 4 fantongyo.apk fantongyo_signed.apk即可(fantongyo_signed.apk是?? 重新簽名后的apk文件)

總結

以上是生活随笔為你收集整理的java 1.8签名apk_给Android的APK程序签名和重新签名的方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。