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已签名。

eafbee39909ba1e962e1227d9e820c81.png

在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文件)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/344502.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【渝粤教育】电大中专职业生涯规划 (3)作业 题库

1职业价值观具有明确的目的性、&#xff08; &#xff09;和坚定性的职业选择的态度和行为。 A自由性 B动机性 C自觉性 D制约性 错误 正确答案&#xff1a;左边查询 学生答案&#xff1a;A 2不属于探索价值观方法的是&#xff08; &#xff09;。 A澄清反应法 B意见表决法 C间接…

使用Oracle验证外部数据

我经常在Corda Slack频道中闲逛&#xff0c;并尽可能回答问题。 我尝试回答的合理数量的问题与Oracle有关。 更具体地说&#xff0c;何时使用一个。 我觉得我可以回答&#xff0c;“当您需要验证可能经常更改的外部数据时使用Oracle”。 我可能在某个时候写了一个类似的答案。 …

【渝粤教育】电大中专药理学基础 (2)_1作业 题库

1.关于苯二氮卓类镇静催眠药的叙述&#xff0c;不正确的是&#xff08;&#xff09;。 A.长期应用不会产生依赖性和成瘾性 B.是目前最常用的镇静催眠药 C.可用于治疗小儿高热惊厥 D.临床上用于治疗焦虑症 E.可用于心脏电复律前给药 错误 正确答案&#xff1a;左边查询 学生答案…

【渝粤教育】电大中专计算机职业素养 (11)作业 题库

1.用冰山模型说明职业素养构成时&#xff0c;我们把浮在水面上面的知识、技能等部分称为&#xff08; &#xff09;的职业素养。 A.获得 B.显性 C.专业 D.隐性 错误 正确答案&#xff1a;左边查询 学生答案&#xff1a;A 2.职业素养的基本内容包括&#xff1a;职业道德、职业意…

java 2d 教程_Java 2D开发技巧之“灯光与阴影”

Java 2D开发技巧之“灯光与阴影”(2016-12-14 02:12:25)标签&#xff1a;杂谈一、 引言在本文中&#xff0c;我们将向你展示如何为扁平形状添加一种灯光效果以实现一种类3D外观。也许你比较满意于自己的文字表达能力&#xff0c;但一幅图片往往能够产生更好的效果。对于图形处理…

【渝粤教育】电大中专跨境电子商务理论与实务 (17)作业 题库

1.在按照交易主体类型中&#xff0c;&#xff08; &#xff09;面对的最终客户为企业或集团客户&#xff0c;提供企业、产品、服务等相关信息。 A.C2C跨境电商或平台 B.B2C跨境电商或平台 C.O2O跨境电商或平台 D.B2B跨境电商或平台 错误 正确答案&#xff1a;左边查询 学生答案…

jooq代码生成_将jOOQ与Spring结合使用:代码生成

jooq代码生成我们可能在本教程的第一部分中还记得jOOQ指出 jOOQ从您的数据库生成Java代码&#xff0c;并允许您通过其流畅的API构建类型安全SQL查询。 本教程的第一部分描述了如何配置使用jOOQ的Spring驱动的应用程序的应用程序上下文&#xff0c;但没有描述如何使用jOOQ创建类…

【渝粤题库】陕西师范大学151109财务报告分析 作业(高起专)

《财务分析》作业 一、单选题 1.以下哪个不属于杜邦分析法的优点&#xff08; &#xff09;。 2.以下哪个不是比率的具体表现形式&#xff08; &#xff09;。 3.根据财务报表的审计结果&#xff0c;具有较大可信度的审计意见类型是&#xff08; &#xff09;。 4.关于杠杆的…

【渝粤题库】陕西师范大学200131中国古代文论 作业(专升本)

《中国古代文论》作业 一、注明下列文献的作者及年代&#xff1a; 1、《典论论文》 2、《文选序》 3、《戏为六绝句》 5、《与元九书》 6、《送孟东野序》 7、《六一诗话》 8、《雪涛阁集序》 9、《文赋》 10、《诗品》 11、《诗品序》 12、《文心雕龙》 13、《沧浪诗话》 14、…

java连接到mysql_[操作系统]Java如何连接到MySQL数据库的

[操作系统]Java如何连接到MySQL数据库的0 2016-05-01 15:00:15下载&#xff1a;mysql-connector-java-5.1.38.tar.gzhttp://dev.mysql.com/downloads/connector/j/tar zxvfmysql-connector-java-5.1.38.tar.gz解压后zhouspubuntu:~/Downloads$cd ./mysql-connector-java-5.1.38…

Spark Run本地设计模式

现在&#xff0c;许多Spark应用程序已成为遗留应用程序&#xff0c;很难在本地进行增强&#xff0c;测试和运行。 Spark具有很好的测试支持&#xff0c;但仍有许多Spark应用程序不可测试。 当您尝试运行一些旧的Spark应用程序时&#xff0c;我将分享一个常见错误。 Exceptio…

【渝粤题库】陕西师范大学201771 中国古代文学(一) 作业

《中国古代文学&#xff08;一&#xff09;》作业 一、单选题&#xff08;共30小题&#xff0c;每题2分&#xff0c;共60分&#xff09; 1、先秦以“笔法”、“微言大义”著称于世的史书是&#xff08; &#xff09; A《尚书》 B《国语》 C《春秋》 D《战国策》 2、汉代“四家诗…

mave本地导入mysql的jar包_将本地的jar包引入到maven项目中

首先进入到maven的目录下&#xff0c;并且将要引入的jar包也放在这个目录下然后执行命令mvn install:install-file -DfilecheckDataAdapter-api.jar -DgroupIdorg.cegn.des -DartifactIdcheckDataAdapter-api -Dversion2.0 -Dpackagingjar等到success成功后&#xff0c;在maven…

【渝粤教育】广东开放大学 网页设计与制作 形成性考核 (25)

选择题 题目&#xff1a; 当链接指向下列哪一种文件时&#xff0c;不打开该文件&#xff0c;而是提供给浏览器下载&#xff1f;( ) 答案&#xff1a;看左侧 题目&#xff1a; 若要获得名为login的表单中名为txtuser的文本输入框的值&#xff0c;以下获取方法中&#xff0c;正…

mysql导入创建表空间_oracle创建表空间 导入数据库

oracle2 然后是创建表空间创建表空间需要创建两个一个临时表空间 一个表空间--创建表空间create tablespace abc datafile ‘D:\tablespce\LANDHIGH_SFTMS.dbf‘ size 500m;--创建用户并指定表空间create user admin identified by admin default tablespace abc quota 500m …

【渝粤教育】广东开放大学 软件工程 形成性考核 (50)

选择题 题目&#xff1a; 关于协作图的描述&#xff0c;下列哪个不正确&#xff08;&#xff09; 题目&#xff1a;多对象是UML哪个视图中的概念&#xff08; &#xff09;。 题目&#xff1a;在UML中&#xff0c;接口有几种表达方式&#xff08;&#xff09;。 题目&#xff1…

java集合根据值排序_Java 8:对集合中的值进行排序

java集合根据值排序意识到Java 8将在接下来的几周内发布其GA版本之后&#xff0c;我认为现在是时候来看看它了&#xff0c;在过去的一周里&#xff0c;我一直在阅读Venkat Subramaniam的书 。 我要讲的是第3章&#xff0c;它涉及对人员集合进行排序。 Person类的定义大致如下&…

【渝粤教育】广东开放大学民事诉讼法 形成性考核 (23)

选择题 题目&#xff1a; 调解的双方当事人依照人民调解等法律&#xff0c;自调解协议生效之日起三十日内&#xff0c;可共同向&#xff08; &#xff09;申请司法确认。 答案&#xff1a;看左侧 题目&#xff1a; 根据我国民事诉讼法的规定&#xff0c;当事人可以书面协议选…

【渝粤题库】广东开放大学 建筑制图 形成性考核

选择题 题目&#xff1a;标注坡度可用&#xff08;&#xff09;&#xff0c;百分数&#xff0c;分数等三种形式。 题目&#xff1a;以下哪种工具不属于常用绘图工具()。 题目&#xff1a;H面上产生的投影叫作&#xff08;&#xff09;。 题目&#xff1a;下列关于投影叙述正确的…

Java线程的不同状态

介绍 在Java中&#xff0c;线程可以具有状态。 Thread.State枚举定义Java线程可以具有的不同状态。 该枚举定义了以下值– 新 可运行 已封锁 等候 TIMED_WAITING 已终止 在接下来的部分中&#xff0c;我将简要概述这些状态以及它们之间的可能过渡。 Java线程的状态 新 …