Snap for 6439596 from 83eec36412695949f24be9d917ed7ba26fff3f5c to qt-aml-tzdata-release

Change-Id: I4ca13275f341d48b2c034e427f6ef846b89bf392
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..7e39c8e
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,48 @@
+# Bazel (https://bazel.io/) BUILD file for apksig library and apksigner tool.
+
+licenses(["notice"])  # Apache License 2.0
+
+# Public API of the apksig library
+java_library(
+    name = "apksig",
+    srcs = glob(
+        ["src/main/java/**/*.java"],
+        exclude = ["src/main/java/com/android/apksig/internal/**/*.java"],
+    ),
+    visibility = ["//visibility:public"],
+    deps = [":apksig-all"],
+)
+
+# All of apksig library, including private API which clients must not directly depend on. Private
+# API may change without regard to its clients outside of the apksig project.
+java_library(
+    name = "apksig-all",
+    srcs = glob(["src/main/java/**/*.java"]),
+    visibility = ["//visibility:private"],
+)
+
+java_binary(
+    name = "apksigner",
+    srcs = glob([
+        "src/apksigner/java/**/*.java",
+    ]),
+    main_class = "com.android.apksigner.ApkSignerTool",
+    resources = glob([
+        "src/apksigner/java/**/*.txt",
+    ]),
+    visibility = ["//visibility:public"],
+    deps = [":apksig"],
+)
+
+java_test(
+    name = "all",
+    srcs = glob([
+        "src/test/java/com/android/apksig/**/*.java",
+    ]),
+    resources = glob([
+        "src/test/resources/**/*",
+    ]),
+    size = "small",
+    test_class = "com.android.apksig.AllTests",
+    deps = [":apksig-all"],
+)
diff --git a/src/main/java/com/android/apksig/ApkSigner.java b/src/main/java/com/android/apksig/ApkSigner.java
index e3870e7..88f2617 100644
--- a/src/main/java/com/android/apksig/ApkSigner.java
+++ b/src/main/java/com/android/apksig/ApkSigner.java
@@ -240,8 +240,7 @@
         List<CentralDirectoryRecord> inputCdRecords =
                 parseZipCentralDirectory(inputCd, inputZipSections);
 
-        List<Hints.PatternWithRange> pinPatterns = extractPinPatterns(
-                inputCdRecords, inputApkLfhSection);
+        List<Pattern> pinPatterns = extractPinPatterns(inputCdRecords, inputApkLfhSection);
         List<Hints.ByteRange> pinByteRanges = pinPatterns == null ? null : new ArrayList<>();
 
         // Step 3. Obtain a signer engine instance
@@ -372,33 +371,28 @@
 
                 // Output entry's Local File Header + data
                 long outputLocalFileHeaderOffset = outputOffset;
-                OutputSizeAndDataOffset outputLfrResult =
+                long outputLocalFileRecordSize =
                         outputInputJarEntryLfhRecordPreservingDataAlignment(
                                 inputApkLfhSection,
                                 inputLocalFileRecord,
                                 outputApkOut,
                                 outputLocalFileHeaderOffset);
-                outputOffset += outputLfrResult.outputBytes;
-                long outputDataOffset =
-                        outputLocalFileHeaderOffset + outputLfrResult.dataOffsetBytes;
+                outputOffset += outputLocalFileRecordSize;
 
                 if (pinPatterns != null) {
-                    boolean pinFileHeader = false;
-                    for (Hints.PatternWithRange pinPattern : pinPatterns) {
+                    boolean pinThisFile = false;
+                    for (Pattern pinPattern : pinPatterns) {
                         if (pinPattern.matcher(inputCdRecord.getName()).matches()) {
-                            Hints.ByteRange dataRange =
-                                    new Hints.ByteRange(outputDataOffset, outputOffset);
-                            Hints.ByteRange pinRange =
-                                    pinPattern.ClampToAbsoluteByteRange(dataRange);
-                            if (pinRange != null) {
-                                pinFileHeader = true;
-                                pinByteRanges.add(pinRange);
-                            }
+                            pinThisFile = true;
+                            break;
                         }
                     }
-                    if (pinFileHeader) {
-                        pinByteRanges.add(new Hints.ByteRange(outputLocalFileHeaderOffset,
-                                                              outputDataOffset));
+
+                    if (pinThisFile) {
+                        pinByteRanges.add(
+                            new Hints.ByteRange(
+                                outputLocalFileHeaderOffset,
+                                outputOffset));
                     }
                 }
 
@@ -580,17 +574,7 @@
         inspectEntryRequest.done();
     }
 
-    private static class OutputSizeAndDataOffset {
-        public long outputBytes;
-        public long dataOffsetBytes;
-
-        public OutputSizeAndDataOffset(long outputBytes, long dataOffsetBytes) {
-            this.outputBytes = outputBytes;
-            this.dataOffsetBytes = dataOffsetBytes;
-        }
-    }
-
-    private static OutputSizeAndDataOffset outputInputJarEntryLfhRecordPreservingDataAlignment(
+    private static long outputInputJarEntryLfhRecordPreservingDataAlignment(
             DataSource inputLfhSection,
             LocalFileRecord inputRecord,
             DataSink outputLfhSection,
@@ -598,27 +582,21 @@
         long inputOffset = inputRecord.getStartOffsetInArchive();
         if (inputOffset == outputOffset) {
             // This record's data will be aligned same as in the input APK.
-            return new OutputSizeAndDataOffset(
-                    inputRecord.outputRecord(inputLfhSection, outputLfhSection),
-                    inputRecord.getDataStartOffsetInRecord());
+            return inputRecord.outputRecord(inputLfhSection, outputLfhSection);
         }
         int dataAlignmentMultiple = getInputJarEntryDataAlignmentMultiple(inputRecord);
         if ((dataAlignmentMultiple <= 1)
                 || ((inputOffset % dataAlignmentMultiple)
                         == (outputOffset % dataAlignmentMultiple))) {
             // This record's data will be aligned same as in the input APK.
-            return new OutputSizeAndDataOffset(
-                    inputRecord.outputRecord(inputLfhSection, outputLfhSection),
-                    inputRecord.getDataStartOffsetInRecord());
+            return inputRecord.outputRecord(inputLfhSection, outputLfhSection);
         }
 
         long inputDataStartOffset = inputOffset + inputRecord.getDataStartOffsetInRecord();
         if ((inputDataStartOffset % dataAlignmentMultiple) != 0) {
             // This record's data is not aligned in the input APK. No need to align it in the
             // output.
-            return new OutputSizeAndDataOffset(
-                    inputRecord.outputRecord(inputLfhSection, outputLfhSection),
-                    inputRecord.getDataStartOffsetInRecord());
+            return inputRecord.outputRecord(inputLfhSection, outputLfhSection);
         }
 
         // This record's data needs to be re-aligned in the output. This is achieved using the
@@ -628,11 +606,8 @@
                         inputRecord.getExtra(),
                         outputOffset + inputRecord.getExtraFieldStartOffsetInsideRecord(),
                         dataAlignmentMultiple);
-        long dataOffset = inputRecord.getDataStartOffsetInRecord() +
-                          aligningExtra.remaining() -
-                          inputRecord.getExtra().remaining();
-        return new OutputSizeAndDataOffset(inputRecord.outputRecordWithModifiedExtra(
-                inputLfhSection, aligningExtra, outputLfhSection), dataOffset);
+        return inputRecord.outputRecordWithModifiedExtra(
+                inputLfhSection, aligningExtra, outputLfhSection);
     }
 
     private static int getInputJarEntryDataAlignmentMultiple(LocalFileRecord entry) {
@@ -819,12 +794,12 @@
      * Return list of pin patterns embedded in the pin pattern asset
      * file.  If no such file, return {@code null}.
      */
-    private static List<Hints.PatternWithRange> extractPinPatterns(
+    private static List<Pattern> extractPinPatterns(
             List<CentralDirectoryRecord> cdRecords, DataSource lhfSection)
                     throws IOException, ApkFormatException {
         CentralDirectoryRecord pinListCdRecord =
                 findCdRecord(cdRecords, Hints.PIN_HINT_ASSET_ZIP_ENTRY_NAME);
-        List<Hints.PatternWithRange> pinPatterns = null;
+        List<Pattern> pinPatterns = null;
         if (pinListCdRecord != null) {
             pinPatterns = new ArrayList<>();
             byte[] patternBlob;
diff --git a/src/main/java/com/android/apksig/Hints.java b/src/main/java/com/android/apksig/Hints.java
index 4070fa2..49ef2b0 100644
--- a/src/main/java/com/android/apksig/Hints.java
+++ b/src/main/java/com/android/apksig/Hints.java
@@ -20,7 +20,6 @@
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 public final class Hints {
@@ -48,39 +47,6 @@
         }
     }
 
-    public static final class PatternWithRange {
-        final Pattern pattern;
-        final long offset;
-        final long size;
-
-        public PatternWithRange(String pattern) {
-            this.pattern = Pattern.compile(pattern);
-            this.offset= 0;
-            this.size = Long.MAX_VALUE;
-        }
-
-        public PatternWithRange(String pattern, long offset, long size) {
-            this.pattern = Pattern.compile(pattern);
-            this.offset = offset;
-            this.size = size;
-        }
-
-        public Matcher matcher(CharSequence input) {
-            return this.pattern.matcher(input);
-        }
-
-        public ByteRange ClampToAbsoluteByteRange(ByteRange rangeIn) {
-            if (rangeIn.end - rangeIn.start < this.offset) {
-                return null;
-            }
-            long rangeOutStart = rangeIn.start + this.offset;
-            long rangeOutSize = Math.min(rangeIn.end - rangeOutStart,
-                                           this.size);
-            return new ByteRange(rangeOutStart,
-                                 rangeOutStart + rangeOutSize);
-        }
-    }
-
     /**
      * Create a blob of bytes that PinnerService understands as a
      * sequence of byte ranges to pin.
@@ -99,20 +65,13 @@
         return bos.toByteArray();
     }
 
-    public static ArrayList<PatternWithRange> parsePinPatterns(byte[] patternBlob) {
-        ArrayList<PatternWithRange> pinPatterns = new ArrayList<>();
+    public static ArrayList<Pattern> parsePinPatterns(byte[] patternBlob) {
+        ArrayList<Pattern> pinPatterns = new ArrayList<>();
         try {
             for (String rawLine : new String(patternBlob, "UTF-8").split("\n")) {
                 String line = rawLine.replaceFirst("#.*", "");  // # starts a comment
-                String[] fields = line.split(" ");
-                if (fields.length == 1) {
-                    pinPatterns.add(new PatternWithRange(fields[0]));
-                } else if (fields.length == 3) {
-                    long start = Long.parseLong(fields[1]);
-                    long end = Long.parseLong(fields[2]);
-                    pinPatterns.add(new PatternWithRange(fields[0], start, end - start));
-                } else {
-                    throw new AssertionError("bad pin pattern line " + line);
+                if (!("".equals(line))) {
+                    pinPatterns.add(Pattern.compile(line));
                 }
             }
         } catch (UnsupportedEncodingException ex) {
diff --git a/src/main/java/com/android/apksig/internal/apk/ApkSigningBlockUtils.java b/src/main/java/com/android/apksig/internal/apk/ApkSigningBlockUtils.java
index 7c13586..cc69af3 100644
--- a/src/main/java/com/android/apksig/internal/apk/ApkSigningBlockUtils.java
+++ b/src/main/java/com/android/apksig/internal/apk/ApkSigningBlockUtils.java
@@ -21,16 +21,10 @@
 import com.android.apksig.apk.ApkFormatException;
 import com.android.apksig.apk.ApkSigningBlockNotFoundException;
 import com.android.apksig.apk.ApkUtils;
-import com.android.apksig.internal.asn1.Asn1BerParser;
-import com.android.apksig.internal.asn1.Asn1DecodingException;
-import com.android.apksig.internal.asn1.Asn1DerEncoder;
-import com.android.apksig.internal.asn1.Asn1EncodingException;
 import com.android.apksig.internal.util.ByteBufferDataSource;
 import com.android.apksig.internal.util.ChainedDataSource;
 import com.android.apksig.internal.util.Pair;
 import com.android.apksig.internal.util.VerityTreeBuilder;
-import com.android.apksig.internal.x509.RSAPublicKey;
-import com.android.apksig.internal.x509.SubjectPublicKeyInfo;
 import com.android.apksig.internal.zip.ZipUtils;
 import com.android.apksig.util.DataSink;
 import com.android.apksig.util.DataSinks;
@@ -39,7 +33,6 @@
 
 import com.android.apksig.util.RunnablesExecutor;
 import java.io.IOException;
-import java.math.BigInteger;
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -65,13 +58,17 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 public class ApkSigningBlockUtils {
 
-    private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
+    private static final char[] HEX_DIGITS = "01234567890abcdef".toCharArray();
     private static final long CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES = 1024 * 1024;
     public static final int ANDROID_COMMON_PAGE_ALIGNMENT_BYTES = 4096;
     public static final byte[] APK_SIGNING_BLOCK_MAGIC =
@@ -778,53 +775,6 @@
         byte[] encodedPublicKey = null;
         if ("X.509".equals(publicKey.getFormat())) {
             encodedPublicKey = publicKey.getEncoded();
-            // if the key is an RSA key check for a negative modulus
-            if ("RSA".equals(publicKey.getAlgorithm())) {
-                try {
-                    // Parse the encoded public key into the separate elements of the
-                    // SubjectPublicKeyInfo to obtain the SubjectPublicKey.
-                    ByteBuffer encodedPublicKeyBuffer = ByteBuffer.wrap(encodedPublicKey);
-                    SubjectPublicKeyInfo subjectPublicKeyInfo = Asn1BerParser.parse(
-                            encodedPublicKeyBuffer, SubjectPublicKeyInfo.class);
-                    // The SubjectPublicKey is encoded as a bit string within the
-                    // SubjectPublicKeyInfo. The first byte of the encoding is the number of padding
-                    // bits; store this and decode the rest of the bit string into the RSA modulus
-                    // and exponent.
-                    ByteBuffer subjectPublicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey;
-                    byte padding = subjectPublicKeyBuffer.get();
-                    RSAPublicKey rsaPublicKey = Asn1BerParser.parse(subjectPublicKeyBuffer,
-                            RSAPublicKey.class);
-                    // if the modulus is negative then attempt to reencode it with a leading 0 sign
-                    // byte.
-                    if (rsaPublicKey.modulus.compareTo(BigInteger.ZERO) < 0) {
-                        // A negative modulus indicates the leading bit in the integer is 1. Per
-                        // ASN.1 encoding rules to encode a positive integer with the leading bit
-                        // set to 1 a byte containing all zeros should precede the integer encoding.
-                        byte[] encodedModulus = rsaPublicKey.modulus.toByteArray();
-                        byte[] reencodedModulus = new byte[encodedModulus.length + 1];
-                        reencodedModulus[0] = 0;
-                        System.arraycopy(encodedModulus, 0, reencodedModulus, 1,
-                                encodedModulus.length);
-                        rsaPublicKey.modulus = new BigInteger(reencodedModulus);
-                        // Once the modulus has been corrected reencode the RSAPublicKey, then
-                        // restore the padding value in the bit string and reencode the entire
-                        // SubjectPublicKeyInfo to be returned to the caller.
-                        byte[] reencodedRSAPublicKey = Asn1DerEncoder.encode(rsaPublicKey);
-                        byte[] reencodedSubjectPublicKey =
-                                new byte[reencodedRSAPublicKey.length + 1];
-                        reencodedSubjectPublicKey[0] = padding;
-                        System.arraycopy(reencodedRSAPublicKey, 0, reencodedSubjectPublicKey, 1,
-                                reencodedRSAPublicKey.length);
-                        subjectPublicKeyInfo.subjectPublicKey = ByteBuffer.wrap(
-                                reencodedSubjectPublicKey);
-                        encodedPublicKey = Asn1DerEncoder.encode(subjectPublicKeyInfo);
-                    }
-                } catch (Asn1DecodingException | Asn1EncodingException e) {
-                    System.out.println("Caught a exception encoding the public key: " + e);
-                    e.printStackTrace();
-                    encodedPublicKey = null;
-                }
-            }
         }
         if (encodedPublicKey == null) {
             try {
diff --git a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java
index f325f8b..d8e4723 100644
--- a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java
+++ b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java
@@ -70,7 +70,7 @@
      * protected by signatures inside the block.
      */
 
-    public static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
+    private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
 
     /** Hidden constructor to prevent instantiation. */
     private V2SchemeSigner() {}
diff --git a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java
index 0ef74a6..51c40bd 100644
--- a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java
+++ b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java
@@ -370,15 +370,7 @@
             return;
         }
         X509Certificate mainCertificate = result.certs.get(0);
-        byte[] certificatePublicKeyBytes;
-        try {
-            certificatePublicKeyBytes = ApkSigningBlockUtils.encodePublicKey(
-                    mainCertificate.getPublicKey());
-        } catch (InvalidKeyException e) {
-            System.out.println("Caught an exception encoding the public key: " + e);
-            e.printStackTrace();
-            certificatePublicKeyBytes = mainCertificate.getPublicKey().getEncoded();
-        }
+        byte[] certificatePublicKeyBytes = mainCertificate.getPublicKey().getEncoded();
         if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
             result.addError(
                     Issue.V2_SIG_PUBLIC_KEY_MISMATCH_BETWEEN_CERTIFICATE_AND_SIGNATURES_RECORD,
diff --git a/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeVerifier.java b/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeVerifier.java
index f263323..16a6408 100644
--- a/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeVerifier.java
+++ b/src/main/java/com/android/apksig/internal/apk/v3/V3SchemeVerifier.java
@@ -432,14 +432,7 @@
             return;
         }
         X509Certificate mainCertificate = result.certs.get(0);
-        byte[] certificatePublicKeyBytes;
-        try {
-            certificatePublicKeyBytes = ApkSigningBlockUtils.encodePublicKey(mainCertificate.getPublicKey());
-        } catch (InvalidKeyException e) {
-            System.out.println("Caught an exception encoding the public key: " + e);
-            e.printStackTrace();
-            certificatePublicKeyBytes = mainCertificate.getPublicKey().getEncoded();
-        }
+        byte[] certificatePublicKeyBytes = mainCertificate.getPublicKey().getEncoded();
         if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
             result.addError(
                     Issue.V3_SIG_PUBLIC_KEY_MISMATCH_BETWEEN_CERTIFICATE_AND_SIGNATURES_RECORD,
diff --git a/src/main/java/com/android/apksig/internal/util/FileChannelDataSource.java b/src/main/java/com/android/apksig/internal/util/RandomAccessFileDataSource.java
similarity index 88%
rename from src/main/java/com/android/apksig/internal/util/FileChannelDataSource.java
rename to src/main/java/com/android/apksig/internal/util/RandomAccessFileDataSource.java
index e4a421a..9c75d26 100644
--- a/src/main/java/com/android/apksig/internal/util/FileChannelDataSource.java
+++ b/src/main/java/com/android/apksig/internal/util/RandomAccessFileDataSource.java
@@ -27,7 +27,7 @@
 /**
  * {@link DataSource} backed by a {@link FileChannel} for {@link RandomAccessFile} access.
  */
-public class FileChannelDataSource implements DataSource {
+public class RandomAccessFileDataSource implements DataSource {
 
     private static final int MAX_READ_CHUNK_SIZE = 1024 * 1024;
 
@@ -36,24 +36,28 @@
     private final long mSize;
 
     /**
-     * Constructs a new {@code FileChannelDataSource} based on the data contained in the
+     * Constructs a new {@code RandomAccessFileDataSource} based on the data contained in the
      * whole file. Changes to the contents of the file, including the size of the file,
      * will be visible in this data source.
      */
-    public FileChannelDataSource(FileChannel channel) {
-        mChannel = channel;
+    public RandomAccessFileDataSource(RandomAccessFile file) {
+        mChannel = file.getChannel();
         mOffset = 0;
         mSize = -1;
     }
 
     /**
-     * Constructs a new {@code FileChannelDataSource} based on the data contained in the
+     * Constructs a new {@code RandomAccessFileDataSource} based on the data contained in the
      * specified region of the provided file. Changes to the contents of the file will be visible in
      * this data source.
      *
      * @throws IndexOutOfBoundsException if {@code offset} or {@code size} is negative.
      */
-    public FileChannelDataSource(FileChannel channel, long offset, long size) {
+    public RandomAccessFileDataSource(RandomAccessFile file, long offset, long size) {
+        this(file.getChannel(), offset, size);
+    }
+
+    private RandomAccessFileDataSource(FileChannel channel, long offset, long size) {
         if (offset < 0) {
             throw new IndexOutOfBoundsException("offset: " + size);
         }
@@ -79,14 +83,14 @@
     }
 
     @Override
-    public FileChannelDataSource slice(long offset, long size) {
+    public RandomAccessFileDataSource slice(long offset, long size) {
         long sourceSize = size();
         checkChunkValid(offset, size, sourceSize);
         if ((offset == 0) && (size == sourceSize)) {
             return this;
         }
 
-        return new FileChannelDataSource(mChannel, mOffset + offset, size);
+        return new RandomAccessFileDataSource(mChannel, mOffset + offset, size);
     }
 
     @Override
diff --git a/src/main/java/com/android/apksig/internal/x509/RSAPublicKey.java b/src/main/java/com/android/apksig/internal/x509/RSAPublicKey.java
deleted file mode 100644
index 521e067..0000000
--- a/src/main/java/com/android/apksig/internal/x509/RSAPublicKey.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.apksig.internal.x509;
-
-import com.android.apksig.internal.asn1.Asn1Class;
-import com.android.apksig.internal.asn1.Asn1Field;
-import com.android.apksig.internal.asn1.Asn1Type;
-
-import java.math.BigInteger;
-
-/**
- * {@code RSAPublicKey} as specified in RFC 3279.
- */
-@Asn1Class(type = Asn1Type.SEQUENCE)
-public class RSAPublicKey {
-    @Asn1Field(index = 0, type = Asn1Type.INTEGER)
-    public BigInteger modulus;
-
-    @Asn1Field(index = 1, type = Asn1Type.INTEGER)
-    public BigInteger publicExponent;
-}
diff --git a/src/main/java/com/android/apksig/util/DataSources.java b/src/main/java/com/android/apksig/util/DataSources.java
index 1f0b40b..00b89d7 100644
--- a/src/main/java/com/android/apksig/util/DataSources.java
+++ b/src/main/java/com/android/apksig/util/DataSources.java
@@ -17,10 +17,9 @@
 package com.android.apksig.util;
 
 import com.android.apksig.internal.util.ByteBufferDataSource;
-import com.android.apksig.internal.util.FileChannelDataSource;
+import com.android.apksig.internal.util.RandomAccessFileDataSource;
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
 
 /**
  * Utility methods for working with {@link DataSource} abstraction.
@@ -45,7 +44,10 @@
      * file, including changes to size of file, will be visible in the data source.
      */
     public static DataSource asDataSource(RandomAccessFile file) {
-        return asDataSource(file.getChannel());
+        if (file == null) {
+            throw new NullPointerException();
+        }
+        return new RandomAccessFileDataSource(file);
     }
 
     /**
@@ -53,28 +55,9 @@
      * Changes to the file will be visible in the data source.
      */
     public static DataSource asDataSource(RandomAccessFile file, long offset, long size) {
-        return asDataSource(file.getChannel(), offset, size);
-    }
-
-    /**
-     * Returns a {@link DataSource} backed by the provided {@link FileChannel}. Changes to the
-     * file, including changes to size of file, will be visible in the data source.
-     */
-    public static DataSource asDataSource(FileChannel channel) {
-        if (channel == null) {
+        if (file == null) {
             throw new NullPointerException();
         }
-        return new FileChannelDataSource(channel);
-    }
-
-    /**
-     * Returns a {@link DataSource} backed by the provided region of the {@link FileChannel}.
-     * Changes to the file will be visible in the data source.
-     */
-    public static DataSource asDataSource(FileChannel channel, long offset, long size) {
-        if (channel == null) {
-            throw new NullPointerException();
-        }
-        return new FileChannelDataSource(channel, offset, size);
+        return new RandomAccessFileDataSource(file, offset, size);
     }
 }
diff --git a/src/main/java/com/android/apksig/util/RunnablesExecutor.java b/src/main/java/com/android/apksig/util/RunnablesExecutor.java
index 4215810..04ec1d8 100644
--- a/src/main/java/com/android/apksig/util/RunnablesExecutor.java
+++ b/src/main/java/com/android/apksig/util/RunnablesExecutor.java
@@ -17,7 +17,7 @@
 package com.android.apksig.util;
 
 public interface RunnablesExecutor {
-    RunnablesExecutor SINGLE_THREADED = p -> p.createRunnable().run();
+    RunnablesExecutor SINGLE_THREADED = p -> p.getRunnable().run();
 
     void execute(RunnablesProvider provider);
 }
diff --git a/src/main/java/com/android/apksig/util/RunnablesProvider.java b/src/main/java/com/android/apksig/util/RunnablesProvider.java
index f96dcfe..5b7bad2 100644
--- a/src/main/java/com/android/apksig/util/RunnablesProvider.java
+++ b/src/main/java/com/android/apksig/util/RunnablesProvider.java
@@ -17,5 +17,5 @@
 package com.android.apksig.util;
 
 public interface RunnablesProvider {
-    Runnable createRunnable();
+    Runnable getRunnable();
 }
diff --git a/src/test/java/com/android/apksig/ApkSignerTest.java b/src/test/java/com/android/apksig/ApkSignerTest.java
index 65d9149..1434017 100644
--- a/src/test/java/com/android/apksig/ApkSignerTest.java
+++ b/src/test/java/com/android/apksig/ApkSignerTest.java
@@ -21,16 +21,8 @@
 
 import com.android.apksig.ApkVerifier.Issue;
 import com.android.apksig.apk.ApkFormatException;
-import com.android.apksig.apk.ApkUtils;
-import com.android.apksig.internal.apk.ApkSigningBlockUtils;
-import com.android.apksig.internal.apk.SignatureInfo;
-import com.android.apksig.internal.apk.v2.V2SchemeSigner;
-import com.android.apksig.internal.apk.v3.V3SchemeSigner;
-import com.android.apksig.internal.asn1.Asn1BerParser;
 import com.android.apksig.internal.util.ByteBufferDataSource;
 import com.android.apksig.internal.util.Resources;
-import com.android.apksig.internal.x509.RSAPublicKey;
-import com.android.apksig.internal.x509.SubjectPublicKeyInfo;
 import com.android.apksig.util.DataSinks;
 import com.android.apksig.util.DataSource;
 import com.android.apksig.util.DataSources;
@@ -52,8 +44,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.math.BigInteger;
-
 @RunWith(JUnit4.class)
 public class ApkSignerTest {
 
@@ -69,10 +59,6 @@
     private static final String SECOND_RSA_2048_SIGNER_RESOURCE_NAME = "rsa-2048_2";
     private static final String THIRD_RSA_2048_SIGNER_RESOURCE_NAME = "rsa-2048_3";
 
-    // This is the same cert as above with the modulus reencoded to remove the leading 0 sign bit.
-    private static final String FIRST_RSA_2048_SIGNER_CERT_WITH_NEGATIVE_MODULUS =
-            "rsa-2048_negmod.x509.der";
-
     private static final String LINEAGE_RSA_2048_2_SIGNERS_RESOURCE_NAME =
             "rsa-2048-lineage-2-signers";
 
@@ -820,83 +806,6 @@
                 lineageFromApk.isSignerInLineage((secondSigner)));
     }
 
-    @Test
-    public void testPublicKeyHasPositiveModulusAfterSigning() throws Exception {
-        // The V2 and V3 signature schemes include the public key from the certificate in the
-        // signing block. If a certificate with an RSAPublicKey is improperly encoded with a
-        // negative modulus this was previously written to the signing block as is and failed on
-        // device verification since on device the public key in the certificate was reencoded with
-        // the correct encoding for the modulus. This test uses an improperly encoded certificate to
-        // sign an APK and verifies that the public key in the signing block is corrected with a
-        // positive modulus to allow on device installs / updates.
-        List<ApkSigner.SignerConfig> signersList = Collections.singletonList(
-                getDefaultSignerConfigFromResources(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
-                        FIRST_RSA_2048_SIGNER_CERT_WITH_NEGATIVE_MODULUS));
-        DataSource signedApk = sign("original.apk", new ApkSigner.Builder(signersList)
-                .setV1SigningEnabled(true)
-                .setV2SigningEnabled(true)
-                .setV3SigningEnabled(true));
-        RSAPublicKey v2PublicKey = getRSAPublicKeyFromSigningBlock(signedApk,
-                ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2);
-        assertTrue("The modulus in the public key in the V2 signing block must not be negative",
-                v2PublicKey.modulus.compareTo(BigInteger.ZERO) > 0);
-        RSAPublicKey v3PublicKey = getRSAPublicKeyFromSigningBlock(signedApk,
-                ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3);
-        assertTrue("The modulus in the public key in the V3 signing block must not be negative",
-                v3PublicKey.modulus.compareTo(BigInteger.ZERO) > 0);
-    }
-
-    private RSAPublicKey getRSAPublicKeyFromSigningBlock(DataSource apk, int signatureVersionId)
-            throws Exception {
-        int signatureVersionBlockId;
-        switch (signatureVersionId) {
-            case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2:
-                signatureVersionBlockId = V2SchemeSigner.APK_SIGNATURE_SCHEME_V2_BLOCK_ID;
-                break;
-            case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3:
-                signatureVersionBlockId = V3SchemeSigner.APK_SIGNATURE_SCHEME_V3_BLOCK_ID;
-                break;
-            default:
-                throw new Exception(
-                        "Invalid signature version ID specified: " + signatureVersionId);
-        }
-        ApkUtils.ZipSections zipSections = ApkUtils.findZipSections(apk);
-        ApkSigningBlockUtils.Result result = new ApkSigningBlockUtils.Result(
-                signatureVersionId);
-        SignatureInfo signatureInfo = ApkSigningBlockUtils.findSignature(apk, zipSections,
-                signatureVersionBlockId, result);
-        // FORMAT:
-        // * length prefixed sequence of length prefixed signers
-        //   * length-prefixed signed data
-        //   * V3+ only - minSDK (uint32)
-        //   * V3+ only - maxSDK (uint32)
-        //   * length-prefixed sequence of length-prefixed signatures:
-        //   * length-prefixed bytes: public key (X.509 SubjectPublicKeyInfo, ASN.1 DER encoded)
-        ByteBuffer signers = ApkSigningBlockUtils.getLengthPrefixedSlice(
-                signatureInfo.signatureBlock);
-        ByteBuffer signer = ApkSigningBlockUtils.getLengthPrefixedSlice(signers);
-        // Since all the data is read from the signer block the signedData and signatures are
-        // discarded.
-        ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
-        // For V3+ signature version IDs discard the min / max SDKs as well
-        if (signatureVersionId >= ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3) {
-            signer.getInt();
-            signer.getInt();
-        }
-        ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
-        ByteBuffer publicKey = ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
-        SubjectPublicKeyInfo subjectPublicKeyInfo = Asn1BerParser.parse(publicKey,
-                SubjectPublicKeyInfo.class);
-        ByteBuffer subjectPublicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey;
-        // The SubjectPublicKey is stored as a bit string in the SubjectPublicKeyInfo with the first
-        // byte indicating the number of padding bits in the public key. Read this first byte to
-        // allow parsing the rest of the RSAPublicKey as a sequence.
-        subjectPublicKeyBuffer.get();
-        RSAPublicKey rsaPublicKey = Asn1BerParser.parse(subjectPublicKeyBuffer,
-                RSAPublicKey.class);
-        return rsaPublicKey;
-    }
-
     /**
      * Asserts that signing the specified golden input file using the provided signing
      * configuration produces output identical to the specified golden output file.
@@ -994,13 +903,4 @@
                 Resources.toCertificateChain(ApkSignerTest.class, keyNameInResources + ".x509.pem");
         return new ApkSigner.SignerConfig.Builder(keyNameInResources, privateKey, certs).build();
     }
-
-    private static ApkSigner.SignerConfig getDefaultSignerConfigFromResources(
-            String keyNameInResources, String certNameInResources) throws Exception {
-        PrivateKey privateKey = Resources.toPrivateKey(ApkSignerTest.class,
-                keyNameInResources + ".pk8");
-        List<X509Certificate> certs = Resources.toCertificateChain(ApkSignerTest.class,
-                certNameInResources);
-        return new ApkSigner.SignerConfig.Builder(keyNameInResources, privateKey, certs).build();
-    }
 }
diff --git a/src/test/java/com/android/apksig/internal/apk/ApkSigningBlockUtilsTest.java b/src/test/java/com/android/apksig/internal/apk/ApkSigningBlockUtilsTest.java
index 1ee3466..7eb7c9b 100644
--- a/src/test/java/com/android/apksig/internal/apk/ApkSigningBlockUtilsTest.java
+++ b/src/test/java/com/android/apksig/internal/apk/ApkSigningBlockUtilsTest.java
@@ -101,7 +101,7 @@
                     List<Future<?>> jobs = new ArrayList<>(jobCount);
 
                     for (int i = 0; i < jobCount; i++) {
-                        jobs.add(forkJoinPool.submit(provider.createRunnable()));
+                        jobs.add(forkJoinPool.submit(provider.getRunnable()));
                     }
 
                     try {
diff --git a/src/test/java/com/android/apksig/internal/util/FileChannelDataSourceTest.java b/src/test/java/com/android/apksig/internal/util/RandomAccessFileDataSourceTest.java
similarity index 93%
rename from src/test/java/com/android/apksig/internal/util/FileChannelDataSourceTest.java
rename to src/test/java/com/android/apksig/internal/util/RandomAccessFileDataSourceTest.java
index 9578926..304f1bf 100644
--- a/src/test/java/com/android/apksig/internal/util/FileChannelDataSourceTest.java
+++ b/src/test/java/com/android/apksig/internal/util/RandomAccessFileDataSourceTest.java
@@ -31,14 +31,14 @@
 import org.junit.runners.JUnit4;
 
 @RunWith(JUnit4.class)
-public class FileChannelDataSourceTest {
+public class RandomAccessFileDataSourceTest {
     @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
 
     @Test
     public void testFeedsCorrectData_whenFilePartiallyReadFromBeginning() throws Exception {
         byte[] fullFileContent = createFileContent(1024 * 1024 + 987654);
         RandomAccessFile raf = createRaf(fullFileContent);
-        DataSource rafDataSource = new FileChannelDataSource(raf.getChannel());
+        DataSource rafDataSource = new RandomAccessFileDataSource(raf);
 
         ByteArrayDataSink dataSink = new ByteArrayDataSink();
 
@@ -56,7 +56,7 @@
     public void testFeedsCorrectData_whenFilePartiallyReadWithOffset() throws Exception {
         byte[] fullFileContent = createFileContent(1024 * 1024 + 987654);
         RandomAccessFile raf = createRaf(fullFileContent);
-        DataSource rafDataSource = new FileChannelDataSource(raf.getChannel());
+        DataSource rafDataSource = new RandomAccessFileDataSource(raf);
 
         ByteArrayDataSink dataSink = new ByteArrayDataSink();
 
@@ -75,7 +75,7 @@
     public void testFeedsCorrectData_whenSeveralMbRead() throws Exception {
         byte[] fullFileContent = createFileContent(3 * 1024 * 1024 + 987654);
         RandomAccessFile raf = createRaf(fullFileContent);
-        DataSource rafDataSource = new FileChannelDataSource(raf.getChannel());
+        DataSource rafDataSource = new RandomAccessFileDataSource(raf);
 
         ByteArrayDataSink dataSink = new ByteArrayDataSink();
 
diff --git a/src/test/java/com/android/apksig/util/DataSourceFromRAFChunkTest.java b/src/test/java/com/android/apksig/util/DataSourceFromRAFChunkTest.java
index e83c906..8116012 100644
--- a/src/test/java/com/android/apksig/util/DataSourceFromRAFChunkTest.java
+++ b/src/test/java/com/android/apksig/util/DataSourceFromRAFChunkTest.java
@@ -24,23 +24,15 @@
 import java.nio.file.Files;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import org.junit.runners.JUnit4;
 
 /**
  * Tests for the {@link DataSource} returned by
  * {@link DataSources#asDataSource(RandomAccessFile, long, long)}.
  */
-@RunWith(Parameterized.class)
+@RunWith(JUnit4.class)
 public class DataSourceFromRAFChunkTest extends DataSourceTestBase {
 
-    @Parameterized.Parameters(name = "{0}")
-    public static DataSourceFromRAFFactory[] data() {
-        return DataSourceFromRAFFactory.values();
-    }
-
-    @Parameterized.Parameter
-    public DataSourceFromRAFFactory factory;
-
     @Test
     public void testFileSizeChangesNotVisible() throws Exception {
         try (CloseableWithDataSource c = createDataSource("abcdefg")) {
@@ -90,7 +82,7 @@
         }
 
         return CloseableWithDataSource.of(
-                factory.create(f, 2, contents.length),
+                DataSources.asDataSource(f, 2, contents.length),
                 new DataSourceFromRAFTest.TmpFileCloseable(tmp, f));
     }
 }
diff --git a/src/test/java/com/android/apksig/util/DataSourceFromRAFFactory.java b/src/test/java/com/android/apksig/util/DataSourceFromRAFFactory.java
deleted file mode 100644
index eec0c11..0000000
--- a/src/test/java/com/android/apksig/util/DataSourceFromRAFFactory.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.apksig.util;
-
-import java.io.RandomAccessFile;
-
-enum DataSourceFromRAFFactory {
-    RANDOM_ACCESS_FILE {
-        @Override DataSource create(RandomAccessFile file) {
-            return DataSources.asDataSource(file);
-        }
-
-        @Override DataSource create(RandomAccessFile file, long offset, long size) {
-            return DataSources.asDataSource(file, offset, size);
-        }
-    },
-    FILE_CHANNEL {
-        @Override DataSource create(RandomAccessFile file) {
-            return DataSources.asDataSource(file.getChannel());
-        }
-
-        @Override DataSource create(RandomAccessFile file, long offset, long size) {
-            return DataSources.asDataSource(file.getChannel(), offset, size);
-        }
-    };
-
-    abstract DataSource create(RandomAccessFile file);
-    abstract DataSource create(RandomAccessFile file, long offset, long size);
-}
diff --git a/src/test/java/com/android/apksig/util/DataSourceFromRAFTest.java b/src/test/java/com/android/apksig/util/DataSourceFromRAFTest.java
index 50de579..36ef760 100644
--- a/src/test/java/com/android/apksig/util/DataSourceFromRAFTest.java
+++ b/src/test/java/com/android/apksig/util/DataSourceFromRAFTest.java
@@ -26,23 +26,15 @@
 import java.nio.file.Files;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import org.junit.runners.JUnit4;
 
 /**
  * Tests for the {@link DataSource} returned by
  * {@link DataSources#asDataSource(java.io.RandomAccessFile)}.
  */
-@RunWith(Parameterized.class)
+@RunWith(JUnit4.class)
 public class DataSourceFromRAFTest extends DataSourceTestBase {
 
-    @Parameterized.Parameters(name = "{0}")
-    public static DataSourceFromRAFFactory[] data() {
-        return DataSourceFromRAFFactory.values();
-    }
-
-    @Parameterized.Parameter
-    public DataSourceFromRAFFactory factory;
-
     @Test
     public void testFileSizeChangesVisible() throws Exception {
         try (CloseableWithDataSource c = createDataSource("abcdefg")) {
@@ -86,7 +78,7 @@
         }
 
         return CloseableWithDataSource.of(
-                factory.create(f),
+                DataSources.asDataSource(f),
                 new TmpFileCloseable(tmp, f));
     }
 
diff --git a/src/test/resources/com/android/apksig/rsa-2048_negmod.x509.der b/src/test/resources/com/android/apksig/rsa-2048_negmod.x509.der
deleted file mode 100644
index ba7e78e..0000000
--- a/src/test/resources/com/android/apksig/rsa-2048_negmod.x509.der
+++ /dev/null
Binary files differ