首页
社区
课程
招聘
[长篇]从Android中RSA算法到密码学非对称性加密算法到大数因子多项式分解(一)
发表于: 2015-8-23 23:16 12338

[长篇]从Android中RSA算法到密码学非对称性加密算法到大数因子多项式分解(一)

2015-8-23 23:16
12338

全文我已写完,但想了想,若一气贴出来篇幅巨大,容易直接把人打蒙。所以采用分期刊登的形式。

今天先说说:
android apk程序中的签名

a. 签名在哪?
一言蔽之:在apk包的META-INF\目录下

随便将一个.apk写该后缀为.zip,解压,类似如图所示。


1. META-INF\ (注:签名后的信息);
2. res\ (注:存放资源文件的目录) ;
3. AndroidManifest.xml (注:程序全局配置文件) ;
4. classes.dex (注:Dalvik字节码);
5. resources.arsc (注:编译后的二进制资源文件)。

META-INF\文件中有三个文件,分别是MANIFEST.MF, CERT.SF, CERT.RSA,如图所示。


现在有一个问题就是,三个文件怎么产生的的——签名产生的,第二个问题签名是怎么做的呢?这里Android提供了APK的签名工具signapk,通过xxx.keystore(java的密钥库、用来进行通信加密用的、比如数字签名。keystore就是用来保存密钥对的,比如公钥和私钥)提供的信息,对APK进行签名,生成的META-INF\文件。

1.MANIFEST.MF文件:遍历APK包中的每一个文件,利用SHA1算法生成这些文件的摘要信息。
2.CERT.SF文件:CERT.SF中保存的是MANIFEST.MF的摘要值
3.CERT.RSA文件:这个文件保存了签名和公钥证书。并且这个证书是自签名的。签名的生成一定会有私钥参与,签名用到的信息摘要就是CERT.SF内容。

b. 为什么apk要签名?
一言蔽之:签名后的apk中因为有每个包文件的消息摘要,从而保证了apk在传输过程中的数据完整性。因为开发者持有私钥,用户们持有公钥,所以保证了用户和开发者之间有效正确的认证关系,于是才实现下面所列的三条功能。

所有的Android应用程序都要求开发人员用一个证书进行数字签名,android系统不会安装没有进行签名的由于程序。平时我们的程序可以在模拟器上安装并运行,是因为在应用程序开发期间,由于是以Debug面试进行编译的,因此ADT根据会自动用默认的密钥和证书来进行签名,而在以发布模式编译时,apk文件就不会得到自动签名,这样就需要进行手工签名。
   
给apk签名可以带来以下好处:
1. 应用程序升级:如果你希望用户无缝升级到新的版本,那么你必须用同一个证书进行签名。这是由于只有以同一个证书签名,系统才会允许安装升级的应用程序。如果你采用了不同的证书,那么系统会要求你的应用程序采用不同的包名称,在这种情况下相当于安装了一个全新的应用程序。如果想升级应用程序,签名证书要相同,包名称要相同!

2.应用程序模块化:Android系统可以允许同一个证书签名的多个应用程序在一个进程里运行,系统实际把他们作为一个单个的应用程序,此时就可以把我们的应用程序以模块的方式进行部署,而用户可以独立的升级其中的一个模块。

3.代码或者数据共享:Android提供了基于签名的权限机制,那么一个应用程序就可以为另一个以相同证书签名的应用程序公开自己的功能。以同一个证书对多个应用程序进行签名,利用基于签名的权限检查,你就可以在应用程序间以安全的方式共享代码和数据了。
不同的应用程序之间,想共享数据,或者共享代码,那么要让他们运行在同一个进程中,而且要让他们用相同的证书签名。

c.签名的构成
一言蔽之:用非对称性加密法中的私钥加密过的,消息摘要+公钥+公钥拥有者信息。

1.消息摘要 -Message Digest
简称摘要,请看英文翻译,是摘要,不是签名,网上几乎所有APK签名分析的文章都混淆了这两个概念。简单的说消息摘要就是在消息数据上,执行一个单向的Hash函数,生成一个固定长度的Hash值,这个Hash值即是消息摘要也称为数字指纹,消息摘要有以下特点:
1. 通过摘要无法推算得出消息本身
2. 如果修改了消息,那么摘要一定会变化(实际上,由于长明文生成短摘要的Hash必然会产生碰撞),所以这句话并不准确,我们可以改为:很难找到一种模式,修改了消息,而它的摘要不会变化(抗冲突性)。

消息摘要的这种特性,很适合来验证数据的 完整性,比如在网络传输过程中下载一个大文件BigFile,我们会同时从网络下载BigFile和BigFile.md5,BigFile.md5保存 BigFile的摘要,我们在本地生成BigFile的消息摘要,和BigFile.md5比较,如果内容相同,则表示下载过程正确。
注意,消息摘要只能保证消息的完整性,并不能保证消息的不可篡改性。

2.数字签名-Signature
数字签名就是信息的发送者用自己的私钥对消息摘要加密产生一个字符串,加密算法确保别人无法伪造生成这段字符串,这段数字串也是对信息的发送者发送信息真实性的一个有效证明。数字签名是非对称密钥加密技术 + 数字摘要技术 的结合。

数字签名技术是将信息摘要用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的信息摘要,然后接收者用相同的Hash 函数对收到的原文产生一个信息摘要,与解密的信息摘要做比对。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改;不同则说明信息被修改过,因 此数字签名能保证信息的完整性。并且由于只有发送者才有加密摘要的私钥,所以我们可以确定信息一定是发送者发送的。

3.数字证书 - Certificate
数字证书是一个经证书授权 中心数字签名的包含公开密钥拥有者信息以及公开密钥的文件。CERT.RSA包含了一个数字签名以及一个数字证书。
需要注意的是Android APK中的CERT.RSA证书是自签名的,并不需要这个证书是第三方权威机构发布或者认证的,用户可以在本地机器自行生成这个自签名证书。

下一期我来解释下:什么是公钥私钥,什么是对称性和非对称性加密法。以及它们的特性和应用。

下一篇:从Android中RSA算法到密码学非对称性加密算法到大数因子多项式分解(二)


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2019-9-30 13:56 被kanxue编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (9)
雪    币: 118
活跃值: (72)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
这个必须mark呀,楼主辛苦。最近在学pc端加密算法
2015-8-23 23:18
0
雪    币: 231
活跃值: (2631)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
3
Mark下,……
2015-8-23 23:57
0
雪    币: 87
活跃值: (88)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
4
上一篇:从Android中RSA算法到密码学非对称性加密算法到大数因子多项式分解(一)

抱歉这周比较忙,更新慢了,书接上回。上回说到Android的签名体系中的非对称性加密算法,进而提出了公钥、私钥概念和RSA数字证书。今天就来说说这些概念和举例。

1.私钥公钥是什么?
一言蔽之:
私有密钥加密法=对称性密钥加密算法=加密解密都用一把私钥对应一套数学算法
公开密钥加密法=非对称性密钥加密算法=加密阶段产生两把数学性相关的、且能互解的、且算法不同的钥匙,一把由创造者保存为私钥,另一把分发给需要的用户为公钥。


以下是入门,高手略过直接看下面举例即可。对于新手虽然字多,看完后相当于你读了几十页的书

2.对称密钥加密法是什么?
私有密钥加密法<也叫对称性密钥加密算法>
指在计算机网络上甲、乙两用户之间进行通信时,发送方甲为了保护要传输的明文信息不被第三方窃取,采用密钥A对信息进行加密而形成密文M并发送给接收方乙,接收方乙用同样的一把密钥A对收到的密文M进行解密,得到明文信息,从而完成密文通信目的的方法。这种信息加密传输方式,就称为私有密钥加密法。上述加密法的一个最大特点是,信息发送方与信息接收方均需采用同样的密钥,具有对称性,所以私有密钥加密又称为对称密钥加密。

具体到电子商务,很多环节要用到私有密钥加密法。例如,在两个商务实体或两个银行之间进行资金的支付结算时,涉及大量的资金流信息的传输与交换。这里以发送方甲银行与接收方乙银行的一次资金信息传输为例,来描述应用私有密钥加密法的过程:银行甲借助专业私有密钥加密算法生成私有密钥A,并且复制一份密钥A借助一个安全可靠通道(如采用数字信封)秘密传递给银行乙;银行甲在本地利用密钥A把信息明文加密成信息密文;银行甲把信息密文借助网络通道传输给银行乙;银行乙接受信息密文;银行乙在本地利用一样的密钥A把信息密文解密成信息明文。这样银行乙就知道银行甲的资金转账通知单的内容,结束通信。

世界上一些专业组织机构研发了许多种私有密钥加密算法,比较著名的有DES算法及其各种变形、国际数据加密算法IDEA等。DES算法由美国国家标准局提出,1977年公布实施,是目前广泛采用的私有密钥加密算法之一,主要应用于银行业中的电子资金转账、军事定点通信等领域,比如电子支票的加密传送。经过20多年的使用,已经发现DES很多不足之处,随着计算机技术进步,对DES的破解方法也日趋有效,所以更安全的高级加密标准AES将会替代DES成为新一代加密标准。

私有密钥加密法的主要优点是运算量小,加解密速度快,由于加解密应用同一把密钥而应用简单。在专用网络中由于通信各方相对固定、所以应用效果较好。但是,私有密钥加密技术也存在着以下一些问题:一是分发不易。由于算法公开,其安全性完全依赖于对私有密钥的保护。因此,密钥使用一段时间后就要更换,而且必须使用与传递加密文件不同的途径来传递密钥,即需要一个传递私有密钥的安全秘密渠道,这样秘密渠道的安全性是相对的,通过电话通知、邮寄软盘、专门派人传送等方式均存在一些问题。二是管理复杂,代价高昂。私有密钥密码体制用于公众通信网时,每对通信对象的密钥不同,必须由不被第三者知道的方式,事先通知对方。随着通信对象的增加,公众通信网上的密码使用者必须保存所有通信对象的大量的密钥。这种大量密钥的分配和保存,是私有密钥密码体制存在的最大问题。三是难以进行用户身份的认定。采用私有密钥加密法实现信息传输,只是解决了数据的机密性问题,并不能认证信息发送者的身份。若密钥被泄露,如被非法获取者猜出,则加密信息就可能被破译,攻击者还可用非法截取到的密钥,以合法身份发送伪造信息。在电子商务中,有可能存在欺骗,别有用心者可能冒用别人的名义发送资金转账指令。因此,必须经常更换密钥,以确保系统安全。四是采用私有密钥加密法的系统比较脆弱,较易遭到不同密码分析的攻击。五是它仅能用于对数据进行加解密处理,提供数据的机密性,不能用于数字签名。

3.非对称密钥加密法是什么?
公开密钥加密法<也叫非对称性密钥加密算法>
公开密钥加密法是针对私有密钥加密法的缺陷而提出来的。是电子商务应用的核心密码技术。所谓公开密钥加密,就是指在计算机网络上甲、乙两用户之间进 行通信时,发送方甲为了保护要传输的明文信息不被第三方窃取,采用密钥A对信息进行加密而形成密文M并发送给接收方乙,接收方乙用另一把密钥B对收到的密 文M进行解密,得到明文信息完密文通信目的的方法。由于密钥A、密钥B这两把密钥中其中一把为用户私有,另一把对网络上的大众用户是公开的,所以这种信息 加密传输方式,就称为公开密钥加密法。与私有(对称)密钥加密法的加密和解密用同一把密钥的原理不同,公开密钥加密法的加密与解密所用密钥是不同的,不对 称,所以公开私有密钥加密法又称为非对称密钥加密法。

公开密钥加密法的应用原理是:借助密钥生成程序生产密钥A与密钥B,这两把密钥在数学上相关,对称作密钥对。用密钥对其中任何一个密钥加密时,可以用 另一个密钥解密,而且只能用此密钥对其中的另一个密钥解密。在实际应用中,某商家可以把生成的密钥A与密钥B做一个约定,将其中一把密钥如密钥A保存好, 只有商家自己知道并使用,不与别人共享,叫作私人密钥;将另一把密钥即密钥B则通过网络公开散发出去,谁都可以获取一把并能应用,属于公开的共享密钥,叫 做公开密钥。如果一个人选择并公布了他的公钥,其他任何人都可以用这一公钥来加密传送给那个人的消息。私钥是秘密保存的,只有私钥的所有者才能利用私钥对 密文进行解密,而且非法用户几乎不可能从公钥推导出私钥。存在下面两种应用情况:一是任何一个收到商家密钥B 的客户,都可以用此密钥B 加密信息,发送给这个商家,那么这些加密信息就只能被这个商家的私人密钥A解密。实现保密性。二是商家利用自己的私人密钥A对要发送的信息进行加密进成密 文信息,发送给商业合作伙伴,那么这个加密信息就只能被公开密钥B解密。这样,由于只能应用公开密钥B解密,根据数学相关关系可以断定密文的形成一定是运 用了私人密钥A进行加密的结果,而私人密钥A只有商家拥有,由此可以断定网上收到的密文一定是拥有私人密钥A的商家发送的。

具体到电子商务,很多环节要用到公开密钥加密法,例如在网络银行客户与银行进行资金的支付结算操作时,就涉及大量的资金流信息的安全传输与交换。以 客户甲与乙网络银行的资金信息传输为例,来描述应用公开密钥加密法在两种情况下的使用过程。首先,网络银行乙通过公开密钥加密法的密钥生成程序,生成自己 的私人密钥A与公开密钥B并数学相关,私人密钥A由网络银行乙自己独自保存,而公开密钥B 已经通过网络某种应用形式(如数字证书)分发给网络银行的众多客户,当然客户甲也拥有一把网络银行乙的公开密钥B。
  1、客户甲传送一“支付通知”给网络银行乙,要求“支付通知”在传送中是密文,并且只能由网络银行乙解密知晓,从而实现了定点保密通信。客户甲利用获得的公开密钥B 在本地对“支付通知”明文进行加密,形成“支付通知”密文,通过网络将密文传输给网络银行乙。网络银行乙收到“支付通知”密文后,发现只能用自己的私人密钥A进行解密形成“支付通知”明文,断定只有自己知晓“支付通知”的内容,的确是发给自己的。
  2、网络银行乙在按照收到的“支付通知”指令完成支付转账服务后, 必须回送客户甲“支付确认”,客户甲在收到“支付确认”后,断定只能是网络银行乙发来的,而不是别人假冒的,将来可作支付凭证,从而实现对网络银行业务行 为的认证,网络银行不能随意否认或抵赖。网络用户乙在按照客户甲的要求完成相关资金转账后,准备一个“支付确认”明文,在本地利用自己的私人密钥A对“支 付确认”明文进行加密,形成“支付确认”密文,通过网络将密文传输给客户甲。客户甲收到“支付确认”密文后,虽然自己有许多密钥,有自己的,也有别人的, 却发现只能用获得的网络银行乙的公开密钥B 进行解密,形成“支付确认”明文,由于公开密钥B 只能解密由私人密钥A加密的密文,而私人密钥A只有网络银行乙所有,因此客户甲断定这个“支付确认”只能是网络银行乙发来的,不是别人假冒的,可作支付完 成的凭证。

当前最著名、应用最广泛的公开密钥系统是RSA(取自三个创始人的名字的第一个字母)算法。目前电子商务中大多数使用公开密钥加密法进行加解密和数字签名的产品和标准使用的都是RSA算法。RSA算法是基于大数的因子分解,而大数的因子分解是数学上的一个难题,其难度随数的位数加多而提高。

优点是可以在不安全的媒体上通信双方交换信息,不需共享通用密钥,用于解密的私钥不需发往任何地方,公钥在传递与发布过程中即使被截获,由于没有与公钥相匹配的私钥,截获公钥也没有意义。能够解决信息的否认与抵赖问题,身份认证较为方便。密钥分配简单,公开密钥可以像电话号码一样,告诉每一个网络成员,商业伙伴需要好好保管的只是一个私人密钥。而且密钥的保存量比起私人密钥加密少得多,管理较为方便。最大的缺陷就在于它的加解密速度。

废话一堆,这下面才是真格的:

4.RSA算法浓缩
[1] 私钥
首先, 找出三个数, p, q, r,
其中 p, q 是两个相异的质数, r 是与 (p-1)(q-1) 互质的数
p, q, r 这三个数便是 private key

[2]公钥
接著, 找出 m, 使得 rm == 1 mod (p-1)(q-1)
这个 m 一定存在, 因为 r 与 (p-1)(q-1) 互质, 用辗转相除法就可以得到了
再来, 计算 n = pq
m, n 这两个数便是 public key

[3]加密
若资料为 a, 将其看成是一个大整数, 假设 a < n
如果 a >= n 的话, 就将 a 表成 s 进位 (s <= n, 通常取 s = 2^t),
则每一位数均小於 n, 然後分段编码
接下来, 计算 b == a^m mod n, (0 <= b < n)

[4]解密
解码的过程是, 计算 c == b^r mod pq (0 <= c < pq)

5.RSA算法用数字举例<再浓缩>
问:用RSA算法加密时,已知公钥是(e=7,n=20),私钥是(d=3,n=20)用公钥对消息M=3加密,得到的密文是多少?
解:
<要加密或解密的数字做e次方或d次方,得到的数字再和n进行模运算,模运算就是求余数>

加密时用公钥d,解密时用私钥e

加密过程:3的7次方等于2187,2187除以20等于109,余数是7 所以得到的密文就是7

解密过程:7的3次方343,343除以20等于340余数3,于是我们又得回原来的明文3

6.RSA算法java实例<再再浓缩>

package com.rsa.test;  
import java.security.*;  
import java.security.spec.*;  
import java.security.interfaces.*;  
import javax.crypto.spec.*;  
import javax.crypto.interfaces.*;  
import java.io.*;  
import java.math.*;  
public class RSATest {  
    public RSATest() {  
    }  
    public static void generateKey() {  
        try {  
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");  
            kpg.initialize(1024);  
            KeyPair kp = kpg.genKeyPair();  
            PublicKey pbkey = kp.getPublic();  
            PrivateKey prkey = kp.getPrivate();  
            // 保存公钥  
            FileOutputStream f1 = new FileOutputStream("pubkey.dat");  
            ObjectOutputStream b1 = new ObjectOutputStream(f1);  
            b1.writeObject(pbkey);  
            // 保存私钥  
            FileOutputStream f2 = new FileOutputStream("privatekey.dat");  
            ObjectOutputStream b2 = new ObjectOutputStream(f2);  
            b2.writeObject(prkey);  
        } catch (Exception e) {  
        }  
    }  
    public static void encrypt() throws Exception {  
        String s = "Hello World!";  
        // 获取公钥及参数e,n  
        FileInputStream f = new FileInputStream("pubkey.dat");  
        ObjectInputStream b = new ObjectInputStream(f);  
        RSAPublicKey pbk = (RSAPublicKey) b.readObject();  
        BigInteger e = pbk.getPublicExponent();  
        BigInteger n = pbk.getModulus();  
        System.out.println("e= " + e);  
        System.out.println("n= " + n);  
        // 获取明文m  
        byte ptext[] = s.getBytes("UTF-8");  
        BigInteger m = new BigInteger(ptext);  
        // 计算密文c  
        BigInteger c = m.modPow(e, n);  
        System.out.println("c= " + c);  
        // 保存密文  
        String cs = c.toString();  
        BufferedWriter out =  
            new BufferedWriter(  
                new OutputStreamWriter(new FileOutputStream("encrypt.dat")));  
        out.write(cs, 0, cs.length());  
        out.close();  
    }  
    public static void decrypt() throws Exception {  
        // 读取密文  
        BufferedReader in =  
            new BufferedReader(  
                new InputStreamReader(new FileInputStream("encrypt.dat")));  
        String ctext = in.readLine();  
        BigInteger c = new BigInteger(ctext);  
        // 读取私钥  
        FileInputStream f = new FileInputStream("privatekey.dat");  
        ObjectInputStream b = new ObjectInputStream(f);  
        RSAPrivateKey prk = (RSAPrivateKey) b.readObject();  
        BigInteger d = prk.getPrivateExponent();  
        // 获取私钥参数及解密  
        BigInteger n = prk.getModulus();  
        System.out.println("d= " + d);  
        System.out.println("n= " + n);  
        BigInteger m = c.modPow(d, n);  
        // 显示解密结果  
        System.out.println("m= " + m);  
        byte[] mt = m.toByteArray();  
        System.out.println("PlainText is ");  
        for (int i = 0; i < mt.length; i++) {  
            System.out.print((char) mt[i]);  
        }  
    }  
    public static void main(String args[]) {  
        try {  
            generateKey();  
            encrypt();  
            decrypt();  
        } catch (Exception e) {  
            System.out.println(e.toString());  
        }  
    }  
}

结果:


7.公开密钥加密法是怎么做到的私钥A与公钥B互解?
一言蔽之:来自于大数因子的多项式分解:就是若我们设计几个超大的素数(每个都有999位)将它们相乘得到一个合数,现在叫你逆向求该合数的是由那几个素数相乘得到的?这几乎是不可能的(更准确的说是现代的计算机需要几万年人算就别想了)

1977年,艾德利曼(Adleman)、希爱默(Shamir)和鲁梅利(Rumely)发明了一个公开密钥码体制。在这个密码体制中,对电文的加密过程是公开的,但是,你仅知道加密过程而未被告知解密过程则不可能对电文进行解密。他们的体制就是依靠这样一个事实:我们能够很容易地将两个大素数(譬如两个百位素数)乘起来;反过来,要分解一不大整数(譬如200位)则几乎不可能。因此RSA体制就与素数判别和大数分解有密切联系。首先,要具体建立一个RSA体制就需要两个大素数,因而就涉及到寻找大素数的问题;而RSA体制的破译之可能性就依赖于分解一个大数可能性。于是,RSA体制的建立与破译就等价于素数判别与大数分解问题。

这里我要指出一点:随着数学的发展,大数因子分解问题可能会在不久的将来得到解决,从而RSA体制将不复存在!
根据美国AT&T研究院Peter W.Shor近期发表的论文来看,他将通过引入量子力学的基本原理,完成一个n位大数的质因子分解,可以达到多项式的时间复杂度。因为,原则上可以在一年左右的时间内分解一个400位的大数。
参考文献:Shor, Peter W. (1997), "Polynomial-Time Algorithms for Prime Factorization and Discrete Logarithms on a Quantum Computer", SIAM J. Comput. 26 (5): 1484 1509

这次主要是知识,所以图少了点,多包涵。下次我们说说RSA算法等非对称性加密算法的基础:大数因子的多项式分解是何方神圣,敬请关注!
2015-8-29 08:17
0
雪    币: 47147
活跃值: (20465)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
5
帖子我从临时会员版移到Android版了,2帖合并一帖了。
感谢你的分享!
2015-8-30 21:45
0
雪    币: 47147
活跃值: (20465)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
6
帖子我从临时会员版移到Android版了,2帖合并一帖了。
感谢你的分享!
2015-8-30 21:46
0
雪    币: 76
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2015-8-31 08:55
0
雪    币: 627
活跃值: (663)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
8
不错,排版也很用心。期待下篇。
2015-8-31 09:37
0
雪    币: 29
活跃值: (97)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
感谢分享
2015-8-31 11:14
0
雪    币: 25
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
RSA算法原理,推荐看一下阮一峰的博客RSA算法原理(一)
2015-9-1 15:37
0
游客
登录 | 注册 方可回帖
返回
//