android应用签名详解

参考文章

http://www.360doc.com/content/12/1225/15/5633521_256180351.shtml

http://www.cnblogs.com/xiwix/archive/2012/04/15/2447910.html

http://www.360doc.com/content/14/0429/11/2306903_373148270.shtml

不要去硬记。
你只要想:既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密;同理,既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证

重点参考:https://www.cnblogs.com/SirSmith/p/4985571.html

注意:2套非对称加密机制和1套不可逆加密机制,共同完成的数字签名整个过程。

保证了

1,正确解密,且只有指定对方可以正确解密

2,发送方的身份认证

3,发送消息的完整性


摘要运算:不可逆加密,如md5,sha1

A的私钥加密:签名;

A的公钥解密是用来验证;因为公钥解密是不安全的,所以在公钥解密之前有一个摘要运算加密;

B公钥加密:这才是真正的原文加密内容部分

B私钥解密:这才是获取原文的


数字签名目的

防止部分开放商可能通过使用相同的Package Name来混淆替换已经安装的程序,我们需要对我们发布的APK文件进行唯一签名,保证我们每次发布的版本的一致性(如自动更新不会因为版本不一致而无法安装);也就是说Android不允许有包名相同的应用同时存在手机中;同时,在权限检查方面,对于申请权限的  protection level  signature 或者 signatureOrSystem 的,会检查权限申请者和权限声明者的证书是否是一致的


以下,我将先介绍普及一些基本概念,最后一步是整个数字签名加密和解密的流程。功底好的同学可以直接看最后一步,若有幸能得大牛浏览到本文,还望能多多指点在下对此知识点理解中的不足之处。


公钥和私钥

公钥和私钥就是俗称的不对称加密方式,是从以前的对称加密(使用用户名与密码)方式的提高。用电子邮件的方式说明一下原理。
使用公钥与私钥的目的就是实现安全的电子邮件,必须实现如下目的:
1. 我发送给你的内容必须加密,在邮件的传输过程中不能被别人看到。
2. 必须保证是我发送的邮件,不是别人冒充我的。
  要达到这样的目标必须发送邮件的两人都有公钥和私钥。
  公钥,就是给大家用的,你可以通过电子邮件发布,可以通过网站让别人下载,公钥其实是用来加密/验章用的。私钥,就是自己的,必须非常小心保存,最好加上 密码,私钥是用来解密/签章,首先就Key的所有权来说,私钥只有个人拥有。公钥与私钥的作用是:用公钥加密的内容只能用私钥解密,用私钥加密的内容只能 用公钥解密。
  比如说,我要给你发送一个加密的邮件。首先,我必须拥有你的公钥,你也必须拥有我的公钥。
  首先,我用你的公钥给这个邮件加密,这样就保证这个邮件不被别人看到,而且保证这个邮件在传送过程中没有被修改。你收到邮件后,用你的私钥就可以解密,就能看到内容。
  其次我用我的私钥给这个邮件加密,发送到你手里后,你可以用我的公钥解密。因为私钥只有我手里有,这样就保证了这个邮件是我发送的。
  当A->B资料时,A会使用B的公钥加密,这样才能确保只有B能解开,否则普罗大众都能解开加密的讯息,就是去了资料的保密性。验证方面则是使用签 验章的机制,A传资料给大家时,会以自己的私钥做签章,如此所有收到讯息的人都可以用A的公钥进行验章,便可确认讯息是由 A 发出来的了。


公钥加密,只有我可以解密;

私钥加密,有公钥的人都可以解密(公钥是开放的,所以可以有很多人有公钥);而且解密得到的信息一定是我发的,私钥就等于代表了我的身份。所以,用私钥加密的文件,就带有我个人信息,这就是大家说的数字签名。


公钥和私钥是相对的,他们相互解密。

公钥加密,私钥解密;

私钥加密是数字签名,公钥验证。


公钥和私钥的生成:

eytooljava证书管理工具,用于生成自权威认证的数字证书keystorekeystore中包含了key entity(私钥和配对公钥)和trusted certificate entities(只含公钥)两种数据

生成keystore

keytool -genkey -v -keystore D:\keytool\android_aimee.keystore -alias D:\keytool\android_aimee.keystore -keyalg RSA -validity 20000


-genkey:在用户主目录下产生“.keystore”,默认在C:\Documents and Settings\aimeejin目录下

-v:显示密钥库中的证书详细信息

-keystore:指定密钥库的名称(产生的各类信息将不在.keystore文件中)

-alias:产生别名,不指定情况下默认为mykey,包含用户的公钥、私钥和证书

-keyalg:指定密钥的算法 ( RSA DSA(如果不指定默认采用DSA)

-validity:指定创建的证书有效期多少天

这里并没有一次性完成证书生成,如拥有者的信息、keystore密码等是通过命令行输入的,也可以直接在keytool命令中通过-dname-storepass等指定 


密钥

密钥分为两种:对称密钥与非对称密钥

对称密钥:使用同一个密钥进行加密和解密

非对称密钥:使用不同的密钥进行加密和解密。典型的公钥、私钥互相加密解密过程。


RSA算法

RSA公钥加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积的值公开作为加密密钥(公钥),而两个大素数就是私钥。

理论上是不可能通过公钥计算出私钥的。但是现在分布式计算和量子计算机发展日趋成熟,RSA的加密安全性也是受到了挑战。

为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。

它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。


RSA的算法涉及三个参数,n、e1、e2。

其中,n是两个大质数p、q的积,n的二进制表示时所占用的位数,就是所谓的密钥长度。

e1和e2是一对相关的值

e1可以任意取,但要求e1与(p-1)*(q-1)互质;

e2,要求(e2*e1)mod((p-1)*(q-1))=1。  其中, mod(a,b):表示a除以b后的余数。

(n,e1),(n,e2)就是密钥对。其中(n,e1)为公钥,(n,e2)为私钥。

RSA加密算法和解密算法是完全相同的,设A为明文,B为密文,则:A=B^e2 mod n;B=A^e1 mod n;(公钥加密体制中,一般用公钥加密,私钥解密)e1和e2可以互换使用,即:A=B^e1 mod n;B=A^e2 mod n;


私钥一定要保证安全,因为私钥是可以推算出来公钥的。但是公钥从理论上是不可以推算出来私钥。

1,从一个私钥推算公钥,正常的话需要时间极短,256位的话肯定不到一秒。但是我贴出的那个程序优化的不好,所以比较慢。如果10的n次方个私钥要推算成公钥,那么所花的时间就得乘以10的n次方倍,当然啦,这个可以并行加速。
2,理论上可以生成所有合法的私钥,但是没办法把全部私钥都穷举一遍,更没可能把那些私钥全存储起来。只能在被查询的时候临时生成。
3,私钥推算公钥比四则运算要略复杂一些,256位的私钥推算公钥,程序优化的好的话,一秒钟以内没问题。

如果攻击者修改程序,没有私钥无法生成CERT.RSA中的数字签名,所以私钥一定要保管好!CERT.RSACERT.SF文件的后缀名不能变,名字可以随意起,但必须相同


信息摘要算法

消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。

现在,消息摘要算法主要应用在“数字签名”领域,作为对明文的摘要算法。著名的摘要算法有RSA公司的MD5算法SHA-1算法及其大量的变体。

特点:

无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。一般认为,摘要的最终输出越长,该摘要算法就越安全。

只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。

消息摘要函数是无陷门的单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息。


数字证书(Certification)

数字证书是一个经证书授权中心数字签名的包含公钥拥有者信息以及公钥文件。

最简单的数字证书包含一个公钥文件、名称以及证书授权中心的数字签名。数字证书还有一个重要的特征就是只在特定的时间段内有效。

在android的签名apk里,CERT.RSA就是格式为PKCS7的数字证书,其中证书发行者对证书的签名是对CERT.SF文件的数字签名(这里我理解,私钥对MANIFEST.MF加密后生成的CERT.SF就是数字签名的过程,也就是MANIFEST.MF+私钥加密签名==CERT.SF),所以是自签名证书。



以下以android的apk为例来理解android的apk升级安装过程中,数字证书,数字签名是如何发挥作用的。

生成MANIFEST.MF文件(摘要信息)

通过消息摘要算法生成固定长度的摘要信息。

作用:

1,把任意长度的输入,通过散列算法变成固定长度的输出(摘要信息)

2,通过这个摘要信息复原原来的信息

3,保证不同信息的摘要信息彼此不同

Manifest manifest = addDigestsToManifest(inputJar);
je = new JarEntry(JarFile.MANIFEST_NAME);
je.setTime(timestamp);
outputJar.putNextEntry(je);
manifest.write(outputJar);


以下是部分摘要信息

Name: res/drawable-hdpi/watch_face_bg_normal5.png
SHA1-Digest: Gr/+YhPKSX/J6TFB24XGl45C3Ao=

Name: resources.arsc
SHA1-Digest: Tro8zk1E8fsr7KA8XwpO6xy9OEc=

Name: res/drawable-hdpi/watch_face_bg_normal29.png
SHA1-Digest: zgVxKIzNVZRoix7+oOXEurr6rG8=

Name: res/drawable-hdpi/watch_face_minute_normal.png
SHA1-Digest: QqhylV5AQhkRuRmZw9aMI8nAtTw=

Name: AndroidManifest.xml
SHA1-Digest: lte1WLHKdYlOAK9G9p5GMoBfguE=



生成CERT.SF文件

RSA是一种非对称加密算法。用私钥通过RSA算法对摘要信息MANIFEST.MF进行加密(私钥加密也可以叫做签名)后会生成文件CERT.SF。

在安装时只能使用公钥才能解密它。解密之后,将它与未加密的摘要信息(MANIFEST.MF文件中的信息)进行对比,如果相符,则表明内容没有被异常修改。

Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(privateKey);
je = new JarEntry(CERT_SF_NAME);
je.setTime(timestamp);
outputJar.putNextEntry(je);
writeSignatureFile(manifest,
new SignatureOutputStream(outputJar, signature));


CERT.RSA文件

CERT.RSA文件中保存了公钥和所采用的加密算法等信息。


apk签名的对比

通过Android签名机制的分析,我们从理论上证明了通过APK公钥的比对能判断一个APK的发布机构。并且这个发布机构是很难伪装的,我们暂时可以认为是不可伪装的。

证书中包含了公钥和证书的其他基本信息。公钥不同,证书肯定互不相同。我们可以通过certificate的getPublicKey方法获取公钥信息。所以比对签名证书本质上就是比对公钥信息。

源码中有一个隐藏的类用于APK包的解析。这个类叫PackageParser,路径为frameworks\base\core\java\android\content\pm\PackageParser.java。当我们需要获取APK包的相关信息时,可以直接使用这个类,下面代码就是一个例子函数:

    private PackageInfo parsePackage(String archiveFilePath, int flags){
          
          PackageParser packageParser = new PackageParser(archiveFilePath);
          DisplayMetrics metrics = new DisplayMetrics();
          metrics.setToDefaults();
         final File sourceFile = new File(archiveFilePath);
          PackageParser.Package pkg = packageParser.parsePackage(
                  sourceFile, archiveFilePath, metrics, 0);
          if (pkg == null) {
             return null;
         }
         
         packageParser.collectCertificates(pkg, 0); 
         
         return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0);
     }

其中参数archiveFilePath指定APK文件路径;flags需设置PackageManager.GET_SIGNATURES位,以保证返回证书签名信息。

具体如何通过PackageParser获取签名信息在此处不做详述,具体代码请参考PackageParser中的public boolean collectCertificates(Package pkg, int flags)和private Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer)方法。至于如何在Android应用开发中使用隐藏的类及方法,可以参看我的这篇文章:《Android应用开发中如何使用隐藏API》。

紧接着,我们就可以通过packageInfo.signatures来访问到APK的签名信息。还需要说明的是 Android中Signature和Java中Certificate的对应关系。它们的关系如下面代码所示:

     pkg.mSignatures = new Signature[certs.length];
     for (int i=0; i<N; i++) {
         pkg.mSignatures[i] = new Signature(
         certs[i].getEncoded());



加密解密的流程图



那么,这两种混合加密方式是如何确保软件安装升级的安全的呢?

关键点

1,只有公钥才能解密CERT.SF,且该公钥也只能解开该CERT.SF

那么,只要验证公钥是正确的,则解密后得到的摘要信息一定是安全的。(表示该CERT.SF一定是我发给你的,而不是别人。而且解密得到的摘要信息也一定是我想要给你用来验证原文的)

2,原文被信息摘要算法(MD5和SHA-1算法)加密后得到的摘要信息是唯一的,相同的输入一定得到相同的输出,不同的输入一定是得到不同的输出。

对比两种信息摘要MANIFEST.MF,如果是一样的,则表示我原文是完整的而且没有被别人修改过原文。

那么,综合起来就是:东西一定是我发给你的,而且东西是完整的而且没有被别人修改过原文,可以放心升级安装。




©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值