Android签名知识总结
来源:互联网 发布:js date 编辑:程序博客网 时间:2024/05/22 21:40
1.签名相关文件的简介
MANIFEST.MF
程序遍历apk包中的所有文件,对非文件夹及未签名文件的文件,逐个生成SHA1的数字签名信息,再用Base64进行编码,最终将这些(摘要)信息存于该文件中,该文件未涉及秘钥信息的使用。(摘要信息)
CERT.SF
存放MANIFEST.MF通过私钥及加密算法加密后的信息。(安装时可通过公钥解密后再与MANIFEST.MF对比信息一致性)。该文件涉及到签名时私钥的使用。
ERT.RSA
CERT.RSA文件中保存了公钥、所采用的加密算法等信息。(数字证书Certificate)
- .SF与.RSA文件的命名可修改,但是两者需要保证一致
- Android签名机制不能阻止APK包被修改,但修改后的再签名无法与原先的签名保持一致。(拥有私钥的情况除外)。
- APK包加密的公钥就打包在APK包内,且不同的私钥对应不同的公钥。换句话,不同的私钥签名的APK公钥也必不相同。所以我们可以根据公钥的对比,来判断私钥是否一致。
2.数字签名信息及MD5与SHA1简介
- 数字签名(signature):在安卓签名过程中,(签名工具)会根据开发者提供的姓名地址及私钥等信息生成一串数字签名(字符串).
- MD5 (Message Digest 信息摘要)、SHA1(Secure Hash Algorithm安全哈希算法)为HASH(哈希)算法或者称之为摘要算法(Digest Algorithm),即将无限制长度的字符串转换成固定长度(MD5是16个字符16*8=128bits,SHA1是20个字节=160bits 20*8bits的长度)。得到的是摘要,输入是无限制的字符。(常用MD5来进行加密处理)
- RSA文件中的签名信息(例:QQ):
(这里的MD5、SHA1信息即数字证书信息(certificate),是通过相应算法计算后得出的。未经修改,则这边的信息应该是与开发者签名时所看到的是一致的。因此可以通过MD5或者是SHA1值来比较该apk包是否被恶意篡改) - 补充两句数字证书和数字签名的一点区别:
- The digital signature(数字签名) for the JAR file that was generated with the signer’s private key
- The certificate(数字证书) containing the signer’s public key, to be used by anyone wanting to verify the signed JAR file
3.使用指令获取apk包签名信息
- jarsigner -verify -verbose -certs your_apk_path.apk
- unzip -p suspect.apk META-INF/CERT.RSA | keytool -printcert 或 unzip -p suspect.apk META-INF/*.RSA | keytool -printcert
- unzip -p suspect.apk META-INF/CERT.RSA | keytool -printcert | grep MD5 或 unzip -p suspect.apk META-INF/*.RSA | keytool -printcert | grep MD5
4.使用代码 获取apk包签名信息(Signature或者Certificate)
有两种实现方法:
- 可以使用Java自带的API(主要用到的为JarFile,JarEntry,Certificate)进行获取,所以这种
- 还有一种方法是使用系统隐藏的API PackageParser,通过反射来使用对应的API.
(但是由于安卓系统版本过多,并且不同厂商进行的修改很多,依赖反射隐藏API的方法并不能保证兼容性和通用性,因此推荐使用JAVA自带API进行获取):
代码:
import android.content.pm.Signature ;import java.io.ByteArrayInputStream ;import java.io.File ;import java.io.IOException ;import java.io.InputStream ;import java.security.MessageDigest ;import java.security.NoSuchAlgorithmException ;import java.security.cert.Certificate ;import java.security.cert.CertificateFactory ;import java.security.cert.X509Certificate ;import java.util.ArrayList ;import java.util.List ;import java.util.jar.JarEntry ;import java.util.jar.JarFile ;/*** 获取Signature串对应的MD5值* Created by wiky on 2016/1/21.*/public class SignatureCheck { public static char [] hexChar = { '0', '1' , '2', '3', '4' , '5', '6', '7' , '8' , '9', 'a', 'b' , 'c', 'd', 'e' , 'f'} ; public static void main (String[] args) { String path = args[0 ]; File f = new File(path); if (!f.exists()) { System.out.println( "文件不存在" ); } System.out.println( "文件存在,path=" +path); try { List<String> signature = getSignaturesFromApk(f); int size = signature.size() ; for ( int i = 0 ; i < size; i++) { System.out.println( "signature = " + signature.get(i)); System.out.println( "signatureMD5:" + getMD5(signature.get(i))) ; } } catch (Exception e) { e.printStackTrace(); } }//====================================获取签名(signature)信息======================================= /** * 从APK中读取签名 * @param file apk文件 * @return signatures列表 * @throws IOException */ private static List<String> getSignaturesFromApk(File file) throws IOException { List<String> signatures = new ArrayList<>(); JarFile jarFile = new JarFile(file); try { JarEntry je = jarFile.getJarEntry("AndroidManifest.xml") ; byte[] readBuffer = new byte[8192 ]; Certificate[] certs = loadCertificates(jarFile , je, readBuffer); if (certs != null) { for (Certificate c : certs) { String sig = toCharsString(c.getEncoded()) ; //这里可以获取更详细的信息 Signature signature = new Signature(c.getEncoded()); CertificateFactory certFactory = CertificateFactory.getInstance( "X.509"); X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(signature.toByteArray())) ; String pubKey = cert.getPublicKey().toString(); String signNumber = cert.getSerialNumber().toString(); System.out.println( "signName:" + cert.getSigAlgName()); System.out.println( "pubKey:" + pubKey); System.out.println( "pubKeyMD5:" + getMD5(pubKey)) ; System.out.println( "signNumber:" + signNumber); System.out.println( "subjectDN:" + cert.getSubjectDN().toString()); signatures.add(sig); } } } catch (Exception ex) { ex.printStackTrace(); } return signatures; } /** * * 加载签名 * * @param jarFile * * @param je * * @param readBuffer * * @return */ private static Certificate[] loadCertificates(JarFile jarFile , JarEntry je, byte [] readBuffer) { try { InputStream is = jarFile.getInputStream(je); while (is.read(readBuffer , 0, readBuffer.length) != - 1) { } is.close(); return je != null ? je.getCertificates() : null; } catch (IOException e) { e.printStackTrace(); } return null; }//====================================使用MD5对签名(signature)进行加密======================================= /** * 用MD5算法加密字符串 * @param val 待加密的字符串 * @return 加密后的字符串 * @throws NoSuchAlgorithmException */ public static String getMD5(String val) throws NoSuchAlgorithmException { MessageDigest md5 = MessageDigest.getInstance("MD5" );//类型可选择"MD5"、"SHA1"、"SHA-256"等 md5.update(val.getBytes()) ; byte[] m = md5.digest() ;//加密 return toHexString(m) ; } /** * * 将签名转成转成可见字符串 * * @param sigBytes * * @return */ private static String toCharsString( byte[] sigBytes) { final int N = sigBytes.length; final int N2 = N * 2; char[] text = new char[N2]; for ( int j = 0 ; j < N; j++) { byte v = sigBytes[j]; int d = (v >> 4) & 0xf ; text[j * 2] = (char ) (d >= 10 ? ( 'a' + d - 10 ) : ('0' + d)) ; d = v & 0xf; text[j * 2 + 1 ] = (char) (d >= 10 ? ('a' + d - 10) : ( '0' + d)); } return new String(text); } /** * 转换为十六进制字符串形式 */ public static String toHexString( byte[] b) { StringBuilder sb = new StringBuilder(b.length * 2); for ( int i = 0 ; i < b.length ; i++) { sb.append(hexChar[(b[i] & 0xf0) >>> 4 ]); sb.append( hexChar[b[i] & 0x0f ]); } return sb.toString(); }}
权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
5.使用情景
某些时候需要获取某个特定的apk(已安装或者未安装)的签名信息,如程序自检测,可信赖的第三方检测(应用市场),系统限定安装,判断是否为山寨软件等
0 0
- Android签名知识总结
- android 签名之必备知识
- Android签名相关知识整理
- Android签名相关知识整理
- Android签名相关知识整理
- Android:应用程序签名总结
- Android签名总结
- Android签名总结
- android 签名key总结:
- Android:应用程序签名总结
- Android签名总结
- Android 签名问题总结
- Android签名总结
- Android签名总结
- cocos2dx Android签名总结
- Android签名总结
- Android签名总结
- Android apk 签名总结
- MyBatis There is no getter for property named 'xxx' in 'class java.lang.String'
- Hibernate 通过批量ID进行查询所对应的对象集合
- 基于Udp的socket 实现
- ThinkPad S1 Yoga怎么设置U盘启动
- Android图像处理之Path
- Android签名知识总结
- java多线程
- 使用Xcode和Instruments调试解决iOS内存泄露
- Win8开机总是“配置Windows更新失败,正在还原更改”的解决方法(图)
- Ecache用法1
- 线程同步的方法:sychronized、lock、reentrantLock等总结分析
- CSS 浮动的16条规则——如果浮动非替换元素,则要指定一个明确的宽度;否则,它们会尽可能地窄
- android 数据库更新操作步骤
- javaIO流