Search in sources :

Example 1 with MinSdkVersionException

use of com.android.apksig.apk.MinSdkVersionException in project AndResGuard by shwenzhang.

the class ApkSignerTool method sign.

private static void sign(String[] params) throws Exception {
    if (params.length == 0) {
        printUsage(HELP_PAGE_SIGN);
        return;
    }
    File outputApk = null;
    File inputApk = null;
    boolean verbose = false;
    boolean v1SigningEnabled = true;
    boolean v2SigningEnabled = true;
    int minSdkVersion = 1;
    boolean minSdkVersionSpecified = false;
    int maxSdkVersion = Integer.MAX_VALUE;
    List<SignerParams> signers = new ArrayList<>(1);
    SignerParams signerParams = new SignerParams();
    OptionsParser optionsParser = new OptionsParser(params);
    String optionName;
    String optionOriginalForm = null;
    while ((optionName = optionsParser.nextOption()) != null) {
        optionOriginalForm = optionsParser.getOptionOriginalForm();
        if (("help".equals(optionName)) || ("h".equals(optionName))) {
            printUsage(HELP_PAGE_SIGN);
            return;
        } else if ("out".equals(optionName)) {
            outputApk = new File(optionsParser.getRequiredValue("Output file name"));
        } else if ("in".equals(optionName)) {
            inputApk = new File(optionsParser.getRequiredValue("Input file name"));
        } else if ("min-sdk-version".equals(optionName)) {
            minSdkVersion = optionsParser.getRequiredIntValue("Mininimum API Level");
            minSdkVersionSpecified = true;
        } else if ("max-sdk-version".equals(optionName)) {
            maxSdkVersion = optionsParser.getRequiredIntValue("Maximum API Level");
        } else if ("v1-signing-enabled".equals(optionName)) {
            v1SigningEnabled = optionsParser.getOptionalBooleanValue(true);
        } else if ("v2-signing-enabled".equals(optionName)) {
            v2SigningEnabled = optionsParser.getOptionalBooleanValue(true);
        } else if ("next-signer".equals(optionName)) {
            if (!signerParams.isEmpty()) {
                signers.add(signerParams);
                signerParams = new SignerParams();
            }
        } else if ("ks".equals(optionName)) {
            signerParams.keystoreFile = optionsParser.getRequiredValue("KeyStore file");
        } else if ("ks-key-alias".equals(optionName)) {
            signerParams.keystoreKeyAlias = optionsParser.getRequiredValue("KeyStore key alias");
        } else if ("ks-pass".equals(optionName)) {
            signerParams.keystorePasswordSpec = optionsParser.getRequiredValue("KeyStore password");
        } else if ("key-pass".equals(optionName)) {
            signerParams.keyPasswordSpec = optionsParser.getRequiredValue("Key password");
        } else if ("v1-signer-name".equals(optionName)) {
            signerParams.v1SigFileBasename = optionsParser.getRequiredValue("JAR signature file basename");
        } else if ("ks-type".equals(optionName)) {
            signerParams.keystoreType = optionsParser.getRequiredValue("KeyStore type");
        } else if ("ks-provider-name".equals(optionName)) {
            signerParams.keystoreProviderName = optionsParser.getRequiredValue("JCA KeyStore Provider name");
        } else if ("ks-provider-class".equals(optionName)) {
            signerParams.keystoreProviderClass = optionsParser.getRequiredValue("JCA KeyStore Provider class name");
        } else if ("ks-provider-arg".equals(optionName)) {
            signerParams.keystoreProviderArg = optionsParser.getRequiredValue("JCA KeyStore Provider constructor argument");
        } else if ("key".equals(optionName)) {
            signerParams.keyFile = optionsParser.getRequiredValue("Private key file");
        } else if ("cert".equals(optionName)) {
            signerParams.certFile = optionsParser.getRequiredValue("Certificate file");
        } else if (("v".equals(optionName)) || ("verbose".equals(optionName))) {
            verbose = optionsParser.getOptionalBooleanValue(true);
        } else {
            throw new ParameterException("Unsupported option: " + optionOriginalForm + ". See --help for supported" + " options.");
        }
    }
    if (!signerParams.isEmpty()) {
        signers.add(signerParams);
    }
    signerParams = null;
    if (signers.isEmpty()) {
        throw new ParameterException("At least one signer must be specified");
    }
    params = optionsParser.getRemainingParams();
    if (inputApk != null) {
        // parameters.
        if (params.length > 0) {
            throw new ParameterException("Unexpected parameter(s) after " + optionOriginalForm + ": " + params[0]);
        }
    } else {
        // supposed to be the path to input APK.
        if (params.length < 1) {
            throw new ParameterException("Missing input APK");
        } else if (params.length > 1) {
            throw new ParameterException("Unexpected parameter(s) after input APK (" + params[1] + ")");
        }
        inputApk = new File(params[0]);
    }
    if ((minSdkVersionSpecified) && (minSdkVersion > maxSdkVersion)) {
        throw new ParameterException("Min API Level (" + minSdkVersion + ") > max API Level (" + maxSdkVersion + ")");
    }
    List<ApkSigner.SignerConfig> signerConfigs = new ArrayList<>(signers.size());
    int signerNumber = 0;
    try (PasswordRetriever passwordRetriever = new PasswordRetriever()) {
        for (SignerParams signer : signers) {
            signerNumber++;
            signer.name = "signer #" + signerNumber;
            try {
                signer.loadPrivateKeyAndCerts(passwordRetriever);
            } catch (ParameterException e) {
                System.err.println("Failed to load signer \"" + signer.name + "\": " + e.getMessage());
                System.exit(2);
                return;
            } catch (Exception e) {
                System.err.println("Failed to load signer \"" + signer.name + "\"");
                e.printStackTrace();
                System.exit(2);
                return;
            }
            String v1SigBasename;
            if (signer.v1SigFileBasename != null) {
                v1SigBasename = signer.v1SigFileBasename;
            } else if (signer.keystoreKeyAlias != null) {
                v1SigBasename = signer.keystoreKeyAlias;
            } else if (signer.keyFile != null) {
                String keyFileName = new File(signer.keyFile).getName();
                int delimiterIndex = keyFileName.indexOf('.');
                if (delimiterIndex == -1) {
                    v1SigBasename = keyFileName;
                } else {
                    v1SigBasename = keyFileName.substring(0, delimiterIndex);
                }
            } else {
                throw new RuntimeException("Neither KeyStore key alias nor private key file available");
            }
            ApkSigner.SignerConfig signerConfig = new ApkSigner.SignerConfig.Builder(v1SigBasename, signer.privateKey, signer.certs).build();
            signerConfigs.add(signerConfig);
        }
    }
    if (outputApk == null) {
        outputApk = inputApk;
    }
    File tmpOutputApk;
    if (inputApk.getCanonicalPath().equals(outputApk.getCanonicalPath())) {
        tmpOutputApk = File.createTempFile("apksigner", ".apk");
        tmpOutputApk.deleteOnExit();
    } else {
        tmpOutputApk = outputApk;
    }
    ApkSigner.Builder apkSignerBuilder = new ApkSigner.Builder(signerConfigs).setInputApk(inputApk).setOutputApk(tmpOutputApk).setOtherSignersSignaturesPreserved(false).setV1SigningEnabled(v1SigningEnabled).setV2SigningEnabled(v2SigningEnabled);
    if (minSdkVersionSpecified) {
        apkSignerBuilder.setMinSdkVersion(minSdkVersion);
    }
    ApkSigner apkSigner = apkSignerBuilder.build();
    try {
        apkSigner.sign();
    } catch (MinSdkVersionException e) {
        String msg = e.getMessage();
        if (!msg.endsWith(".")) {
            msg += '.';
        }
        throw new MinSdkVersionException("Failed to determine APK's minimum supported platform version" + ". Use --min-sdk-version to override", e);
    }
    if (!tmpOutputApk.getCanonicalPath().equals(outputApk.getCanonicalPath())) {
        Files.move(tmpOutputApk.toPath(), outputApk.toPath(), StandardCopyOption.REPLACE_EXISTING);
    }
    if (verbose) {
        System.out.println("Signed");
    }
}
Also used : ArrayList(java.util.ArrayList) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) KeyStoreException(java.security.KeyStoreException) UnrecoverableKeyException(java.security.UnrecoverableKeyException) MinSdkVersionException(com.android.apksig.apk.MinSdkVersionException) IOException(java.io.IOException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) InvalidKeyException(java.security.InvalidKeyException) File(java.io.File) ApkSigner(com.android.apksig.ApkSigner) MinSdkVersionException(com.android.apksig.apk.MinSdkVersionException)

Example 2 with MinSdkVersionException

use of com.android.apksig.apk.MinSdkVersionException in project AndResGuard by shwenzhang.

the class ApkSignerTool method verify.

private static void verify(String[] params) throws Exception {
    if (params.length == 0) {
        printUsage(HELP_PAGE_VERIFY);
        return;
    }
    File inputApk = null;
    int minSdkVersion = 1;
    boolean minSdkVersionSpecified = false;
    int maxSdkVersion = Integer.MAX_VALUE;
    boolean maxSdkVersionSpecified = false;
    boolean printCerts = false;
    boolean verbose = false;
    boolean warningsTreatedAsErrors = false;
    OptionsParser optionsParser = new OptionsParser(params);
    String optionName;
    String optionOriginalForm = null;
    while ((optionName = optionsParser.nextOption()) != null) {
        optionOriginalForm = optionsParser.getOptionOriginalForm();
        if ("min-sdk-version".equals(optionName)) {
            minSdkVersion = optionsParser.getRequiredIntValue("Mininimum API Level");
            minSdkVersionSpecified = true;
        } else if ("max-sdk-version".equals(optionName)) {
            maxSdkVersion = optionsParser.getRequiredIntValue("Maximum API Level");
            maxSdkVersionSpecified = true;
        } else if ("print-certs".equals(optionName)) {
            printCerts = optionsParser.getOptionalBooleanValue(true);
        } else if (("v".equals(optionName)) || ("verbose".equals(optionName))) {
            verbose = optionsParser.getOptionalBooleanValue(true);
        } else if ("Werr".equals(optionName)) {
            warningsTreatedAsErrors = optionsParser.getOptionalBooleanValue(true);
        } else if (("help".equals(optionName)) || ("h".equals(optionName))) {
            printUsage(HELP_PAGE_VERIFY);
            return;
        } else if ("in".equals(optionName)) {
            inputApk = new File(optionsParser.getRequiredValue("Input APK file"));
        } else {
            throw new ParameterException("Unsupported option: " + optionOriginalForm + ". See --help for supported" + " options.");
        }
    }
    params = optionsParser.getRemainingParams();
    if (inputApk != null) {
        // parameters.
        if (params.length > 0) {
            throw new ParameterException("Unexpected parameter(s) after " + optionOriginalForm + ": " + params[0]);
        }
    } else {
        // supposed to be the input APK.
        if (params.length < 1) {
            throw new ParameterException("Missing APK");
        } else if (params.length > 1) {
            throw new ParameterException("Unexpected parameter(s) after APK (" + params[1] + ")");
        }
        inputApk = new File(params[0]);
    }
    if ((minSdkVersionSpecified) && (maxSdkVersionSpecified) && (minSdkVersion > maxSdkVersion)) {
        throw new ParameterException("Min API Level (" + minSdkVersion + ") > max API Level (" + maxSdkVersion + ")");
    }
    ApkVerifier.Builder apkVerifierBuilder = new ApkVerifier.Builder(inputApk);
    if (minSdkVersionSpecified) {
        apkVerifierBuilder.setMinCheckedPlatformVersion(minSdkVersion);
    }
    if (maxSdkVersionSpecified) {
        apkVerifierBuilder.setMaxCheckedPlatformVersion(maxSdkVersion);
    }
    ApkVerifier apkVerifier = apkVerifierBuilder.build();
    ApkVerifier.Result result;
    try {
        result = apkVerifier.verify();
    } catch (MinSdkVersionException e) {
        String msg = e.getMessage();
        if (!msg.endsWith(".")) {
            msg += '.';
        }
        throw new MinSdkVersionException("Failed to determine APK's minimum supported platform version" + ". Use --min-sdk-version to override", e);
    }
    boolean verified = result.isVerified();
    boolean warningsEncountered = false;
    if (verified) {
        List<X509Certificate> signerCerts = result.getSignerCertificates();
        if (verbose) {
            System.out.println("Verifies");
            System.out.println("Verified using v1 scheme (JAR signing): " + result.isVerifiedUsingV1Scheme());
            System.out.println("Verified using v2 scheme (APK Signature Scheme v2): " + result.isVerifiedUsingV2Scheme());
            System.out.println("Number of signers: " + signerCerts.size());
        }
        if (printCerts) {
            int signerNumber = 0;
            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
            MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            for (X509Certificate signerCert : signerCerts) {
                signerNumber++;
                System.out.println("Signer #" + signerNumber + " certificate DN" + ": " + signerCert.getSubjectDN());
                byte[] encodedCert = signerCert.getEncoded();
                System.out.println("Signer #" + signerNumber + " certificate SHA-256 digest: " + HexEncoding.encode(sha256.digest(encodedCert)));
                System.out.println("Signer #" + signerNumber + " certificate SHA-1 digest: " + HexEncoding.encode(sha1.digest(encodedCert)));
                System.out.println("Signer #" + signerNumber + " certificate MD5 digest: " + HexEncoding.encode(md5.digest(encodedCert)));
                if (verbose) {
                    PublicKey publicKey = signerCert.getPublicKey();
                    System.out.println("Signer #" + signerNumber + " key algorithm: " + publicKey.getAlgorithm());
                    int keySize = -1;
                    if (publicKey instanceof RSAKey) {
                        keySize = ((RSAKey) publicKey).getModulus().bitLength();
                    } else if (publicKey instanceof ECKey) {
                        keySize = ((ECKey) publicKey).getParams().getOrder().bitLength();
                    } else if (publicKey instanceof DSAKey) {
                        // DSA parameters may be inherited from the certificate. We
                        // don't handle this case at the moment.
                        DSAParams dsaParams = ((DSAKey) publicKey).getParams();
                        if (dsaParams != null) {
                            keySize = dsaParams.getP().bitLength();
                        }
                    }
                    System.out.println("Signer #" + signerNumber + " key size (bits): " + ((keySize != -1) ? String.valueOf(keySize) : "n/a"));
                    byte[] encodedKey = publicKey.getEncoded();
                    System.out.println("Signer #" + signerNumber + " public key SHA-256 digest: " + HexEncoding.encode(sha256.digest(encodedKey)));
                    System.out.println("Signer #" + signerNumber + " public key SHA-1 digest: " + HexEncoding.encode(sha1.digest(encodedKey)));
                    System.out.println("Signer #" + signerNumber + " public key MD5 digest: " + HexEncoding.encode(md5.digest(encodedKey)));
                }
            }
        }
    } else {
        System.err.println("DOES NOT VERIFY");
    }
    for (ApkVerifier.IssueWithParams error : result.getErrors()) {
        System.err.println("ERROR: " + error);
    }
    // false positive -- this resource is not opened here
    @SuppressWarnings("resource") PrintStream warningsOut = (warningsTreatedAsErrors) ? System.err : System.out;
    for (ApkVerifier.IssueWithParams warning : result.getWarnings()) {
        warningsEncountered = true;
        warningsOut.println("WARNING: " + warning);
    }
    for (ApkVerifier.Result.V1SchemeSignerInfo signer : result.getV1SchemeSigners()) {
        String signerName = signer.getName();
        for (ApkVerifier.IssueWithParams error : signer.getErrors()) {
            System.err.println("ERROR: JAR signer " + signerName + ": " + error);
        }
        for (ApkVerifier.IssueWithParams warning : signer.getWarnings()) {
            warningsEncountered = true;
            warningsOut.println("WARNING: JAR signer " + signerName + ": " + warning);
        }
    }
    for (ApkVerifier.Result.V2SchemeSignerInfo signer : result.getV2SchemeSigners()) {
        String signerName = "signer #" + (signer.getIndex() + 1);
        for (ApkVerifier.IssueWithParams error : signer.getErrors()) {
            System.err.println("ERROR: APK Signature Scheme v2 " + signerName + ": " + error);
        }
        for (ApkVerifier.IssueWithParams warning : signer.getWarnings()) {
            warningsEncountered = true;
            warningsOut.println("WARNING: APK Signature Scheme v2 " + signerName + ": " + warning);
        }
    }
    if (!verified) {
        System.exit(1);
        return;
    }
    if ((warningsTreatedAsErrors) && (warningsEncountered)) {
        System.exit(1);
        return;
    }
}
Also used : RSAKey(java.security.interfaces.RSAKey) ECKey(java.security.interfaces.ECKey) DSAParams(java.security.interfaces.DSAParams) DSAKey(java.security.interfaces.DSAKey) MessageDigest(java.security.MessageDigest) MinSdkVersionException(com.android.apksig.apk.MinSdkVersionException) PrintStream(java.io.PrintStream) PublicKey(java.security.PublicKey) X509Certificate(java.security.cert.X509Certificate) ApkVerifier(com.android.apksig.ApkVerifier) File(java.io.File)

Aggregations

MinSdkVersionException (com.android.apksig.apk.MinSdkVersionException)2 File (java.io.File)2 ApkSigner (com.android.apksig.ApkSigner)1 ApkVerifier (com.android.apksig.ApkVerifier)1 IOException (java.io.IOException)1 PrintStream (java.io.PrintStream)1 InvalidKeyException (java.security.InvalidKeyException)1 KeyStoreException (java.security.KeyStoreException)1 MessageDigest (java.security.MessageDigest)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 PublicKey (java.security.PublicKey)1 UnrecoverableKeyException (java.security.UnrecoverableKeyException)1 X509Certificate (java.security.cert.X509Certificate)1 DSAKey (java.security.interfaces.DSAKey)1 DSAParams (java.security.interfaces.DSAParams)1 ECKey (java.security.interfaces.ECKey)1 RSAKey (java.security.interfaces.RSAKey)1 InvalidKeySpecException (java.security.spec.InvalidKeySpecException)1 ArrayList (java.util.ArrayList)1