java –jar signapk.jar [-w] publickey.x509[.pem] privatekey.pk8 input.jar output.jar
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 {
//...
}
}
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=
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);
/*计算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;
}
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);
}
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<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');
}
}
private static void writeSignatureBlock(
CMSTypedData data, X509Certificate publicKey, PrivateKey privateKey,
OutputStream out)
throws IOException,
CertificateEncodingException,
OperatorCreationException,
CMSException {
ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>(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());
}
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 */
cd E:\SoftWare\adt-bundle-windows-x86-20140702\sdk\build-tools\android-4.4W
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有