/** * Outputs this record, replacing its extra field with the provided one, and returns returns the * number of bytes output. */ public long outputRecordWithModifiedExtra( DataSource sourceApk, ByteBuffer extra, DataSink output) throws IOException { long recordStartOffsetInSource = getStartOffsetInArchive(); int extraStartOffsetInRecord = getExtraFieldStartOffsetInsideRecord(); int extraSizeBytes = extra.remaining(); int headerSize = extraStartOffsetInRecord + extraSizeBytes; ByteBuffer header = ByteBuffer.allocate(headerSize); header.order(ByteOrder.LITTLE_ENDIAN); sourceApk.copyTo(recordStartOffsetInSource, extraStartOffsetInRecord, header); header.put(extra.slice()); header.flip(); ZipUtils.setUnsignedInt16(header, EXTRA_LENGTH_OFFSET, extraSizeBytes); long outputByteCount = header.remaining(); output.consume(header); long remainingRecordSize = getSize() - mDataStartOffset; sourceApk.feed(recordStartOffsetInSource + mDataStartOffset, remainingRecordSize, output); outputByteCount += remainingRecordSize; return outputByteCount; }
private static ByteBuffer getZipCentralDirectory( DataSource apk, ApkUtils.ZipSections apkSections) throws IOException, ApkFormatException { long cdSizeBytes = apkSections.getZipCentralDirectorySizeBytes(); if (cdSizeBytes > Integer.MAX_VALUE) { throw new ApkFormatException("ZIP Central Directory too large: " + cdSizeBytes); } long cdOffset = apkSections.getZipCentralDirectoryOffset(); ByteBuffer cd = apk.getByteBuffer(cdOffset, (int) cdSizeBytes); cd.order(ByteOrder.LITTLE_ENDIAN); return cd; }
long centralDirOffsetForDigesting = beforeCentralDir.size(); ByteBuffer eocdBuf = ByteBuffer.allocate((int) eocd.size()); eocdBuf.order(ByteOrder.LITTLE_ENDIAN); eocd.copyTo(0, (int) eocd.size(), eocdBuf); eocdBuf.flip(); ZipUtils.setZipEocdCentralDirectoryOffset(eocdBuf, centralDirOffsetForDigesting);
inputApk.slice( 0, (inputApkSigningBlockOffset != -1) inputApkLfhSection.feed(inputOffset, chunkSize, outputApkOut); outputOffset += chunkSize; inputOffset = inputLocalFileHeaderStartOffset; inputLocalFileRecord = LocalFileRecord.getRecord( inputApkLfhSection, inputCdRecord, inputApkLfhSection.size()); } catch (ZipFormatException e) { throw new ApkFormatException("Malformed ZIP entry: " + inputCdRecord.getName(), e); long inputLfhSectionSize = inputApkLfhSection.size(); if (inputOffset < inputLfhSectionSize) { inputApkLfhSection.feed(inputOffset, chunkSize, outputApkOut); outputOffset += chunkSize; inputOffset = inputLfhSectionSize; inputZipSections.getZipEndOfCentralDirectory(), outputCentralDirRecordCount, outputCentralDirDataSource.size(), outputCentralDirStartOffset); outputCentralDirDataSource.feed(0, outputCentralDirDataSource.size(), outputApkOut); outputApkOut.consume(outputEocd); signerEngine.outputDone();
long fileSize = zip.size(); if (fileSize < ZIP_EOCD_REC_MIN_SIZE) { return null; long fileSize = zip.size(); if (fileSize < ZIP_EOCD_REC_MIN_SIZE) { ByteBuffer buf = zip.getByteBuffer(bufOffsetInFile, maxEocdSize); buf.order(ByteOrder.LITTLE_ENDIAN); int eocdOffsetInBuf = findZipEndOfCentralDirectoryRecord(buf);
for (DataSource input : contents) { chunkCountLong += getChunkCount(input.size(), CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES); long inputRemaining = input.size(); while (inputRemaining > 0) { int chunkSize = input.feed(inputOffset, chunkSize, mdSink); } catch (IOException e) { throw new IOException("Failed to read chunk #" + chunkIndex, e);
ByteBuffer footer = apk.getByteBuffer(centralDirStartOffset - 24, 24); footer.order(ByteOrder.LITTLE_ENDIAN); if ((footer.getLong(8) != APK_SIG_BLOCK_MAGIC_LO) "APK Signing Block offset out of range: " + apkSigBlockOffset); ByteBuffer apkSigBlock = apk.getByteBuffer(apkSigBlockOffset, 8); apkSigBlock.order(ByteOrder.LITTLE_ENDIAN); long apkSigBlockSizeInHeader = apkSigBlock.getLong(0); + apkSigBlockSizeInHeader + " vs " + apkSigBlockSizeInFooter); return Pair.of(apk.slice(apkSigBlockOffset, totalSize), apkSigBlockOffset);
@Override public void inputApkSigningBlock(DataSource apkSigningBlock) { checkNotClosed(); if ((apkSigningBlock == null) || (apkSigningBlock.size() == 0)) { return; } if (mOtherSignersSignaturesPreserved) { // TODO: Preserve blocks other than APK Signature Scheme v2 blocks of signers configured // in this engine. return; } // TODO: Preserve blocks other than APK Signature Scheme v2 blocks. }
/** * Outputs this record and returns returns the number of bytes output. */ public long outputRecord(DataSource sourceApk, DataSink output) throws IOException { long size = getSize(); sourceApk.feed(getStartOffsetInArchive(), size, output); return size; }
/** * Verifies the provided APK's APK Signature Scheme v2 signatures and returns the result of * verification. APK is considered verified only if {@link Result#verified} is {@code true}. If * verification fails, the result will contain errors -- see {@link Result#getErrors()}. * * @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 v2 signatures are found * @throws IOException if an I/O error occurs when reading the APK */ public static Result verify(DataSource apk, ApkUtils.ZipSections zipSections) throws IOException, ApkFormatException, NoSuchAlgorithmException, SignatureNotFoundException { Result result = new Result(); SignatureInfo signatureInfo = findSignature(apk, zipSections, result); DataSource beforeApkSigningBlock = apk.slice(0, signatureInfo.apkSigningBlockOffset); DataSource centralDir = apk.slice( signatureInfo.centralDirOffset, signatureInfo.eocdOffset - signatureInfo.centralDirOffset); ByteBuffer eocd = signatureInfo.eocd; verify(beforeApkSigningBlock, signatureInfo.signatureBlock, centralDir, eocd, result); return result; }
/** * Returns the APK Signature Scheme v2 block contained in the provided APK file and the * additional information relevant for verifying the block against the file. * * @throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v2 * @throws IOException if an I/O error occurs while reading the APK */ private static SignatureInfo findSignature( DataSource apk, ApkUtils.ZipSections zipSections, Result result) throws IOException, SignatureNotFoundException { // Find the APK Signing Block. The block immediately precedes the Central Directory. ByteBuffer eocd = zipSections.getZipEndOfCentralDirectory(); Pair<DataSource, Long> apkSigningBlockAndOffset = findApkSigningBlock(apk, zipSections); DataSource apkSigningBlock = apkSigningBlockAndOffset.getFirst(); long apkSigningBlockOffset = apkSigningBlockAndOffset.getSecond(); ByteBuffer apkSigningBlockBuf = apkSigningBlock.getByteBuffer(0, (int) apkSigningBlock.size()); apkSigningBlockBuf.order(ByteOrder.LITTLE_ENDIAN); // Find the APK Signature Scheme v2 Block inside the APK Signing Block. ByteBuffer apkSignatureSchemeV2Block = findApkSignatureSchemeV2Block(apkSigningBlockBuf, result); return new SignatureInfo( apkSignatureSchemeV2Block, apkSigningBlockOffset, zipSections.getZipCentralDirectoryOffset(), zipSections.getZipEndOfCentralDirectoryOffset(), eocd); }
modifiedEocd.put(eocd); modifiedEocd.flip(); ZipUtils.setZipEocdCentralDirectoryOffset(modifiedEocd, beforeApkSigningBlock.size()); Map<ContentDigestAlgorithm, byte[]> actualContentDigests; try {
if (mDataCompressed) { try (InflateSinkAdapter inflateAdapter = new InflateSinkAdapter(sink)) { lfhSection.feed(dataStartOffsetInArchive, mDataSize, inflateAdapter); long actualUncompressedSize = inflateAdapter.getOutputByteCount(); if (actualUncompressedSize != mUncompressedDataSize) { lfhSection.feed(dataStartOffsetInArchive, mDataSize, sink);
cdRecords, apk.slice(0, zipSections.getZipCentralDirectoryOffset())); if (minSdkVersion > mMaxSdkVersion) { throw new IllegalArgumentException(
ByteBuffer cd = apk.getByteBuffer(cdOffset, (int) cdSizeBytes); cd.order(ByteOrder.LITTLE_ENDIAN);
androidManifest = LocalFileRecord.getUncompressedData( lhfSection, androidManifestCdRecord, lhfSection.size()); } catch (ZipFormatException e) { throw new MinSdkVersionException(
header = apk.getByteBuffer(headerStartOffset, headerSizeWithName); } catch (IOException e) { throw new IOException("Failed to read Local File Header of " + entryName, e); extra = apk.getByteBuffer( headerStartOffset + HEADER_SIZE_BYTES + nameLength, extraLength); + ", CD start: " + cdStartOffset); ByteBuffer dataDescriptorPotentialSig = apk.getByteBuffer(dataEndOffset, 4); dataDescriptorPotentialSig.order(ByteOrder.LITTLE_ENDIAN); if (dataDescriptorPotentialSig.getInt() == DATA_DESCRIPTOR_SIGNATURE) {