use of com.android.apksig.internal.apk.ContentDigestAlgorithm in project apksig by venshine.
the class V4SchemeSigner method generateV4Signature.
/**
* Generate v4 signature and hash tree for a given APK.
*/
public static Pair<V4Signature, byte[]> generateV4Signature(DataSource apkContent, SignerConfig signerConfig) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
// Salt has to stay empty for fs-verity compatibility.
final byte[] salt = null;
// Not used by apksigner.
final byte[] additionalData = null;
final long fileSize = apkContent.size();
// Obtaining first supported digest from v2/v3 blocks (SHA256 or SHA512).
final byte[] apkDigest = getApkDigest(apkContent);
// Obtaining the merkle tree and the root hash in verity format.
ApkSigningBlockUtils.VerityTreeAndDigest verityContentDigestInfo = ApkSigningBlockUtils.computeChunkVerityTreeAndDigest(apkContent);
final ContentDigestAlgorithm verityContentDigestAlgorithm = verityContentDigestInfo.contentDigestAlgorithm;
final byte[] rootHash = verityContentDigestInfo.rootHash;
final byte[] tree = verityContentDigestInfo.tree;
final Pair<Integer, Byte> hashingAlgorithmBlockSizePair = convertToV4HashingInfo(verityContentDigestAlgorithm);
final V4Signature.HashingInfo hashingInfo = new V4Signature.HashingInfo(hashingAlgorithmBlockSizePair.getFirst(), hashingAlgorithmBlockSizePair.getSecond(), salt, rootHash);
// Generating SigningInfo and combining everything into V4Signature.
final V4Signature signature;
try {
signature = generateSignature(signerConfig, hashingInfo, apkDigest, additionalData, fileSize);
} catch (InvalidKeyException | SignatureException | CertificateEncodingException e) {
throw new InvalidKeyException("Signer failed", e);
}
return Pair.of(signature, tree);
}
use of com.android.apksig.internal.apk.ContentDigestAlgorithm in project apksig by venshine.
the class V4SchemeSigner method pickBestDigest.
private static byte[] pickBestDigest(List<ApkSigningBlockUtils.Result.SignerInfo.ContentDigest> contentDigests) throws SignatureException {
if (contentDigests == null || contentDigests.isEmpty()) {
throw new SignatureException("Should have at least one digest");
}
int bestAlgorithmOrder = -1;
byte[] bestDigest = null;
for (ApkSigningBlockUtils.Result.SignerInfo.ContentDigest contentDigest : contentDigests) {
final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.findById(contentDigest.getSignatureAlgorithmId());
final ContentDigestAlgorithm contentDigestAlgorithm = signatureAlgorithm.getContentDigestAlgorithm();
if (!isSupported(contentDigestAlgorithm, true)) {
continue;
}
final int algorithmOrder = digestAlgorithmSortingOrder(contentDigestAlgorithm);
if (bestAlgorithmOrder < algorithmOrder) {
bestAlgorithmOrder = algorithmOrder;
bestDigest = contentDigest.getValue();
}
}
if (bestDigest == null) {
throw new SignatureException("Failed to find a supported digest in the source APK");
}
return bestDigest;
}
use of com.android.apksig.internal.apk.ContentDigestAlgorithm in project apksig by venshine.
the class V4SchemeVerifier method verifyRootHashAndTree.
private static void verifyRootHashAndTree(DataSource apkContent, ApkSigningBlockUtils.Result.SignerInfo signerInfo, byte[] expectedDigest, byte[] expectedTree) throws IOException, NoSuchAlgorithmException {
ApkSigningBlockUtils.VerityTreeAndDigest actualContentDigestInfo = ApkSigningBlockUtils.computeChunkVerityTreeAndDigest(apkContent);
ContentDigestAlgorithm algorithm = actualContentDigestInfo.contentDigestAlgorithm;
final byte[] actualDigest = actualContentDigestInfo.rootHash;
final byte[] actualTree = actualContentDigestInfo.tree;
if (!Arrays.equals(expectedDigest, actualDigest)) {
signerInfo.addError(ApkVerifier.Issue.V4_SIG_APK_ROOT_DID_NOT_VERIFY, algorithm, toHex(expectedDigest), toHex(actualDigest));
return;
}
// Only check verity tree if it is not empty
if (expectedTree != null && !Arrays.equals(expectedTree, actualTree)) {
signerInfo.addError(ApkVerifier.Issue.V4_SIG_APK_TREE_DID_NOT_VERIFY, algorithm, toHex(expectedDigest), toHex(actualDigest));
return;
}
signerInfo.verifiedContentDigests.put(algorithm, actualDigest);
}
use of com.android.apksig.internal.apk.ContentDigestAlgorithm 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.internal.apk.ContentDigestAlgorithm in project apksig by venshine.
the class ApkVerifier method getApkContentDigestFromV1SigningScheme.
private static Map<ContentDigestAlgorithm, byte[]> getApkContentDigestFromV1SigningScheme(List<CentralDirectoryRecord> cdRecords, DataSource apk, ApkUtils.ZipSections zipSections) throws IOException, ApkFormatException {
CentralDirectoryRecord manifestCdRecord = null;
Map<ContentDigestAlgorithm, byte[]> v1ContentDigest = new EnumMap<>(ContentDigestAlgorithm.class);
for (CentralDirectoryRecord cdRecord : cdRecords) {
if (MANIFEST_ENTRY_NAME.equals(cdRecord.getName())) {
manifestCdRecord = cdRecord;
break;
}
}
if (manifestCdRecord == null) {
// thus an empty digest will invalidate that signature.
return v1ContentDigest;
}
try {
byte[] manifestBytes = LocalFileRecord.getUncompressedData(apk, manifestCdRecord, zipSections.getZipCentralDirectoryOffset());
v1ContentDigest.put(ContentDigestAlgorithm.SHA256, computeSha256DigestBytes(manifestBytes));
return v1ContentDigest;
} catch (ZipFormatException e) {
throw new ApkFormatException("Failed to read APK", e);
}
}
Aggregations