接着上篇,继续来分析签名过程,先看张简易的时序图:
主要对签名时的命令行进行分析:
java -jar signapk.jar platform.x509.pem platform.pk8 **.apk ***.apk
注:如果对已签名的apk执行该命令,会重新覆盖已有的签名信息,故印证前面说讲的支持多次签名,以最后一次为准
signapk代码位于android源码路径:
SignApk.java (build\tools\signapk)
是个可执行程序,代码只有514行,具体可参考代码。
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中实现