diff --git a/app/build.gradle b/app/build.gradle index 4f860b825a..c411aaf02a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,3 @@ -import org.signal.signing.ApkSignerUtil - -import java.security.MessageDigest - apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' @@ -532,67 +528,6 @@ dependencyVerification { configuration = '(play|website)(Prod|Staging)(Debug|Release)RuntimeClasspath' } -def assembleWebsiteDescriptor = { variant, file -> - if (file.exists()) { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - file.eachByte 4096, {bytes, size -> - md.update(bytes, 0, size); - } - - String digest = md.digest().collect {String.format "%02x", it}.join(); - String url = variant.productFlavors.get(0).ext.websiteUpdateUrl - String apkName = file.getName() - - String descriptor = "{" + - "\"versionCode\" : ${canonicalVersionCode * postFixSize + abiPostFix['universal']}," + - "\"versionName\" : \"$canonicalVersionName\"," + - "\"sha256sum\" : \"$digest\"," + - "\"url\" : \"$url/$apkName\"" + - "}" - - File descriptorFile = new File(file.getParent(), apkName.replace(".apk", ".json")) - - descriptorFile.write(descriptor) - } -} - -def signProductionRelease = { variant -> - variant.outputs.collect { output -> - String apkName = output.outputFile.name - File inputFile = new File(output.outputFile.path) - File outputFile = new File(output.outputFile.parent, apkName.replace('-unsigned', '')) - - new ApkSignerUtil('sun.security.pkcs11.SunPKCS11', - 'pkcs11.config', - 'PKCS11', - 'file:pkcs11.password').calculateSignature(inputFile.getAbsolutePath(), - outputFile.getAbsolutePath()) - - inputFile.delete() - outputFile - } -} - -task signProductionPlayRelease { - doLast { - signProductionRelease(android.applicationVariants.find { (it.name == 'playProdRelease') }) - } -} - -task signProductionInternalRelease { - doLast { - signProductionRelease(android.applicationVariants.find { (it.name == 'internalProdRelease') }) - } -} - -task signProductionWebsiteRelease { - doLast { - def variant = android.applicationVariants.find { (it.name == 'websiteProdRelease') } - File signedRelease = signProductionRelease(variant).find { it.name.contains('universal') } - assembleWebsiteDescriptor(variant, signedRelease) - } -} - def getLastCommitTimestamp() { if (!(new File('.git').exists())) { return System.currentTimeMillis().toString() diff --git a/buildSrc/src/main/java/org/signal/signing/ApkSignerUtil.java b/buildSrc/src/main/java/org/signal/signing/ApkSignerUtil.java deleted file mode 100644 index 144d55e17b..0000000000 --- a/buildSrc/src/main/java/org/signal/signing/ApkSignerUtil.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.signal.signing; - -import com.android.apksig.ApkSigner; -import com.android.apksig.apk.ApkFormatException; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.security.InvalidKeyException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.Provider; -import java.security.Security; -import java.security.SignatureException; -import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Collections; -import java.util.Enumeration; -import java.util.LinkedList; -import java.util.List; - -public class ApkSignerUtil { - - private final String providerClass; - - private final String providerArgument; - - private final String keyStoreType; - - private final String keyStorePassword; - - - public ApkSignerUtil(String providerClass, String providerArgument, String keyStoreType, String keyStorePassword) { - this.providerClass = providerClass; - this.providerArgument = providerArgument; - this.keyStoreType = keyStoreType; - this.keyStorePassword = keyStorePassword; - } - - public void calculateSignature(String inputApkFile, String outputApkFile) - throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, ApkFormatException, InvalidKeyException, SignatureException - { - System.out.println("Running calculateSignature()..."); - - if (providerClass != null) { - installProvider(providerClass, providerArgument); - } - - ApkSigner apkSigner = new ApkSigner.Builder(Collections.singletonList(loadKeyStore(keyStoreType, keyStorePassword))) - .setV1SigningEnabled(true) - .setV2SigningEnabled(true) - .setInputApk(new File(inputApkFile)) - .setOutputApk(new File(outputApkFile)) - .setOtherSignersSignaturesPreserved(false) - .build(); - - apkSigner.sign(); - } - - private void installProvider(String providerName, String providerArgument) { - try { - Class providerClass = Class.forName(providerName); - - if (!Provider.class.isAssignableFrom(providerClass)) { - throw new IllegalArgumentException("JCA Provider class " + providerClass + " not subclass of " + Provider.class.getName()); - } - - Provider provider; - - if (providerArgument != null) { - provider = (Provider) providerClass.getConstructor(String.class).newInstance(providerArgument); - } else { - provider = (Provider) providerClass.getConstructor().newInstance(); - } - - Security.addProvider(provider); - } catch (ClassNotFoundException | InstantiationException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { - throw new IllegalArgumentException(e); - } - } - - private ApkSigner.SignerConfig loadKeyStore(String keyStoreType, String keyStorePassword) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException { - KeyStore keyStoreEntity = KeyStore.getInstance(keyStoreType == null ? KeyStore.getDefaultType() : keyStoreType); - char[] password = getPassword(keyStorePassword); - keyStoreEntity.load(null, password); - - Enumeration aliases = keyStoreEntity.aliases(); - String keyAlias = null; - - while (aliases != null && aliases.hasMoreElements()) { - String alias = aliases.nextElement(); - if (keyStoreEntity.isKeyEntry(alias)) { - keyAlias = alias; - break; - } - } - - if (keyAlias == null) { - throw new IllegalArgumentException("Keystore has no key entries!"); - } - - PrivateKey privateKey = (PrivateKey) keyStoreEntity.getKey(keyAlias, password); - Certificate[] certificates = keyStoreEntity.getCertificateChain(keyAlias); - - if (certificates == null || certificates.length == 0) { - throw new IllegalArgumentException("Unable to load certificates!"); - } - - List results = new LinkedList<>(); - - for (Certificate certificate : certificates) { - results.add((X509Certificate)certificate); - } - - - return new ApkSigner.SignerConfig.Builder("Signal Signer", privateKey, results).build(); - } - - private char[] getPassword(String encoded) throws IOException { - if (encoded.startsWith("file:")) { - String name = encoded.substring("file:".length()); - BufferedReader reader = new BufferedReader(new FileReader(new File(name))); - String password = reader.readLine(); - - if (password.length() == 0) { - throw new IOException("Failed to read password from file: " + name); - } - - return password.toCharArray(); - } else { - return encoded.toCharArray(); - } - } - -}