android 自带的sha算法,sha1-collision & android signature algorithm

SHA1-Collision & Android Sign

参看SHA1-collision我们可以知道,SHA-1签名已经不安全了,签名算法可以考虑升级到SHA-2或者其他算法。

0x01 SHA1-Collision

1. SHA-1是什么?

SHA-1(英语:Secure Hash Algorithm 1,中文名:安全散列算法1)是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦数据处理标准(FIPS)[2]。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数,参考:SHA-1

2. SHA1-Collision是什么?

两个内容不同的数据,SHA-1算法会生成相同的摘要信息,参考:SHA1 collision Two PDF。

3. SHA1-Collision对Android的影响

Android SDK默认对apk使用SHA-1签名,在最坏的情况下,攻击者可以伪造SHA-1值相同的文件替换已签名apk中的文件来达到攻击的目的。

0x02 Android的证书验证机制

我们知道Android的Apk文件是一个压缩文件,文件结构大致如下:

.

├── AndroidManifest.xml

├── META-INF

│ ├── CERT.RSA

│ ├── CERT.SF

│ └── MANIFEST.MF

├── assets

├── classes.dex

├── classes2.dex

├── classes3.dex

├── lib

├── res

└── resources.arsc

apk相关的签名相关的文件在META-INF目录中,其中:

MANIFEST.MF

遍历APK包中除了META-INF\文件夹以外的所有文件,利用SHA-1算法生成这些文件的消息摘要,然后转化为对应的base64编码。MANIFEST.MF存储的是文件的摘要值,保证完整性,防止文件被篡改。

.SF

xx.SF文件(xx为使用者证书的自定义别名,默认为CERT,即CERT.SF),保存的是MANIFEST.MF的摘要值, 以及MANIFEST.MF中每一个摘要项的摘要值,然后转化成对应的base64编码。虽然该文件的后缀名.sf(SignatureFile)看起来是签名文件,但是并没有私钥参与运算,也不保存任何签名内容。

.RSA/.DSA

.RSA/.DSA文件(后缀不同采用的签名算法不同,.RSA使用的是RSA算法,.DSA使用的是数字签名算法DSA,目前APK主要使用的是这两种算法),保存的是第二项.SF文件的数字签名,同时还会包括签名采用的数字证书(公钥)。特别说明,当使用多重证书签名时,每一个.sf文件必须有一个.RSA/.DSA文件与之对应,也就是说使用证书CERT1签名时有CERT1.SF和CERT1.RSA,同时采用证书CERT2签名时又会生成CERT2.SF和CERT2.RSA。

Android 系统不允许安装没有任何数字签名的应用APK程序,所有应用程序必须使用某个证书进行签名(一般为应用开发者自签名证书),

APK源文件,首先由应用开发者使用自己的私钥,对整个文件进行签名,生成上述的三个文件,然后打包成签名后的APK文件;然后发布到市场。

用户从市场下载APK安装文件,在真正安装APK前,会首先验证数字签名。具体步骤:

首先计算除META-INF\ 文件夹以外所有文件的SHA1摘要值,同MANIFEST.MF文件中的摘要值做比对。如果不同,则证明源文件被篡改,验证不通过,拒绝安装。

计算MANIFEST.MF的摘要值, 以及MANIFEST.MF中每一个摘要项的摘要值,同.SF文件中的摘要值做比对。如果不同,则证明.SF被篡改,验证不通过,拒绝安装。

从.RSA 文件中取出开发者证书,然后从证书中提取开发者公钥,用该公钥对.SF文件做数字签名,并将结果同.RSA文件中的.SF签名进行比对。如果不同,则验证不通过,拒绝安装。

0x03 Android支持的签名算法

android 4.3之前不支持SHA1之外的其他签名算法,在4.3之后支持了SHA2等算法,详见:

There is security vs compatibility trade off a few might be interested in. Pre-4.3, Android did not support any signature algorithms except SHA1. With Android >= 4.3, SHA256 support was fixed, and SHA384, SHA512, and ECDSA were added (source). There are still android 2.3.3 (android-10) devices being sold, so anyone interested in backwards compatibility will have to heed this.

在android 4.3版本之前的手机上面安装使用sha-256签名的app时,错误日志信息大致如下:

adb install -r Downloads/notepad-sha256withrsa-sha256.apk

~/Downloads/notepad-sha256withrsa-sha256.apk: 1 file pushed. 4.3 MB/s (62395 bytes in 0.014s)

pkg: /data/local/tmp/notepad-sha256withrsa-sha256.apk

Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES]

0x04 签名生成与查看

生成keystore

keytool -genkey -v -keystore test.keystore -alias testkey -keyalg RSA -keysize 2048 -sigalg SHA256withRSA -dname "cn=Test,ou=Test,c=CA" -validity 10000

查看APK的签名算法

keytool -printcert -jarfile notepad-sha1withrsa-sha1.apk

查看keystore

keytool -list -v -keystore test.keystore

jarsigner签名

jarsigner -keystore mykeystore -storepass password -sigalg SHA256withRSA -digestalg SHA256 my.apk test

0x05 jarsigner与apksigner的区别

jarsigner是jdk自带的工具,apksigner是android sdk自带的工具(build-tools 24.0.3+版本才拥有)。在android build-tools 24.0.3以前默认使用jarsigner对app进行签名,在24.0.3版本以及之后使用apksigner进行签名,其中apksigner签名算法根据android的最低版本的不同而不同,jarsigner则可以直接指定签名算法(见: 上面的jarsigner签名)。

tool

minSdkVersion < 18

minSdkVersion >= 18

apksigner

SHA1withRSA

SHA256withRSA

apksigner

SHA1withDSA

SHA256withDSA

apksigner

SHA256withEC

代码详见com.android.apksig.internal.apk.v1.V1SchemeSigner:

public static DigestAlgorithm getSuggestedSignatureDigestAlgorithm(PublicKey signingKey, int minSdkVersion)

throws InvalidKeyException

{

String keyAlgorithm = signingKey.getAlgorithm();

if ("RSA".equalsIgnoreCase(keyAlgorithm))

{

if (minSdkVersion < 18) {

return DigestAlgorithm.SHA1;

}

return DigestAlgorithm.SHA256;

}

if ("DSA".equalsIgnoreCase(keyAlgorithm))

{

if (minSdkVersion < 21) {

return DigestAlgorithm.SHA1;

}

return DigestAlgorithm.SHA256;

}

if ("EC".equalsIgnoreCase(keyAlgorithm))

{

if (minSdkVersion < 18) {

throw new InvalidKeyException("ECDSA signatures only supported for minSdkVersion 18 and higher");

}

return DigestAlgorithm.SHA256;

}

throw new InvalidKeyException("Unsupported key algorithm: " + keyAlgorithm);

}

0x06 升级签名算法为SHA-2

综上所示,我们可以知道App使用签名算法的地方有两处,分别是:

使用keytools生成keystore时指定的算法。

使用jarsigner/apksigner和keystore对app进行签名时指定的算法。

这里我们不修改签名文件keystore的签名算法,我们只修改签名App时使用的签名算法为SHA-2,鉴于上面的原因我们需要升级android app的minSdkVersion >= 18,下面介绍两种升级SHA-2的方法:

升级buildToolsVersion的版本大于等于24.0.3,gradle打包时会自动调用apksigner使用SHA256withRSA对app进行签名。

使用jarsigner对app进行签名,然后在命令参数中直接指定签名算法即可。

0x07 遗留问题

由于keystore未发生变化,所以使用不同签名算法的app是可以互相覆盖的,故而攻击者也可以使用旧版本的apk(使用SHA-1)覆盖新版本apk(使用SHA-2)继续进行攻击,所以为了避免被攻击者进行攻击的最好更换keystore,但是这样就没法覆盖安装了,详细请参考things-that-cannot-change。

0x08 参考引用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值