接着上篇,继续来分析签名过程,先看张简易的时序图:
主要对签名时的命令行进行分析:
java -jar signapk.jar platform.x509.pem platform.pk8 **.apk ***.apk
java -jar signapk.jar platform.x509.pem platform.pk8 **.apk ***.apk
注:如果对已签名的apk执行该命令,会重新覆盖已有的签名信息,故印证前面说讲的支持多次签名,以最后一次为准
signapk代码位于android源码路径:
SignApk.java (build\tools\signapk)
是个可执行程序,代码只有514行,具体可参考代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
public
static
void
main(String[] args) {
if
(args.length !=
4
&& args.length !=
5
) {
System.err.println(
"Usage: signapk [-w] "
+
"publickey.x509[.pem] privatekey.pk8 "
+
"input.jar output.jar"
);
System.exit(
2
);
}
boolean
signWholeFile =
false
;
int
argstart =
0
;
if
(args[
0
].equals(
"-w"
)) {
signWholeFile =
true
;
argstart =
1
;
}
JarFile inputJar =
null
;
JarOutputStream outputJar =
null
;
FileOutputStream outputFile =
null
;
try
{
X509Certificate publicKey = readPublicKey(
new
File(args[argstart+
0
]));
// Assume the certificate is valid for at least an hour.
long
timestamp = publicKey.getNotBefore().getTime() + 3600L *
1000
;
PrivateKey privateKey = readPrivateKey(
new
File(args[argstart+
1
]));
inputJar =
new
JarFile(
new
File(args[argstart+
2
]),
false
);
// Don't verify.
OutputStream outputStream =
null
;
if
(signWholeFile) {
outputStream =
new
ByteArrayOutputStream();
}
else
{
outputStream = outputFile =
new
FileOutputStream(args[argstart+
3
]);
}
outputJar =
new
JarOutputStream(outputStream);
outputJar.setLevel(
9
);
JarEntry je;
// MANIFEST.MF
Manifest manifest = addDigestsToManifest(inputJar);
je =
new
JarEntry(JarFile.MANIFEST_NAME);
je.setTime(timestamp);
outputJar.putNextEntry(je);
manifest.write(outputJar);
// CERT.SF
Signature signature = Signature.getInstance(
"SHA1withRSA"
);
signature.initSign(privateKey);
je =
new
JarEntry(CERT_SF_NAME);
je.setTime(timestamp);
outputJar.putNextEntry(je);
writeSignatureFile(manifest,
new
SignatureOutputStream(outputJar, signature));
// CERT.RSA
je =
new
JarEntry(CERT_RSA_NAME);
je.setTime(timestamp);
outputJar.putNextEntry(je);
writeSignatureBlock(signature, publicKey, outputJar);
// Everything else
copyFiles(manifest, inputJar, outputJar, timestamp);
outputJar.close();
outputJar =
null
;
outputStream.flush();
if
(signWholeFile) {
outputFile =
new
FileOutputStream(args[argstart+
3
]);
signWholeOutputFile(((ByteArrayOutputStream)outputStream).toByteArray(),
outputFile, publicKey, privateKey);
}
}
catch
(Exception e) {
e.printStackTrace();
System.exit(
1
);
}
finally
{
try
{
if
(inputJar !=
null
) inputJar.close();
if
(outputFile !=
null
) outputFile.close();
}
catch
(IOException e) {
e.printStackTrace();
System.exit(
1
);
}
}
}
|
1.MANIFEST.MF:保存资源文件的摘要经base64编码后的信息---数字摘要
2.CERT.SF:保存对摘要hash后的信息----数字签名
3.CERT.RSA:保存公钥信息---数字证书
涉及到的类:
Signature.java (frameworks\base\core\java\android\content\pm)
之后设备安装apk,会校验签名,校验过程主要在PackageManagerService中实现
原作者:http://my.oschina.net/blackylin/blog/207480