Android逆向之密码技术

介绍伪随机数生成器、公钥密码、消息认证码、数字签名、密钥协商等密码技术的概念、应用、常见算法、攻击方法等,也会介绍些Android 中可能使用的密码技术,后续会继续更新其他密码算法和攻击方式等。

消息直接明文传递是不安全的,可能会被窃听导致机密泄露,提高消息传递的安全性主要有两种方式,密码术和隐写术。

  • 隐写术:信息隐藏在多种载体中,如:视频、硬盘和图像,将需要隐藏的信息通过特殊的方式嵌入到载体中,而又不损害载体原来信息的表达,旨在保护需要隐藏的信息不被他人识别。
  • 密码术:为了使信息无法被外人理解,而对信息进行加密让消息内容无法解读的技术。

本文主要介绍密码技术的相关知识,密码学按照发展历程区分,可以分为古典密码学和现代密码学两个阶段。

古典密码学

在计算机出现之前,密码学主要通过字符间的置换代换实现信息加密。置换是把明文中的字母重新排列,字母本身不变,但其位置改变了;代换则是将明文中的字符替代成其他字符。

算法 原理 解密
凯撒密码 字母按顺序往后推 x 位得到密文 暴力破解,平移25次得到 x
简单替换密码 建立字母表,将字母一一按照字母表替换得到密文 频率分析,统计一般英文中使用的字母或字母频率,对比密文中顺序,依次尝试替换
仿射密码 将字母对应数值按照函数转为另一个数值,函数:(k1m+k2)mod26(k_1m+k_2)mod26 暴力破解;频率分析

还有Vigenre多表代换密码Scytale密码轨道栅栏密码等算法,古典密码学中有些算法的密钥空间有限比如凯撒密码,对于这种算法可以直接采用暴力破解,穷举得到密钥;由于古典密码是基于字符,并且有些算法加密前后的字母是一一对应关系,对于这种算法可以采用频率分析法加快破译速度。

现代密码技术

现代密码技术与古典密码的区别主要是由字符层加密转移到了字节层加密,安全性的保证也从保密算法转移到了保密密钥,主要包括以下技术:

技术 功能
伪随机数生成器 生成密钥
对称密码 消息的机密性
公钥密码 消息的机密性、身份认证
单向散列函数 消息的完整性(防篡改)
消息认证码 消息的完整性(防篡改)、身份认证
数字签名 消息的完整性(防篡改)、身份认证、防止否认
证书 公钥验证

对称密码

对称密码

加密密钥与解密密钥相同的密码技术,用于保证消息的机密性

优点:通常所需密钥较小、效率高、速度快。

缺点:无法安全的将密钥送达到需要解密消息的人的手里。

常见算法 简介
DES 1977年美国颁布的非机密数据的正式数据加密标准,应用广泛,已经能被暴力破解,如今已逐步被AES替代
AES 高级加密标准,下一代的加密算法标准,采用了Rijndael算法,用于替代DES
3DES 通过增加DES的密钥长度来避免被暴力破解,将DES重复三次得到的一种密码算法,但速度不高
Blowfish 由Bruce Schneider于1993年设计,速度快,并且目前为止还没有有效地破解方法

公钥密码

公钥密码

又称为非对称密码,发送方使用公钥加密数据,接收方使用私钥解密数据,已知私钥可推导出公钥,但已知公钥不能推导出私钥。既可以用于保证消息的机密性,也可以用于认证

过程:消息接收方提前生成一对公私钥,并将公钥广播出去,私钥自己保存,消息发送方获取被广播的公钥,使用公钥加密要传输的内容,加密后通过网络传输给接收方,接收方使用私钥解密。

优点:由于解密数据的私钥不需要在网络传输,降低了密钥泄露的风险,提高了安全性。

缺点:加密解密耗费时间长、计算速度慢、通过密钥也更长、一般只适合少量数据加密。

常见算法 安全性依赖 简介
RSA 大整数因子分解的困难性 最为普及的公钥加密算法,密钥和加密的文件块可变,既能用于数据加密也能用于数字签名
ECC 椭圆曲线离散对数问题的困难性 RSA相比具有所需密钥长度短、加密速度快、破解难度高、抗攻击性更强的优点,可用ECDH密钥交换、ECDSA数字签名
Elgamal mod N下求离散对数的困难性 既能用于数据加密也能用于数字签名,但加密生成的密文长度是明文的两倍
Rabin mod N下求平方根的困难性 破译等价于对大整数的分解,对同一密文可能对应四个不同明文,解密时需要识别真正的明文

单向散列函数

单向散列函数

又称单向Hash函数、杂凑函数,输出的散列值称为消息摘要或者指纹。单向散列函数可以根据消息的内容计算出散列值,通过比对散列值就可以检查消息的完整性,散列值的长度固定与消息的内容无关,还具有弱抗碰撞性、强抗碰撞性、单向性的特点。

弱抗碰撞性:当给定某条消息的散列值时,单向散列函数必须确保要找到和该条消息具有相同散列值的另外一条消息是非常困难的。

强抗碰撞性:找到散列值相同的两条不同的消息是非常困难的。

单向性:无法通过散列值反算出消息。

应用:检查下载的软件是否被篡改(下载软件后计算散列值,跟官网网站公布的软件散列值对比)、基于口令的加密PBE、消息认证码、数字签名、伪随机数生成器、一次性口令。

攻击方法:暴力破解、生日攻击

常见算法 简介
MD4 Rivest 在1990年设计,摘要长度128位,在 Dobbertin 等人提出寻找MD4散列碰撞方法后被淘汰
MD5 Rivest 在1991年设计,摘要长度128位,强抗碰撞性已被攻破
SHA-1 美国国家安全局设计,由美国国家标准技术研究所发布为联邦数据处理标准,摘要长度160位,强抗碰撞性已被攻破
SHA-2 美国国家标准与技术研究院(NIST)在2001年发布,是SHA-1的后继者,算法标准包括SHA-224SHA-256SHA-384SHA-512SHA-512/224SHA-512/256六种
SHA-3 2012年 NIST 选定 Keccak 算法成为SHA-3,并将其推荐为SHA-2的备选(不是继承者)
RIPEMD 1996年由鲁汶大学 COSIC 研究小组发布,RIPEMD的强抗碰撞性已被攻破,但是RIPEMD的改进版RIPEMD-160尚未被攻破,比特币中使用的单向散列函数就是RIPEMD-160

伪随机数生成器

一种能够模拟产生随机数列的算法,用于密钥生成,如果生成随机数算法不好,则密钥可能会被推测出带来风险。生成一个真正意义上的“随机数”对于计算机来说是不可能的,伪随机数也只是尽可能地接近其应具有的随机性。

伪随机数生成器结构

内部状态:需要生成伪随机数时,伪随机数生成器根据内存中的数值(内部状态)进行计算得到伪随机数,生成后改变内部状态,为下一次伪随机数生成做准备,因此内部状态决定了下一个伪随机数的数值。

种子:一串随机比特数列,用于对伪随机数生成器内部状态进行初始化,因此根据种子就可以生成自己专属的随机数列。伪随机数生成器通常都是公开,种子需要自己保密,保密的种子让生成的伪随机数更难以预测。

常见算法 简介
平方取中法 1946年由冯·诺伊曼提出产生[0,1]均匀分布随机数的方法,易于实现,但是对小数目偏倚,均匀性不好,随机数列的长度和周期难以确定,对初始值依赖性很大
乘积取中法 对平方取中法的改进,产生的伪随机数列长度和均匀性都有改善,但是数列长度不够,对初始值依赖性依然很大
移位法 由于计算机特有的逻辑移位运算,可以对种子N0左移n位得到M1,右移n位得到M2,将M1与M2做逻辑相加运算得到随机数,产生速度很快,但对初始值依赖性很大
线性同余法 通过对前一个数进行线性运算并取模从而得到下一个数,是最早最知名的伪随机数生成算法之一,曾被广泛应用,包括加同余法、乘同余法、混合同余法,但产生的伪随机数分布于有限条等距平行线上
马特赛特旋转演算法 是1997年提出的伪随机数生成算法,其修复了以往随机数生成算法的诸多缺陷,目前在各种编程语言和库中已普遍存在或作为默认的伪随机数发生器,比如python的random()函数

消息认证码

消息认证码

又叫消息鉴别码、文件消息认证码、讯息鉴别码、信息认证码,简称MAC。可以用来检查在消息传递过程中,其内容是否被更改过,还可以作为消息来源的身份验证,确认消息的来源,简单来说就是可以用来防篡改认证

与单向散列函数类似,发送方根据任意长度的消息生成MAC值,生成后将消息与MAC值一起发送给接收方,接收方接收后计算MAC与发送方发送的MAC比对,确定消息的完整性,但是不同之处在于消息认证码的发送方与接收方使用了共享密钥进行消息加密,而单向散列函数不需要密钥。由于MAC值是根据共享的密钥生成的,发送方与接收方的密钥不同则MAC值不会相同,所以比对MAC值也可以对发送方的身份进行认证

攻击方法:暴力破解、生日攻击、共享密钥推测、重放攻击

无法解决的问题:对第三方证明、防止否认

否认:由于发送方和接收方共享了密钥,都可以生成消息正确的MAC值,对于第三方来说,无法确认消息究竟是由发送方还是接收方生成,因此发送方在可能会在发送生成的消息之后进行否认,第三方无法鉴别。

实现 介绍
HMAC 一种使用单向散列函数来构造消息认证码的方法,任何高强度的单向散列函数都可以被用于HMAC,比如SHA-256构造的HMAC就叫做HMAC-SHA-256,目前在 IPSec 和其他网络协议(如 SSL )中得以广泛应用
分组密码 将分组密码的密钥作为消息认证码的共享密钥,使用CBC模式将消息全部加密,CBC模式最后一个分组会受到整个消息和密钥双重影响,因此作为MAC值使用。AES-CMAC就是一种这样的实现

数字签名

是一种相当于现实世界中的盖章、签字的功能在计算机世界中进行实现的技术,与消息认证码很相似,最大的不同在于数字签名的发送方与接收方各自使用不同的密钥,除了和消息认证码一样可以防篡改认证外还可以防止否认

数字签名

签名者先将明文通过单向散列函数加密得到摘要,摘要通过私钥加密得到签名,将签名与明文传送,验证者接收后,使用公钥解密得到签名者的摘要,再通过单向散列函数计算得到摘要,两个摘要作对比。私钥为签名者所拥有,但公钥是对外公开的,因为任何人都可以成为验证者对签名进行验证。

防止否认:因为签名者和验证者使用了不同密钥,消息的签名一定使用了签名者的私钥才可以生成,接收方不可以生成正确消息的签名,因为签名者无法对消息进行否认。

应用:网站安全信息公告、下载的软件防篡改、公钥证书、SSL/TLS等。

攻击方法:中间人攻击、对使用的单向散列函数强抗碰撞性攻击、潜在伪造、对使用的签名算法针对性攻击。

无法解决的问题:公钥验证。因为验证者需要使用公钥对签名进行验证,但是数字签名本身无法确保公钥来自真正的发送者,因此可以使用证书,证书要由可信任的机构颁发,验证者通过证书链验证证书的合法、有效性来完成对公钥的验证。

常见算法 介绍
RSA RSA既可用于非对称加密也可用作数字签名,需要配合单向散列函数使用,比如SHA256withRSA就是SHA256RSA配合的数字签名实现
DSA 不能用作加密,只用作数字签名,由NIST在1991年制定的数字签名规范(DSS),安全性基于解离散对数的困难性
ECDSA 使用ECC公钥算法对数字签名算法DSA的模拟实现的数字签名算法,比特币里就使用了这种算法
RSA-PSS RSAPSS结合的数字签名算法,PSS是私钥签名流程的一种填充模式,RSA-PSS并不对消息本身进行签名,而是对其散列值进行签名

证书

pkc

公钥证书(Public-Key Certificate,PKC)的简称,记录着个人信息(姓名、组织、邮箱地址等个人信息)和个人公钥,并由认证机构(Certification Authority、Certifying Authority,CA)施加数字签名。

数字签名需要用公钥来确认发送者的身份,但是无法确认公钥是确实来自真正的发送者的未被篡改的公钥,而公钥证书可以帮助验证公钥

举例A向B发送密文场景说明下证书大致使用方式:首先B创建密钥对,将自己的个人信息以及公钥发送到认证机构C,认证机C构验证信息后对B的公钥加上数字签名形成证书(数字签名生成需要认证机构C自身的私钥),A从认证机构C处获取证书并验证证书合法性,验证通过后解析得到了B的公钥,A将要发送的消息通过B的公钥加密后发送给B,B接收后通过自己的私钥解密,完成通信。

X.509:证书是由不同认证机构颁发的,为了方便验证需要证书有特定的格式,于是人们制定了证书的标准规范,而X.509就是一套使用最广泛的证书标准,HTTPS协议依赖的SSL证书使用的就是这种格式,它是由国际电信联盟(ITU)和国际标准化组织(ISO)制定,发布后经过两次修订,目前版本是X.509 V3

公钥基础设施:简称PKI,是为了能够更有效地运用公钥而制定的一系列规范和规格的总称,而并非指某一个单独特定的规范或规格,主要功能是绑定证书持有者的身份和相关的密钥对,为用户提供证书申请、证书作废、证书获取、证书状态查询的途径,并利用数字证书及相关的各种服务(证书发布,黑名单发布,时间戳服务等)实现通信中各实体的身份认证、完整性、抗抵赖性和保密性。

CRL:证书作废清单,当用户的私钥丢失、被盗时,认证机构需要对证书进行作废CRL是认证机构宣布作废的证书一览表,用户需要从认证机构获取最新的CRL并查询自己要用于验证签名的公钥证书是否已作废,一般来说,需要要由证书处理软件及时更新CRL

证书链:除自签名证书外,大多数申请的证书是层级结构的,从下到上依次为"用户证书–中间证书–根证书",证书验证时也会沿着这个证书链依次验证。

攻击方法:证书生成前直接对公钥进行攻击、注册相似信息进行攻击、窃取认证机构的私钥、伪装成认证机构、利用CRL发布更新的时间差攻击。

分组密码模式

密码算法可以分组密码流密码两类。流密码是对数据流进行连续处理,处理过程需要保持内部状态的 一类算法;分组密码是每次只能处理特定长度数据的一类算法,比如DES3DESAES

因为分组密码只能处理固定长度的数据,当需要加密的数据超过分组长度时,就需要对算法进行迭代来将数据全部加密,迭代的方法就称为分组密码的模式,常见模式:

五种分组密码模式

模式 优点 缺点
ECB 简单;快速;支持并行加解密计算 明文中的重复排列会反映在密文中;通过删除、替换密文分组可以对明文进行操作;对包含某些比特错误的密文进行解密时,对应的分组会出错;不能抵御重放攻击
CBC 明文的重复排列不会反映在密文中;支持并行解密计算;能够解密任意密文分组 对包含某些错误比特的密文进行解密时,第一个分组的全部比特以及后一个分组的相应比特会出错;加密不支持并行计算
CFB 不需要填充;支持并行解密计算;能够解密任意密文分组 加密不支持并行计算;对包含某些错误比特的密文进行解密时,第一个分组的全部比特以及后一个分组的相应比特会出错;不能抵御重放攻击
OFB 不需要填充;可事先进行加解密的准备;加解密使用相同结构;对包含某些错误比特的密文进行解密时,只有明文中相应的比特会出错 不支持并行运算;主动攻击这反转密文分组中的某些比特时,明文分组中相对应的比特也会被反转
CTR 不需要填充;可事先进行加密、解密的准备;加密、解密使用相同的结构;对包含某些错误比特的密文进行解密时,只有明文中相对应的比特会出错;支持并行加解密计算 主动攻击者反转密文分组中的某些比特时,明文分组中对应的比特也会被反转

混合密码系统

对称加密的加密速度快但无法无法抵御中间人攻击,非对称加密可以解决密钥配送问题但加密效率低,可以将对称加密和非对称加密结合起来组成混合密码系统,同时拥有两种加密方式的优势,比如SSL就是这样的混合密码系统。

混合密码系统

加密流程

  1. 接收方事先生成非对称加密的公私钥对,发送方从接收方那里获取公钥。

  2. 发送方使用伪随机数生成器生成会话密钥。

  3. 使用该会话密钥通过对称加密加密消息,生成密文。

  4. 使用之前约定的非对称加密公钥加密会话密钥。

  5. 将加密过后的会话密钥和密文合并,组成密文。

解密流程

  1. 接收方接收组合密文,得到会话密钥和消息密文。
  2. 使用之前生成好的非对称加密私钥解密会话密钥,得到对称加密的密钥。
  3. 使用对称加密的密钥解密密文,得到消息内容。

密钥协商

即使在有攻击者在偷窥客户端与服务器的网络传输的情况下,客户端依然可以利用“密钥协商机制”与服务器端协商出一个只有二者可知的,用来数据加密的会话密钥。

实现方式 简介
DH Diffie-Hellman密钥协商协议,安全性基于“离散对数问题”的复杂度,不支持认证无法抵御中间人攻击,可以配合签名算法如RSADSA实现身份认证
RSA 先生成RSA密钥对,拿到公钥的一方先生成随机的会话密钥,并用公钥加密,把加密结果发给对方,对方用私钥解密,双方都得到了会话密钥
ECDH ECCDH结合,安全性变为“椭圆曲线的离散对数问题”的复杂度,也法抵御中间人攻击

密码算法

国密系列

国密算法是国家密码局制定标准的一系列算法,对称加密算法有SM1SM4SM5SM6SM7SM8ZUC,公钥算法有SM2SM9,摘要算法有SM3,其中SM2SM3SM4SM9ZUC公开了算法细节,剩余未被公开。

算法 类型 简介
SM2 公钥算法 基于ECC实现,在我国商用密码体系中被用来替换RSA算法,相对于RSA抗攻击性更强、性能更好、同等强度下密钥更小
SM3 散列算法 适用于商用密码应用中的数字签名、消息认证码的生成与验证、随机数的生成,在SHA-256基础上改进实现的一种算法,采用Merkle-Damgard结构
SM4 对称加密算法 无线局域网标准的分组数据算法,密钥长度和分组长度均为128位,加密算法与密钥扩展算法都采用32轮非线性迭代结构,S盒为固定的8比特输入8比特输出

DES

1977年美国联邦信息处理标准中使用的一种对称加密算法,一直以来被很多国家的政府和银行等广泛使用。随着计算机算力的提高,如今DES已经能被暴力破解,强度大不如前,如今AES已经正式替代了DES

密钥:8字节64位,每隔7位有一位用于错误检查,所以有效密钥为56位。

结构:16轮循环的Feistel网络。

攻击方法:暴力破解、差分分析攻击(改变一部分明文分析密文产生的改变)、线性攻击(将明文和密文一些对应位进行XOR计算结果位零的概率)。

DES

3DES

因为DES已经能够被破解,为了增加强度,将DES重复三次得到的一种对称加密算法。但是由于处理速度不高,实际使用并不多。

3DES

AES

一种对称加密算法,1997年NIST公开募集AES用于替代原先的DES,经过五年的甄选,最终比利时密码学家Joan Daemen和Vincent Rijmen设计的Rijdael算法力压群雄,被选定为AES标准,目前还没有针对AES的低复杂度有效的攻击算法。

密钥:128、192、256位三种。

分组:固定为128位。

结构:多轮SPN结构,每轮分为字节代换(SubByte)、行移位(ShiftRow)、列混合(MixColumn)、轮密钥加(AddRoundKey)步骤。

攻击方法:边信道攻击(利用测量物理数据的方式推测出可能的密钥)。

AES

RSA

RSA是在1977年由麻省理工学院的Ron Rivest、Adi Shamir、Leonard Adleman三人一起提出的公钥算法,利用了大整数因子分解的困难性,算法密钥越长越难破解,目前被破解的最长RSA密钥是768位,一般认为,1024位的密钥基本安全,2048位的密钥极其安全 。

公私钥生成流程

  1. N = 两个质数乘积 = p x q。例如p=17,q=19,实际要选取的质数比较大,N=17 x 19 = 323。

  2. L = p-1 和 q-1的最小公倍数 = lcm(p-1, q-1) = lcm(17-1, 19-1) = 144。

  3. 选取一个与L互质的数作为E,即E和L最大公约数是1,比如选取数5作为E,5和144互质,E和N组成公钥。

  4. 选取数字D,D需要满足E x D mod L = 1,即5 x D mod 144 = 1,D可以为29,D和N组成私钥。

加密公式=EmodN密文=明文^E\mod\N

解密公式=DmodN明文=密文^D\mod\N

攻击方法:暴力破解、中间人攻击、选择密文攻击。

ECC

椭圆加密算法是一种公钥算法,最初由Koblitz和Miller两人于1985年提出,基于椭圆曲线上离散对数计算问题,利用椭圆曲线上的有理点构成Abel加法群上椭圆离散对数的计算困难性

RSA相比具有所需密钥长度短、加密速度快、破解难度高、抗攻击性更强的优点。ECDH是基于ECCDH的密钥协商协议,ECDSA是基于ECCDSA的数字签名算法。

攻击方法:Pohlig-Hellman 攻击、Pollard Rho 攻击、中间人攻击。

Android中的密码技术

锁屏

目前安卓锁屏解锁方式主要有数字密码、手势密码、人脸识别、虹膜识别、指纹等方式,其中数字密码、手势密码比较简单,也不需要借助硬件层实现,这里先只介绍这两种解锁方式用到的密码技术(基于Android 5.1版本,目前正在阅读Android 11.0源码,如果实现方式不同,后续再更新):

数字密码:首先取设备信息做盐值,数字密码加盐值组成加盐密码,加密值= MD5(加盐密码).toHex() + SHA

-1(加盐密码).toHex() ,然后把加密值保存在数据库中(数据库文件为"/data/system/locksettings.db"),使用了MD5SHA-1两种散列算法。

手势密码:将手势密码转为对应的字节数组,使用SHA-1散列算法加密后存储。

签名

APK 需要签名之后才可以被安装,签名是为了安全性,防止恶意破解者反编译修改之后重新安装。应用可以由第三方(OEM、运营商、其他应用市场)签名,也可以自行签名,Android 提供了使用自签名证书进行代码签名的功能。SDK里的apksigner是Google官方提供的APK专用签名及验证工具,目前支持v1v2v3v4四种签名方案:

签名方案 引入版本 简介
v1 一开始就有 基于 JAR 签名,不保护 APK 的某些部分,例如 ZIP 元数据,存在安全隐患,APK 验证时必须解压所有已压缩的条目,性能也较低
v2 Android 7.0 一种全文件签名方案,对整个 APK 进行签名,能够发现对 APK 的受保护部分进行的所有更改,安全性更高同时验证速度也更快,APK 签名会存储在“APK 签名分块”内
v3 Android 9 添加了密钥轮替,使应用能够在 APK 更新过程中更改其签名密钥
v4 Android 11 支持与流式传输兼容的签名方案,基于根据 APK 的所有字节计算得出的 Merkle 哈希树

HTTPS

应用与服务器的请求如果直接使用 HTTP 是极不安全的,可能会被人直接看得到请求明文内容,也可能会被人冒充和篡改,因此应该使用 HTTPS 协议。

为防止 HTTPS 请求被抓包,可以采取设置无代理模式、增强本地证书校验、SSL Pinning 证书锁定、TLS 双向认证等方式进一步提高安全性,具体可以参考Android逆向之https 一文。

参考与引用


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!