Search in sources :

Example 6 with DataSource

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

the class FileChannelDataSourceTest method testFeedsCorrectData_whenFilePartiallyReadWithOffset.

@Test
public void testFeedsCorrectData_whenFilePartiallyReadWithOffset() throws Exception {
    byte[] fullFileContent = createFileContent(1024 * 1024 + 987654);
    RandomAccessFile raf = createRaf(fullFileContent);
    DataSource rafDataSource = new FileChannelDataSource(raf.getChannel());
    ByteArrayDataSink dataSink = new ByteArrayDataSink();
    int offset = 23456;
    int bytesToFeed = 1024 * 1024 + 12345;
    rafDataSource.feed(offset, bytesToFeed, dataSink);
    byte[] expectedBytes = Arrays.copyOfRange(fullFileContent, offset, offset + bytesToFeed);
    byte[] resultBytes = getDataSinkBytes(dataSink);
    assertArrayEquals(expectedBytes, resultBytes);
}
Also used : RandomAccessFile(java.io.RandomAccessFile) DataSource(com.android.apksig.util.DataSource) Test(org.junit.Test)

Example 7 with DataSource

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

the class ChainedDataSource method feed.

@Override
public void feed(long offset, long size, DataSink sink) throws IOException {
    if (offset + size > mTotalSize) {
        throw new IndexOutOfBoundsException("Requested more than available");
    }
    for (DataSource src : mSources) {
        // Offset is beyond the current source. Skip.
        if (offset >= src.size()) {
            offset -= src.size();
            continue;
        }
        // If the remaining is enough, finish it.
        long remaining = src.size() - offset;
        if (remaining >= size) {
            src.feed(offset, size, sink);
            break;
        }
        // If the remaining is not enough, consume all.
        src.feed(offset, remaining, sink);
        size -= remaining;
        offset = 0;
    }
}
Also used : DataSource(com.android.apksig.util.DataSource)

Example 8 with DataSource

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

the class ChainedDataSource method slice.

@Override
public DataSource slice(long offset, long size) {
    // Find the first slice.
    Pair<Integer, Long> firstSource = locateDataSource(offset);
    int beginIndex = firstSource.getFirst();
    long beginLocalOffset = firstSource.getSecond();
    DataSource beginSource = mSources[beginIndex];
    if (beginLocalOffset + size <= beginSource.size()) {
        return beginSource.slice(beginLocalOffset, size);
    }
    // Add the first slice to chaining, followed by the middle full slices, then the last.
    ArrayList<DataSource> sources = new ArrayList<>();
    sources.add(beginSource.slice(beginLocalOffset, beginSource.size() - beginLocalOffset));
    Pair<Integer, Long> lastSource = locateDataSource(offset + size - 1);
    int endIndex = lastSource.getFirst();
    long endLocalOffset = lastSource.getSecond();
    for (int i = beginIndex + 1; i < endIndex; i++) {
        sources.add(mSources[i]);
    }
    sources.add(mSources[endIndex].slice(0, endLocalOffset + 1));
    return new ChainedDataSource(sources.toArray(new DataSource[0]));
}
Also used : ArrayList(java.util.ArrayList) DataSource(com.android.apksig.util.DataSource)

Example 9 with DataSource

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

the class VerityTreeBuilder method generateVerityTree.

/**
 * Returns the byte buffer that contains the whole verity tree.
 *
 * The tree is built bottom up. The bottom level has 256-bit digest for each 4 KB block in the
 * input file.  If the total size is larger than 4 KB, take this level as input and repeat the
 * same procedure, until the level is within 4 KB.  If salt is given, it will apply to each
 * digestion before the actual data.
 *
 * The returned root hash is calculated from the last level of 4 KB chunk, similarly with salt.
 *
 * The tree is currently stored only in memory and is never written out.  Nevertheless, it is
 * the actual verity tree format on disk, and is supposed to be re-generated on device.
 */
public ByteBuffer generateVerityTree(DataSource fileSource) throws IOException {
    int digestSize = mMd.getDigestLength();
    // Calculate the summed area table of level size. In other word, this is the offset
    // table of each level, plus the next non-existing level.
    int[] levelOffset = calculateLevelOffset(fileSource.size(), digestSize);
    ByteBuffer verityBuffer = ByteBuffer.allocate(levelOffset[levelOffset.length - 1]);
    // Generate the hash tree bottom-up.
    for (int i = levelOffset.length - 2; i >= 0; i--) {
        DataSink middleBufferSink = new ByteBufferSink(slice(verityBuffer, levelOffset[i], levelOffset[i + 1]));
        DataSource src;
        if (i == levelOffset.length - 2) {
            src = fileSource;
            digestDataByChunks(src, middleBufferSink);
        } else {
            src = DataSources.asDataSource(slice(verityBuffer.asReadOnlyBuffer(), levelOffset[i + 1], levelOffset[i + 2]));
            digestDataByChunks(src, middleBufferSink);
        }
        // If the output is not full chunk, pad with 0s.
        long totalOutput = divideRoundup(src.size(), CHUNK_SIZE) * digestSize;
        int incomplete = (int) (totalOutput % CHUNK_SIZE);
        if (incomplete > 0) {
            byte[] padding = new byte[CHUNK_SIZE - incomplete];
            middleBufferSink.consume(padding, 0, padding.length);
        }
    }
    return verityBuffer;
}
Also used : DataSink(com.android.apksig.util.DataSink) ByteBuffer(java.nio.ByteBuffer) DataSource(com.android.apksig.util.DataSource)

Example 10 with DataSource

use of com.android.apksig.util.DataSource in project LSPatch by LSPosed.

the class SigningExtension method onOutputZipEntriesWritten.

private void onOutputZipEntriesWritten() throws IOException {
    if (!dirty) {
        return;
    }
    // Check whether we should output an APK Signing Block which contains v2 signatures
    byte[] apkSigningBlock;
    byte[] centralDirBytes = zFile.getCentralDirectoryBytes();
    byte[] eocdBytes = zFile.getEocdBytes();
    ApkSignerEngine.OutputApkSigningBlockRequest2 addV2SignatureRequest;
    // file (as reported to this extension).
    if (cachedApkSigningBlock != null) {
        apkSigningBlock = cachedApkSigningBlock;
        addV2SignatureRequest = null;
    } else {
        DataSource centralDir = DataSources.asDataSource(ByteBuffer.wrap(centralDirBytes));
        DataSource eocd = DataSources.asDataSource(ByteBuffer.wrap(eocdBytes));
        long zipEntriesSizeBytes = zFile.getCentralDirectoryOffset() - zFile.getExtraDirectoryOffset();
        DataSource zipEntries = zFile.asDataSource(0, zipEntriesSizeBytes);
        try {
            addV2SignatureRequest = signer.outputZipSections2(zipEntries, centralDir, eocd);
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | ApkFormatException | IOException e) {
            throw new IOException("Failed to generate v2 signature", e);
        }
        if (addV2SignatureRequest != null) {
            apkSigningBlock = addV2SignatureRequest.getApkSigningBlock();
            if (sdkDependencyData != null) {
                apkSigningBlock = SigningBlockUtils.addToSigningBlock(apkSigningBlock, sdkDependencyData, DEPENDENCY_INFO_BLOCK_ID);
            }
            apkSigningBlock = Bytes.concat(new byte[addV2SignatureRequest.getPaddingSizeBeforeApkSigningBlock()], apkSigningBlock);
        } else {
            apkSigningBlock = new byte[0];
            if (sdkDependencyData != null) {
                apkSigningBlock = SigningBlockUtils.addToSigningBlock(apkSigningBlock, sdkDependencyData, DEPENDENCY_INFO_BLOCK_ID);
                int paddingSize = ApkSigningBlockUtils.generateApkSigningBlockPadding(zipEntries, /* apkSigningBlockPaddingSupported */
                true).getSecond();
                apkSigningBlock = Bytes.concat(new byte[paddingSize], apkSigningBlock);
            }
        }
        cachedApkSigningBlock = apkSigningBlock;
    }
    // Insert the APK Signing Block into the output right before the ZIP Central Directory and
    // accordingly update the start offset of ZIP Central Directory in ZIP End of Central
    // Directory.
    zFile.directWrite(zFile.getCentralDirectoryOffset() - zFile.getExtraDirectoryOffset(), apkSigningBlock);
    zFile.setExtraDirectoryOffset(apkSigningBlock.length);
    if (addV2SignatureRequest != null) {
        addV2SignatureRequest.done();
    }
}
Also used : ApkFormatException(com.android.apksig.apk.ApkFormatException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) SignatureException(java.security.SignatureException) IOException(java.io.IOException) InvalidKeyException(java.security.InvalidKeyException) ApkSignerEngine(com.android.apksig.ApkSignerEngine) DefaultApkSignerEngine(com.android.apksig.DefaultApkSignerEngine) 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