Search in sources :

Example 16 with DataSource

use of com.android.apksig.util.DataSource in project apksig by venshine.

the class DefaultApkSignerEngine method outputZipSectionsInternal.

private OutputApkSigningBlockRequestImpl outputZipSectionsInternal(DataSource zipEntries, DataSource zipCentralDirectory, DataSource zipEocd, boolean apkSigningBlockPaddingSupported) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {
    checkNotClosed();
    checkV1SigningDoneIfEnabled();
    if (!mV2SigningEnabled && !mV3SigningEnabled && !isEligibleForSourceStamp()) {
        return null;
    }
    checkOutputApkNotDebuggableIfDebuggableMustBeRejected();
    // adjust to proper padding
    Pair<DataSource, Integer> paddingPair = ApkSigningBlockUtils.generateApkSigningBlockPadding(zipEntries, apkSigningBlockPaddingSupported);
    DataSource beforeCentralDir = paddingPair.getFirst();
    int padSizeBeforeApkSigningBlock = paddingPair.getSecond();
    DataSource eocd = ApkSigningBlockUtils.copyWithModifiedCDOffset(beforeCentralDir, zipEocd);
    List<Pair<byte[], Integer>> signingSchemeBlocks = new ArrayList<>();
    ApkSigningBlockUtils.SigningSchemeBlockAndDigests v2SigningSchemeBlockAndDigests = null;
    ApkSigningBlockUtils.SigningSchemeBlockAndDigests v3SigningSchemeBlockAndDigests = null;
    // new APK signing block.
    if (mOtherSignersSignaturesPreserved && mPreservedSignatureBlocks != null && !mPreservedSignatureBlocks.isEmpty()) {
        signingSchemeBlocks.addAll(mPreservedSignatureBlocks);
    }
    // create APK Signature Scheme V2 Signature if requested
    if (mV2SigningEnabled) {
        invalidateV2Signature();
        List<ApkSigningBlockUtils.SignerConfig> v2SignerConfigs = createV2SignerConfigs(apkSigningBlockPaddingSupported);
        v2SigningSchemeBlockAndDigests = V2SchemeSigner.generateApkSignatureSchemeV2Block(mExecutor, beforeCentralDir, zipCentralDirectory, eocd, v2SignerConfigs, mV3SigningEnabled, mOtherSignersSignaturesPreserved ? mPreservedV2Signers : null);
        signingSchemeBlocks.add(v2SigningSchemeBlockAndDigests.signingSchemeBlock);
    }
    if (mV3SigningEnabled) {
        invalidateV3Signature();
        List<ApkSigningBlockUtils.SignerConfig> v3SignerConfigs = createV3SignerConfigs(apkSigningBlockPaddingSupported);
        v3SigningSchemeBlockAndDigests = V3SchemeSigner.generateApkSignatureSchemeV3Block(mExecutor, beforeCentralDir, zipCentralDirectory, eocd, v3SignerConfigs);
        signingSchemeBlocks.add(v3SigningSchemeBlockAndDigests.signingSchemeBlock);
    }
    if (isEligibleForSourceStamp()) {
        ApkSigningBlockUtils.SignerConfig sourceStampSignerConfig = createSourceStampSignerConfig();
        Map<Integer, Map<ContentDigestAlgorithm, byte[]>> signatureSchemeDigestInfos = new HashMap<>();
        if (mV3SigningEnabled) {
            signatureSchemeDigestInfos.put(VERSION_APK_SIGNATURE_SCHEME_V3, v3SigningSchemeBlockAndDigests.digestInfo);
        }
        if (mV2SigningEnabled) {
            signatureSchemeDigestInfos.put(VERSION_APK_SIGNATURE_SCHEME_V2, v2SigningSchemeBlockAndDigests.digestInfo);
        }
        if (mV1SigningEnabled) {
            Map<ContentDigestAlgorithm, byte[]> v1SigningSchemeDigests = new HashMap<>();
            try {
                // Jar signing related variables must have been already populated at this point
                // if V1 signing is enabled since it is happening before computations on the APK
                // signing block (V2/V3/V4/SourceStamp signing).
                byte[] inputJarManifest = (mInputJarManifestEntryDataRequest != null) ? mInputJarManifestEntryDataRequest.getData() : null;
                byte[] jarManifest = V1SchemeSigner.generateManifestFile(mV1ContentDigestAlgorithm, mOutputJarEntryDigests, inputJarManifest).contents;
                // The digest of the jar manifest does not need to be computed in chunks due to
                // the small size of the manifest.
                v1SigningSchemeDigests.put(ContentDigestAlgorithm.SHA256, computeSha256DigestBytes(jarManifest));
            } catch (ApkFormatException e) {
                throw new RuntimeException("Failed to generate manifest file", e);
            }
            signatureSchemeDigestInfos.put(VERSION_JAR_SIGNATURE_SCHEME, v1SigningSchemeDigests);
        }
        signingSchemeBlocks.add(V2SourceStampSigner.generateSourceStampBlock(sourceStampSignerConfig, signatureSchemeDigestInfos));
    }
    // create APK Signing Block with v2 and/or v3 and/or SourceStamp blocks
    byte[] apkSigningBlock = ApkSigningBlockUtils.generateApkSigningBlock(signingSchemeBlocks);
    mAddSigningBlockRequest = new OutputApkSigningBlockRequestImpl(apkSigningBlock, padSizeBeforeApkSigningBlock);
    return mAddSigningBlockRequest;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ApkSigningBlockUtils(com.android.apksig.internal.apk.ApkSigningBlockUtils) DataSource(com.android.apksig.util.DataSource) ApkFormatException(com.android.apksig.apk.ApkFormatException) ContentDigestAlgorithm(com.android.apksig.internal.apk.ContentDigestAlgorithm) Map(java.util.Map) HashMap(java.util.HashMap) Pair(com.android.apksig.internal.util.Pair)

Example 17 with DataSource

use of com.android.apksig.util.DataSource in project apksig by venshine.

the class V2SchemeVerifier method verify.

/**
 * Verifies the provided APK's APK Signature Scheme v2 signatures and returns the result of
 * verification. The APK must be considered verified only if
 * {@link ApkSigningBlockUtils.Result#verified} is
 * {@code true}. If verification fails, the result will contain errors -- see
 * {@link ApkSigningBlockUtils.Result#getErrors()}.
 *
 * <p>Verification succeeds iff the APK's APK Signature Scheme v2 signatures are expected to
 * verify on all Android platform versions in the {@code [minSdkVersion, maxSdkVersion]} range.
 * If the APK's signature is expected to not verify on any of the specified platform versions,
 * this method returns a result with one or more errors and whose
 * {@code Result.verified == false}, or this method throws an exception.
 *
 * @throws ApkFormatException if the APK is malformed
 * @throws NoSuchAlgorithmException if the APK's signatures cannot be verified because a
 *         required cryptographic algorithm implementation is missing
 * @throws ApkSigningBlockUtils.SignatureNotFoundException if no APK Signature Scheme v2
 * signatures are found
 * @throws IOException if an I/O error occurs when reading the APK
 */
public static ApkSigningBlockUtils.Result verify(RunnablesExecutor executor, DataSource apk, ApkUtils.ZipSections zipSections, Map<Integer, String> supportedApkSigSchemeNames, Set<Integer> foundSigSchemeIds, int minSdkVersion, int maxSdkVersion) throws IOException, ApkFormatException, NoSuchAlgorithmException, ApkSigningBlockUtils.SignatureNotFoundException {
    ApkSigningBlockUtils.Result result = new ApkSigningBlockUtils.Result(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2);
    SignatureInfo signatureInfo = ApkSigningBlockUtils.findSignature(apk, zipSections, V2SchemeConstants.APK_SIGNATURE_SCHEME_V2_BLOCK_ID, result);
    DataSource beforeApkSigningBlock = apk.slice(0, signatureInfo.apkSigningBlockOffset);
    DataSource centralDir = apk.slice(signatureInfo.centralDirOffset, signatureInfo.eocdOffset - signatureInfo.centralDirOffset);
    ByteBuffer eocd = signatureInfo.eocd;
    verify(executor, beforeApkSigningBlock, signatureInfo.signatureBlock, centralDir, eocd, supportedApkSigSchemeNames, foundSigSchemeIds, minSdkVersion, maxSdkVersion, result);
    return result;
}
Also used : SignatureInfo(com.android.apksig.internal.apk.SignatureInfo) ApkSigningBlockUtils(com.android.apksig.internal.apk.ApkSigningBlockUtils) ByteBuffer(java.nio.ByteBuffer) DataSource(com.android.apksig.util.DataSource)

Example 18 with DataSource

use of com.android.apksig.util.DataSource in project apksig by venshine.

the class V3SchemeVerifier method verify.

/**
 * Verifies the provided APK's APK Signature Scheme v3 signatures and returns the result of
 * verification. The APK must be considered verified only if
 * {@link ApkSigningBlockUtils.Result#verified} is
 * {@code true}. If verification fails, the result will contain errors -- see
 * {@link ApkSigningBlockUtils.Result#getErrors()}.
 *
 * <p>Verification succeeds iff the APK's APK Signature Scheme v3 signatures are expected to
 * verify on all Android platform versions in the {@code [minSdkVersion, maxSdkVersion]} range.
 * If the APK's signature is expected to not verify on any of the specified platform versions,
 * this method returns a result with one or more errors and whose
 * {@code Result.verified == false}, or this method throws an exception.
 *
 * @throws ApkFormatException if the APK is malformed
 * @throws NoSuchAlgorithmException if the APK's signatures cannot be verified because a
 *         required cryptographic algorithm implementation is missing
 * @throws SignatureNotFoundException if no APK Signature Scheme v3
 * signatures are found
 * @throws IOException if an I/O error occurs when reading the APK
 */
public static ApkSigningBlockUtils.Result verify(RunnablesExecutor executor, DataSource apk, ApkUtils.ZipSections zipSections, int minSdkVersion, int maxSdkVersion) throws IOException, NoSuchAlgorithmException, SignatureNotFoundException {
    ApkSigningBlockUtils.Result result = new ApkSigningBlockUtils.Result(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3);
    SignatureInfo signatureInfo = ApkSigningBlockUtils.findSignature(apk, zipSections, V3SchemeConstants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID, result);
    DataSource beforeApkSigningBlock = apk.slice(0, signatureInfo.apkSigningBlockOffset);
    DataSource centralDir = apk.slice(signatureInfo.centralDirOffset, signatureInfo.eocdOffset - signatureInfo.centralDirOffset);
    ByteBuffer eocd = signatureInfo.eocd;
    // platforms
    if (minSdkVersion < AndroidSdkVersion.P) {
        minSdkVersion = AndroidSdkVersion.P;
    }
    verify(executor, beforeApkSigningBlock, signatureInfo.signatureBlock, centralDir, eocd, minSdkVersion, maxSdkVersion, result);
    return result;
}
Also used : SignatureInfo(com.android.apksig.internal.apk.SignatureInfo) ApkSigningBlockUtils(com.android.apksig.internal.apk.ApkSigningBlockUtils) ByteBuffer(java.nio.ByteBuffer) DataSource(com.android.apksig.util.DataSource)

Example 19 with DataSource

use of com.android.apksig.util.DataSource in project apksig by venshine.

the class ApkSigningBlockUtils method computeOneMbChunkContentDigests.

static void computeOneMbChunkContentDigests(Set<ContentDigestAlgorithm> digestAlgorithms, DataSource[] contents, Map<ContentDigestAlgorithm, byte[]> outputContentDigests) throws IOException, NoSuchAlgorithmException, DigestException {
    // For each digest algorithm the result is computed as follows:
    // 1. Each segment of contents is split into consecutive chunks of 1 MB in size.
    // The final chunk will be shorter iff the length of segment is not a multiple of 1 MB.
    // No chunks are produced for empty (zero length) segments.
    // 2. The digest of each chunk is computed over the concatenation of byte 0xa5, the chunk's
    // length in bytes (uint32 little-endian) and the chunk's contents.
    // 3. The output digest is computed over the concatenation of the byte 0x5a, the number of
    // chunks (uint32 little-endian) and the concatenation of digests of chunks of all
    // segments in-order.
    long chunkCountLong = 0;
    for (DataSource input : contents) {
        chunkCountLong += getChunkCount(input.size(), CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES);
    }
    if (chunkCountLong > Integer.MAX_VALUE) {
        throw new DigestException("Input too long: " + chunkCountLong + " chunks");
    }
    int chunkCount = (int) chunkCountLong;
    ContentDigestAlgorithm[] digestAlgorithmsArray = digestAlgorithms.toArray(new ContentDigestAlgorithm[digestAlgorithms.size()]);
    MessageDigest[] mds = new MessageDigest[digestAlgorithmsArray.length];
    byte[][] digestsOfChunks = new byte[digestAlgorithmsArray.length][];
    int[] digestOutputSizes = new int[digestAlgorithmsArray.length];
    for (int i = 0; i < digestAlgorithmsArray.length; i++) {
        ContentDigestAlgorithm digestAlgorithm = digestAlgorithmsArray[i];
        int digestOutputSizeBytes = digestAlgorithm.getChunkDigestOutputSizeBytes();
        digestOutputSizes[i] = digestOutputSizeBytes;
        byte[] concatenationOfChunkCountAndChunkDigests = new byte[5 + chunkCount * digestOutputSizeBytes];
        concatenationOfChunkCountAndChunkDigests[0] = 0x5a;
        setUnsignedInt32LittleEndian(chunkCount, concatenationOfChunkCountAndChunkDigests, 1);
        digestsOfChunks[i] = concatenationOfChunkCountAndChunkDigests;
        String jcaAlgorithm = digestAlgorithm.getJcaMessageDigestAlgorithm();
        mds[i] = MessageDigest.getInstance(jcaAlgorithm);
    }
    DataSink mdSink = DataSinks.asDataSink(mds);
    byte[] chunkContentPrefix = new byte[5];
    chunkContentPrefix[0] = (byte) 0xa5;
    int chunkIndex = 0;
    // digest to be more efficient because it's presented with all of its input in one go.
    for (DataSource input : contents) {
        long inputOffset = 0;
        long inputRemaining = input.size();
        while (inputRemaining > 0) {
            int chunkSize = (int) Math.min(inputRemaining, CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES);
            setUnsignedInt32LittleEndian(chunkSize, chunkContentPrefix, 1);
            for (int i = 0; i < mds.length; i++) {
                mds[i].update(chunkContentPrefix);
            }
            try {
                input.feed(inputOffset, chunkSize, mdSink);
            } catch (IOException e) {
                throw new IOException("Failed to read chunk #" + chunkIndex, e);
            }
            for (int i = 0; i < digestAlgorithmsArray.length; i++) {
                MessageDigest md = mds[i];
                byte[] concatenationOfChunkCountAndChunkDigests = digestsOfChunks[i];
                int expectedDigestSizeBytes = digestOutputSizes[i];
                int actualDigestSizeBytes = md.digest(concatenationOfChunkCountAndChunkDigests, 5 + chunkIndex * expectedDigestSizeBytes, expectedDigestSizeBytes);
                if (actualDigestSizeBytes != expectedDigestSizeBytes) {
                    throw new RuntimeException("Unexpected output size of " + md.getAlgorithm() + " digest: " + actualDigestSizeBytes);
                }
            }
            inputOffset += chunkSize;
            inputRemaining -= chunkSize;
            chunkIndex++;
        }
    }
    for (int i = 0; i < digestAlgorithmsArray.length; i++) {
        ContentDigestAlgorithm digestAlgorithm = digestAlgorithmsArray[i];
        byte[] concatenationOfChunkCountAndChunkDigests = digestsOfChunks[i];
        MessageDigest md = mds[i];
        byte[] digest = md.digest(concatenationOfChunkCountAndChunkDigests);
        outputContentDigests.put(digestAlgorithm, digest);
    }
}
Also used : DataSink(com.android.apksig.util.DataSink) IOException(java.io.IOException) DataSource(com.android.apksig.util.DataSource) ChainedDataSource(com.android.apksig.internal.util.ChainedDataSource) ByteBufferDataSource(com.android.apksig.internal.util.ByteBufferDataSource) DigestException(java.security.DigestException) MessageDigest(java.security.MessageDigest)

Example 20 with DataSource

use of com.android.apksig.util.DataSource in project apksig by venshine.

the class ApkSigningBlockUtilsLite method findSignature.

/**
 * Returns the APK Signature Scheme block contained in the provided APK file for the given ID
 * and the additional information relevant for verifying the block against the file.
 *
 * @param blockId the ID value in the APK Signing Block's sequence of ID-value pairs
 *                identifying the appropriate block to find, e.g. the APK Signature Scheme v2
 *                block ID.
 *
 * @throws SignatureNotFoundException if the APK is not signed using given APK Signature Scheme
 * @throws IOException if an I/O error occurs while reading the APK
 */
public static SignatureInfo findSignature(DataSource apk, ZipSections zipSections, int blockId) throws IOException, SignatureNotFoundException {
    // Find the APK Signing Block.
    DataSource apkSigningBlock;
    long apkSigningBlockOffset;
    try {
        ApkUtilsLite.ApkSigningBlock apkSigningBlockInfo = ApkUtilsLite.findApkSigningBlock(apk, zipSections);
        apkSigningBlockOffset = apkSigningBlockInfo.getStartOffset();
        apkSigningBlock = apkSigningBlockInfo.getContents();
    } catch (ApkSigningBlockNotFoundException e) {
        throw new SignatureNotFoundException(e.getMessage(), e);
    }
    ByteBuffer apkSigningBlockBuf = apkSigningBlock.getByteBuffer(0, (int) apkSigningBlock.size());
    apkSigningBlockBuf.order(ByteOrder.LITTLE_ENDIAN);
    // Find the APK Signature Scheme Block inside the APK Signing Block.
    ByteBuffer apkSignatureSchemeBlock = findApkSignatureSchemeBlock(apkSigningBlockBuf, blockId);
    return new SignatureInfo(apkSignatureSchemeBlock, apkSigningBlockOffset, zipSections.getZipCentralDirectoryOffset(), zipSections.getZipEndOfCentralDirectoryOffset(), zipSections.getZipEndOfCentralDirectory());
}
Also used : ApkSigningBlockNotFoundException(com.android.apksig.apk.ApkSigningBlockNotFoundException) ApkUtilsLite(com.android.apksig.apk.ApkUtilsLite) ByteBuffer(java.nio.ByteBuffer) DataSource(com.android.apksig.util.DataSource)

Aggregations

DataSource (com.android.apksig.util.DataSource)29 RandomAccessFile (java.io.RandomAccessFile)11 Test (org.junit.Test)10 ByteBuffer (java.nio.ByteBuffer)7 ArrayList (java.util.ArrayList)6 ApkFormatException (com.android.apksig.apk.ApkFormatException)5 ApkSigningBlockUtils (com.android.apksig.internal.apk.ApkSigningBlockUtils)5 IOException (java.io.IOException)5 ApkUtils (com.android.apksig.apk.ApkUtils)4 ByteBufferDataSource (com.android.apksig.internal.util.ByteBufferDataSource)4 SignerConfig (com.android.apksig.SigningCertificateLineage.SignerConfig)3 CentralDirectoryRecord (com.android.apksig.internal.zip.CentralDirectoryRecord)3 DataSink (com.android.apksig.util.DataSink)3 File (java.io.File)3 MessageDigest (java.security.MessageDigest)3 ApkSigningBlockNotFoundException (com.android.apksig.apk.ApkSigningBlockNotFoundException)2 SignatureInfo (com.android.apksig.internal.apk.SignatureInfo)2 ChainedDataSource (com.android.apksig.internal.util.ChainedDataSource)2 Pair (com.android.apksig.internal.util.Pair)2 ZipFormatException (com.android.apksig.zip.ZipFormatException)2