Embed testkeys into jar

This commit is contained in:
topjohnwu
2018-01-27 00:19:35 +08:00
parent 97cf15007f
commit c61135ee7b
9 changed files with 70 additions and 56 deletions

View File

@@ -15,7 +15,7 @@ jar {
shadowJar {
baseName = 'zipsigner'
classifier = null
version = 1.1
version = 2.0
}
buildscript {
@@ -23,7 +23,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.2'
}
}

View File

@@ -102,7 +102,7 @@ class CryptoUtils {
return signer.sign();
}
static X509Certificate readPublicKey(InputStream input)
static X509Certificate readCertificate(InputStream input)
throws IOException, GeneralSecurityException {
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
@@ -116,9 +116,9 @@ class CryptoUtils {
static PrivateKey readPrivateKey(InputStream input)
throws IOException, GeneralSecurityException {
try {
byte[] buffer = new byte[4096];
int size = input.read(buffer);
byte[] bytes = Arrays.copyOf(buffer, size);
ByteArrayStream buf = new ByteArrayStream();
buf.readFrom(input);
byte[] bytes = buf.toByteArray();
/* Check to see if this is in an EncryptedPrivateKeyInfo structure. */
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
/*

View File

@@ -18,11 +18,9 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.encoders.Base64;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -69,21 +67,27 @@ public class SignAPK {
Security.insertProviderAt(sBouncyCastleProvider, 1);
}
public static void signZip(InputStream publicIn, InputStream privateIn,
public static void signZip(InputStream cert, InputStream key,
JarMap input, OutputStream output, boolean minSign) throws Exception {
int alignment = 4;
int hashes = 0;
X509Certificate publicKey = CryptoUtils.readPublicKey(publicIn);
hashes |= getDigestAlgorithm(publicKey);
if (cert == null) {
cert = SignAPK.class.getResourceAsStream("/keys/testkey.x509.pem");
}
X509Certificate certificate = CryptoUtils.readCertificate(cert);
hashes |= getDigestAlgorithm(certificate);
// Set the ZIP file timestamp to the starting valid time
// of the 0th certificate plus one hour (to match what
// we've historically done).
long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000;
PrivateKey privateKey = CryptoUtils.readPrivateKey(privateIn);
long timestamp = certificate.getNotBefore().getTime() + 3600L * 1000;
if (key == null) {
key = SignAPK.class.getResourceAsStream("/keys/testkey.pk8");
}
PrivateKey privateKey = CryptoUtils.readPrivateKey(key);
if (minSign) {
signWholeFile(input.getFile(), publicKey, privateKey, output);
signWholeFile(input.getFile(), certificate, privateKey, output);
} else {
JarOutputStream outputJar = new JarOutputStream(output);
// For signing .apks, use the maximum compression to make
@@ -95,7 +99,8 @@ public class SignAPK {
outputJar.setLevel(9);
Manifest manifest = addDigestsToManifest(input, hashes);
copyFiles(manifest, input, outputJar, timestamp, alignment);
signFile(manifest, input, publicKey, privateKey, outputJar);
signFile(manifest, input, certificate, privateKey, outputJar);
outputJar.close();
}
}

View File

@@ -35,7 +35,7 @@ public class SignBoot {
}
public static boolean doSignature(String target, InputStream imgIn, OutputStream imgOut,
InputStream keyIn, InputStream certIn) {
InputStream cert, InputStream key) {
try {
ByteArrayStream bas = new ByteArrayStream();
bas.readFrom(imgIn);
@@ -51,23 +51,29 @@ public class SignBoot {
signableSize + " bytes");
}
BootSignature bootsig = new BootSignature(target, image.length);
X509Certificate cert = CryptoUtils.readPublicKey(certIn);
bootsig.setCertificate(cert);
PrivateKey key = CryptoUtils.readPrivateKey(keyIn);
bootsig.setSignature(bootsig.sign(image, key),
CryptoUtils.getSignatureAlgorithmIdentifier(key));
if (cert == null) {
cert = SignBoot.class.getResourceAsStream("/keys/testkey.x509.pem");
}
X509Certificate certificate = CryptoUtils.readCertificate(cert);
bootsig.setCertificate(certificate);
if (key == null) {
key = SignBoot.class.getResourceAsStream("/keys/testkey.pk8");
}
PrivateKey privateKey = CryptoUtils.readPrivateKey(key);
bootsig.setSignature(bootsig.sign(image, privateKey),
CryptoUtils.getSignatureAlgorithmIdentifier(privateKey));
byte[] encoded_bootsig = bootsig.getEncoded();
imgOut.write(image);
imgOut.write(encoded_bootsig);
imgOut.flush();
return true;
} catch (Exception e) {
e.printStackTrace(System.err);
e.printStackTrace();
return false;
}
}
public static boolean verifySignature(InputStream imgIn, InputStream certPath) {
public static boolean verifySignature(InputStream imgIn, InputStream certIn) {
try {
ByteArrayStream bas = new ByteArrayStream();
bas.readFrom(imgIn);
@@ -80,8 +86,8 @@ public class SignBoot {
}
byte[] signature = Arrays.copyOfRange(image, signableSize, image.length);
BootSignature bootsig = new BootSignature(signature);
if (certPath != null) {
bootsig.setCertificate(CryptoUtils.readPublicKey(certPath));
if (certIn != null) {
bootsig.setCertificate(CryptoUtils.readCertificate(certIn));
}
if (bootsig.verify(Arrays.copyOf(image, signableSize))) {
System.err.println("Signature is VALID");
@@ -90,7 +96,6 @@ public class SignBoot {
System.err.println("Signature is INVALID");
}
} catch (Exception e) {
e.printStackTrace(System.err);
System.err.println("Invalid image: not signed");
}
return false;

View File

@@ -2,44 +2,58 @@ package com.topjohnwu.crypto;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.Security;
public class ZipSigner {
public static void main(String[] args) {
public static void usage() {
System.err.println("Usage: zipsigner [-m] [x509.pem] [pk8] input.jar output.jar");
System.err.println("If no certificate/private key pair is specified, it will use the embedded test keys.");
System.err.println(" -m: enable minimal signing");
System.exit(2);
}
public static void main(String[] args) throws Exception {
boolean minSign = false;
int argStart = 0;
if (args.length < 4) {
System.err.println("Usage: zipsigner [-m] publickey.x509[.pem] privatekey.pk8 input.jar output.jar");
System.exit(2);
}
if (args.length < 2)
usage();
if (args[0].equals("-m")) {
minSign = true;
argStart = 1;
}
InputStream cert = null;
InputStream key = null;
if (args.length - argStart == 4) {
cert = new BufferedInputStream(new FileInputStream(new File(args[argStart])));
key = new BufferedInputStream(new FileInputStream(new File(args[argStart + 1])));
argStart += 2;
}
if (args.length - argStart != 2)
usage();
SignAPK.sBouncyCastleProvider = new BouncyCastleProvider();
Security.insertProviderAt(SignAPK.sBouncyCastleProvider, 1);
File pubKey = new File(args[argStart]);
File privKey = new File(args[argStart + 1]);
File input = new File(args[argStart + 2]);
File output = new File(args[argStart + 3]);
File input = new File(args[argStart]);
File output = new File(args[argStart + 1]);
try (InputStream pub = new FileInputStream(pubKey);
InputStream priv = new FileInputStream(privKey);
JarMap jar = new JarMap(input, false);
try (JarMap jar = new JarMap(input, false);
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(output))) {
SignAPK.signZip(pub, priv, jar, out, minSign);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
SignAPK.signZip(cert, key, jar, out, minSign);
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET
MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM
qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4
wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy
4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU
RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s
zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw
HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ
AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud
EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa
J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y
LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe
+ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX
31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr
sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0=
-----END CERTIFICATE-----