Android App安装启动时签名校验
Android发布时签名
- 分发:即部署,需要签名。若要发布 .APK,必须首先使用签名密钥(也称为证书)对它进行签名。创建新证书(里面包含一对公私钥,个人/公司的信息)
秘钥的位置默认【加固需要用到】:C:\Users\USERNAME\AppData\Local\Xamarin\Mono for Android\Keystore\
Android KeyStore以及打包签名
Android KeyStore + FingerprintManager 存储密码
安卓密钥库(允许你存储加密密钥),指纹识别中也有创建key
Android上App升级更新
安卓系统本身在安装app时会对app验证签名。
测试步骤: 在本机上有一个低版本的app,然后安装一个高版本的app(分发时用不同的证书签名),
安装提示:安装失败“更新包与已安装应用的签名不一致”
建议卸载,卸载当前版本后,可以安装成功!(这个没法控制用户,,所以可以考虑在app启动时验证签名)
App启动时检测签名是否正确
对比apk签名证书的SHA1值是否自己用的签名证书的值,而不是被别人篡改过的证书的值(防止自己的应用被反编译后重新打包)
1、获取自己对app分发时签名证书的SHA1值
首先进入CMD,然后输入:
keytool -exportcert -list -v -alias huyNew -keystore "C:\Users\huy\AppData\Local\Xamarin\Mono for Android\Keystore\huyNew\huyNew.keystore"
回车
在提示下输入密钥口令(是自己设置的密码) (注:此时输入字符cmd是不显示的,请输入完整后直接回车。如果失败说明你输错了)
参考:
如何使用 keytool 获取签名证书的 SHA-1 哈希值
2、Xamarin.Android下获取app证书SHA1值
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Android.App; using Android.Content; using Android.Content.PM; using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; using Java.IO; using Java.Security; using Java.Security.Cert; using Signature = Android.Content.PM.Signature; namespace AndroidDevice.Droid { /// <summary> /// 验证签名 /// </summary> public class SignCheck { private Context context; /// <summary> /// 应用的签名 /// </summary> public String cer = null; /// <summary> /// 真实的证书 /// </summary> private String realCer = null; private static String TAG = "SignCheck"; public SignCheck(Context context) { this.context = context; this.cer = GetCertificateSHA1Fingerprint(); } public SignCheck(Context context, String realCer) { this.context = context; this.realCer = realCer; this.cer = GetCertificateSHA1Fingerprint(); } public String getRealCer() { return realCer; } /// <summary> /// 获取应用的签名 /// </summary> /// <returns></returns> public String GetCertificateSHA1Fingerprint() { //获取包管理器 PackageManager pm = context.PackageManager; //获取当前要获取 SHA1 值的包名,也可以用其他的包名,但需要注意, //在用其他包名的前提是,此方法传递的参数 Context 应该是对应包的上下文。 String packageName = context.PackageName; //返回包括在包中的签名信息。。还可以获取签名信息等 PackageInfoFlags.SigningCertificates var packageInfo = pm.GetPackageInfo(context.PackageName, PackageInfoFlags.Signatures); //签名信息 List<Signature> signatures = packageInfo.Signatures?.ToList(); if (signatures == null || signatures.Count == 0) { return ""; } byte[] cert = signatures[0].ToByteArray(); //将签名转换为字节数组流 //InputStream input = new ByteArrayInputStream(cert); System.IO.Stream input = new MemoryStream(cert); //证书工厂类,这个类实现了出厂合格证算法的功能 CertificateFactory cf = null; try { cf = CertificateFactory.GetInstance("X509"); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(TAG + e.StackTrace); } //X509 证书,X.509 是一种非常通用的证书格式 X509Certificate c = null; try { c = (X509Certificate)cf.GenerateCertificate(input); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(TAG + e.StackTrace); } String hexString = null; try { //加密算法的类,这里的参数可以使 MD4,MD5 等加密算法 MessageDigest md = MessageDigest.GetInstance("SHA1"); //获得公钥 byte[] publicKey = md.Digest(c.GetEncoded()); //字节到十六进制的格式转换 hexString = byte2HexFormatted(publicKey); } catch (NoSuchAlgorithmException e) { System.Diagnostics.Debug.WriteLine(TAG + e.StackTrace); } catch (CertificateEncodingException e) { System.Diagnostics.Debug.WriteLine(TAG + e.StackTrace); } return hexString; } //这里是将获取到得编码进行16 进制转换 private String byte2HexFormatted(byte[] arr) { StringBuilder str = new StringBuilder(arr.Length * 2); for (int i = 0; i < arr.Length; i++) { String h = arr[i].ToString("X2"); int l = h.Length; if (l == 1) h = "0" + h; if (l > 2) h = h.Substring(l - 2, l); str.Append(h.ToUpper()); if (i < (arr.Length - 1)) str.Append(':'); } return str.ToString(); } /// <summary> /// 检测签名是否正确 /// </summary> /// <returns></returns> public bool check() { if (this.realCer != null) { cer = cer.Trim(); realCer = realCer.Trim(); if (this.cer.Equals(this.realCer)) { return true; } } else { System.Diagnostics.Debug.WriteLine(TAG + "未给定真实的签名 SHA-1 值"); } return false; } } }
测试
//测试签名 SignCheck signCheck = new SignCheck(this, "27:19:6E:38:6B:87:5E:76:AD:F7:00:E7:EA:84:E4:C6:EE:E3:3D:FA"); if (signCheck.check()) { //TODO 签名正常 } else { //TODO 签名不正确 Toast.MakeText(this, "请前往官方渠道下载正版 app", ToastLength.Long); } LoadApplication(new App(signCheck.cer));
signCheck.cer 为当前app的签名证书SHA1值。判断它与SignCheck构造函数中传入的真实值是否相等即可