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;
}
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;
}
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;
}
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);
}
}
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());
}
Aggregations