android签名校验代码,Android签名验证解析

本文详细解析了Android安装APK时的签名验证过程,包括知识回顾、签名验证解析两大部分。首先介绍了签名完成后生成的MANIFEST.MF、CERT.SF和CERT.RSA文件的作用。接着详细阐述了验证过程中如何收集签名、验证MANIFEST.MF和CERT.SF文件,以及如何对比CERT.RSA文件以确认签名的正确性。通过对apk中每个文件的数据摘要值与签名的比对,确保了APK的安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、本文主要内容

知识回顾

签名验证解析

总结

本文介绍下Android在安装apk时,对签名的验证过程

2、知识回顾

在Android签名过程详解一文中,我已经详细说明签名的过程以及为什么要这么做,一起回顾下,当签名完成后,生成的3个文件分别有什么作用:

对Apk中的每个文件做一次算法(数据摘要+Base64编码),保存到MANIFEST.MF文件中

对MANIFEST.MF整个文件做一次算法(数据摘要+Base64编码),存放到CERT.SF文件的头属性中,在对MANIFEST.MF文件中各个属性块做一次算法(数据摘要+Base64编码),存到到一个属性块中。

对CERT.SF文件做签名,内容存档到CERT.RSA中

让我们带着这些基础知识来看看签名的验证过程

3、签名验证解析

Android Apk安装过程解析一文中阐述了apk安装过程,其中在 installPackageLI 方法中将验证签名。

//收集签名并验证

try {

pp.collectCertificates(pkg, parseFlags);

} catch (PackageParserException e) {

res.setError("Failed collect during installPackageLI", e);

return;

}

跟踪collectCertificates方法,它在 PackageParser 类当中:

private static void collectCertificates(Package pkg, File apkFile, int flags)

throws PackageParserException {

final String apkPath = apkFile.getAbsolutePath();

StrictJarFile jarFile = null;

try {

jarFile = new StrictJarFile(apkPath);

// Always verify manifest, regardless of source

//验证apk有没有androidmenifest.xml文件,如果没有则抛出异常

final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);

if (manifestEntry == null) {

throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,

"Package " + apkPath + " has no manifest");

}

final List toVerify = new ArrayList<>();

toVerify.add(manifestEntry);

// If we're parsing an untrusted package, verify all contents

//如果是不被信任的应用,那么将apk中除文件夹、META-INF文件夹内的文件、androidmenifest.xml的其它文件entry都添加到要验证的列表中

if ((flags & PARSE_IS_SYSTEM) == 0) {

final Iterator i = jarFile.iterator();

while (i.hasNext()) {

final ZipEntry entry = i.next();

if (entry.isDirectory()) continue;

if (entry.getName().startsWith("META-INF/")) continue;

if (entry.getName().equals(ANDROID_MANIFEST_FILENAME)) continue;

toVerify.add(entry);

}

}

// Verify that entries are signed consistently with the first entry

// we encountered. Note that for splits, certificates may have

// already been populated during an earlier parse of a base APK.

//验证每一个entry

for (ZipEntry entry : toVerify) {

//loadCertificates方法中将验证MANIFEST.MF文件以及CERT.SF

final Certificate[][] entryCerts = loadCertificates(jarFile, entry);

if (ArrayUtils.isEmpty(entryCerts)) {

throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,

"Package " + apkPath + " has no certificates at entry "

+ entry.getName());

}

final Signature[] entrySignatures = convertToSignatures(entryCerts);

if (pkg.mCertificates == null) {

pkg.mCertificates = entryCerts;

pkg.mSignatures = entrySignatures;

pkg.mSigningKeys = new ArraySet();

for (int i=0; i < entryCerts.length; i++) {

pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());

}

} else {

//签名对比,相当于验证CERT.RSA中文件的内容

if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {

throw new PackageParserException(

INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath

+ " has mismatched certificates at entry "

+ entry.getName());

}

}

}

} catch (GeneralSecurityException e) {

throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,

"Failed to collect certificates from " + apkPath, e);

} catch (IOException | RuntimeException e) {

throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,

"Failed to collect certificates from " + apkPath, e);

} finally {

closeQuietly(jarFile);

}

}

方法中存在一个列表,toVerify ,待验证的列表,然后通过循环将apk中除文件夹、META-INF文件夹内的文件以及androidmenifest.xml以外的文件都添加到此列表中来,以上代码是否感觉非常熟悉?

// If we're parsing an untrusted package, verify all contents

//如果是不被信任的应用&#

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值