证书Certificate以及android打包签名

证书:

CA(证书信任机构) 也拥有一个证书(内含公钥和私钥)。网上的公众用户通过验证 CA 的签字从而信任 CA ,任何人都可以得到 CA 的证书(含公钥),用以验证它所签发的证书。
如果用户想得到一份属于自己的证书,他应先向 CA 提出申请。在 CA 判明申请者的身份后,便为他分配一个公钥,并且 CA 将该公钥与申请者的身份信息绑在一起,并为之签字后,便形成证书发给申请者。
如果一个用户想鉴别另一个证书的真伪,他就用 CA 的公钥对那个证书上的签字进行验证,一旦验证通过,该证书就被认为是有效的。证书实际是由证书签证机关(CA)签发的对用户的公钥的认证。

内容包括:电子签证机关的信息、公钥用户信息、公钥、权威机构的签字和有效期等等。
格式和验证方法:普遍遵循X.509 国际标准。
技术:涉及到公钥和私钥,使用非对称加密,例如RSA、椭圆加密算法等。

数字签名:

数字签名(又称公钥数字签名、电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。
数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。
数字签名是非对称密钥加密技术与数字摘要技术的应用。
数字签名包括两部分:

  • 签名:使用私钥加密。
  • 验证:使用公钥解密。

签名和验证是一对互补的操作。
其功能是:保证信息传输的完整性、身份认证、防止交易中抵赖发生。

报文摘要:

MessageDigest(报文摘要,简称MD),单向哈希算法(例如MD5、SHA算法等),不可逆,找出具有同一报文摘要的两个不同报文是很困难的。如果报文一旦被修改,那么计算出的摘要就不同,通过这种方法可以检测到报文是否被修改。可以通过报文计算出摘要,但是难以从摘要中推算出原报文。并且任一长度的报文计算出的摘要是固定长度的。

假如现在 Alice 向 Bob 传送数字信息,为了保证信息传送的保密性、真实性、完整性和不可否认性,需要对传送的信息进行数字加密和签名,其传送过程为:
1.Alice 准备好要传送的数字信息(content);
2.Alice 对content进行哈希运算,得到一个信息摘要;
3.Alice 用自己的RSA私钥对信息摘要进行加密得到 Alice 的数字签名,并将其附在数字信息上;
4.Alice 随机产生一个DES加密密钥,并用此密钥对content进行加密,形成密文;
5.Alice 用 Bob 的公钥对刚才随机产生的DES加密密钥进行加密,将加密后的 DES 密钥连同密文一起传送给Bob;
6.Bob 收到 Alice 传送来的密文和加密过的 DES 密钥,先用自己的私钥对加密的 DES 密钥进行解密,得到 Alice随机产生的加密密钥;
7.Bob 然后用随机密钥对收到的密文进行解密,得到明文的数字信息,然后将随机密钥抛弃;
8.Bob 用 Alice 的公钥对 Alice 的数字签名进行解密,得到信息摘要;
9.Bob 用相同的哈希算法对收到的明文再进行一次哈希运算,得到一个新的信息摘要;
10.Bob 将收到的信息摘要和新产生的信息摘要进行比较,如果一致,说明收到的信息没有被修改过。

这里写图片描述

通过上述该流程图,主要是自己持有自己的私钥,沟通消息的对方持有与自己私钥对应的公钥,例如在该例子中,alice和bob都持有自己的私钥,并且也互相持有对方的公钥。所以,综上所述,数字签名其实就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。
不知道大家有没有注意,前面讲的这种数字签名方法,有一个前提,就是消息的接收者必须要事先得到正确的公钥。如果一开始公钥就被别人篡改了,那坏人就会被你当成好人,而真正的消息发送者给你发的消息会被你视作无效的。而且,很多时候根本就不具备事先沟通公钥的信息通道。那么如何保证公钥的安全可信呢?这就要靠数字证书来解决了。
可以看出,数字证书其实也用到了数字签名技术。只不过要签名的内容是消息发送方的公钥,以及一些其它信息。但与普通数字签名不同的是,数字证书中签名者不是随随便便一个普通的机构,而是要有一定公信力的机构。这就好像你的大学毕业证书上签名的一般都是德高望重的校长一样。一般来说,这些有公信力机构的根证书已经在设备出厂前预先安装到了你的设备上了。所以,数字证书可以保证数字证书里的公钥确实是这个证书的所有者的,或者证书可以用来确认对方的身份。数字证书主要是用来解决公钥的安全发放问题。

Android打包签名

在android中打包的时候其实是需要签名的,结合我们刚刚上面说的东西来分析android的打包。一个apk安装在手机上都是需要附带签名的。如果是release包的话,一般开发者会指定使用自己创建的证书,如果没有指定,则会默认使用系统的证书,该默认的证书存储在C:\Users\admin.android\debug.keystore,不同的电脑可能安装不同路径。一个签名证书文件中,是包含一对公私钥,用私钥对apk进行签名,在安装到android手机时,系统会使用证书中对应签名私钥的公钥来验证,查看apk是否被更改过,如果没有则可以安装在手机上。任何的app store都不允许使用默认的debug.keystore打包的apk发布上去,因为debug.keystore的密码是默认的,不安全。
Android Studio给我们提供了方便创建证书的功能:
这里写图片描述
这里写图片描述
当你选择打带有指定签名的apk时,需要指定证书(如第一张图)。如果选择创建新的证书(如图二),在第一个红框中主要是设置证书的相关属性,在创建一个证书的时候,默认要创建一对公私钥,在第二个红框中就是设置该公私钥的相关信息。一个证书中可以有多对公私钥,每一对公私钥都要有相关的用户信息,打包签名的时候,可以证明该apk是由你开发的。可以看到创建证书需要设置密码,创建一对key的时候也需要设置密码,看如下代码就知道是干嘛用的了。

public static void init() {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
            File file = new File(getApplicationContext().getFilesDir(), "release.jks");
            if(!file.exists()) {
                store.load(null, null);
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    AppLog.e(TAG, e.getMessage());
                }
            } else {
                in = new FileInputStream(file);
                store.load(in, "storePsw".toCharArray());
            }

            KeyStore.PasswordProtection keyPassword = new KeyStore.PasswordProtection("keypsw".toCharArray());
            if(store.containsAlias("mykey")) {
                KeyStore.SecretKeyEntry entry = (KeyStore.SecretKeyEntry) store.getEntry("mykey", keyPassword);
                secretKey = entry.getSecretKey();
            }

            if(secretKey == null) {
                SecureRandom random = new SecureRandom();
                KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
                keyGenerator.init(128, random);
                secretKey = keyGenerator.generateKey();
                KeyStore.SecretKeyEntry keyStoreEntry = new KeyStore.SecretKeyEntry(secretKey);
                store.setEntry("mykey", keyStoreEntry, keyPassword);

                out = new FileOutputStream(file);
                store.store(out, "storepsw".toCharArray());
            }
        } catch (Exception e) {
            AppLog.e(TAG, e.getMessage());
        } finally {
            in.close();
            out.close();
        }
    }

storepsw代表的是访问keystore的密码口令,也就是第一个红框中设置的密码。keypsw代表的是访问某个key的密码口令,也就是第二个红框中设置的密码。从该段代码中可以看到访问keystore需要密码,打开keystore后访问key也是需要密码的,当然前提是该key是需要密码的,你完全可以设置该key不需要密码就可以访问。但是对于打包的证书来说是需要密码的,不能让人轻易访问到私钥。
通过android studio创建证书的功能来创建一个证书,通过命令行来查看
这里写图片描述
还可以选择已有的证书并添加新的公私钥对:
这里写图片描述

下面继续来看看Android中签名的两个工具:jarsign和signapk

关于这两个工具开始的时候很容易混淆,感觉他们两到底有什么区别吗?

其实这两个工具很好理解,jarsign是Java本生自带的一个工具,他可以对jar进行签名的。而signapk是后面专门为了Android应用程序apk进行签名的工具,他们两的签名算法没什么区别,主要是签名时使用的文件不一样,这个就要引出下面的问题了。
keystore文件和pk8,x509.pem文件的区别?
我们上面了解到了jarsign和signapk两个工具都可以进行Android中的签名,那么他们的区别在于签名时使用的文件不一样
jarsign工具签名时使用的是keystore文件
signapk工具签名时使用的是pk8,x509.pem文件
两种的签名方式有什么区别?
jarsigner签名时用的是keystore文件,signapk签名时用的是pk8和x509.pem文件,而且都是给apk进行签名的,那么keystore文件和pk8,x509.pem他们之间是不是有什么联系呢?答案是肯定的,网上搜了一下,果然他们之间是可以转化的,这里就不在分析如何进行转化的,网上的例子貌似很多,有专门的的工具可以进行转化 。

其中我们在使用Eclipse工具写程序的时候,出Debug包的时候,默认用的是jarsign工具进行签名的,而且Eclipse中有一个默认签名文件:C:\Users\admin.android\debug.keystore
这里写图片描述
我们看到上面有MD5和SHA1的摘要,这个就是keystore文件中私钥的数据摘要,这个信息也是我们在申请很多开发平台账号的时候需要填入的信息,比如申请百度地图,微信SDK等,会需要填写应用的MD5或者是SHA1信息。

如果使用signapk工具来打包文件的话,在生成的apk文件中解压会看到如下三个文件:
这里写图片描述
MANIFEST.MF:
这里写图片描述
CERT.SF:
这里写图片描述
CERT.RSA:
这里写图片描述
这三个文件的具体解析请看该网址:http://www.2cto.com/kf/201512/455388.html
其实MANIFEST.MF中存储的是:逐一遍历里面的所有条目,如果是目录就跳过,如果是一个文件,就用SHA1(或者SHA256)消息摘要算法提取出该文件的摘要然后进行BASE64编码后,作为“SHA1-Digest”属性的值写入到MANIFEST.MF文件中的一个块中。该块有一个“Name”属性,其值就是该文件在apk包中的路径。
CERT.SF文件做了什么:计算这个MANIFEST.MF文件的整体SHA1值,再经过BASE64编码后,记录在CERT.SF主属性块(在文件头上)的“SHA1-Digest-Manifest”属性值值下;逐条计算MANIFEST.MF文件中每一个块的SHA1,并经过BASE64编码后,记录在CERT.SF中的同名块中,属性的名字是”SHA1-Digest”。
CERT.RSA会把之前生成的 CERT.SF文件, 用私钥计算出签名, 然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中保存。CERT.RSA是一个满足PKCS7格式的文件。

为何要这么来签名

首先,如果你改变了apk包中的任何文件,那么在apk安装校验时,改变后的文件摘要信息与MANIFEST.MF的检验信息不同,于是验证失败,程序就不能成功安装。
其次,如果你对更改的过的文件相应的算出新的摘要值,然后更改MANIFEST.MF文件里面对应的属性值,那么必定与CERT.SF文件中算出的摘要值不一样,照样验证失败。
最后,如果你还不死心,继续计算MANIFEST.MF的摘要值,相应的更改CERT.SF里面的值,那么数字签名值必定与CERT.RSA文件中记录的不一样,还是失败。
那么能不能继续伪造数字签名呢?不可能,因为没有数字证书对应的私钥。
而且在打包的时候,会将带有公钥的证书附带在apk上,来让系统验证该apk是否被修改过。
所以,如果要重新打包后的应用程序能再Android设备上安装,必须对其进行重签名。

从上面的分析可以得出,只要修改了Apk中的任何内容,就必须重新签名,不然会提示安装失败,当然这里不会分析,后面一篇文章会注重分析为何会提示安装失败。
而且一个app应该只使用一个证书来签名,否则更新app至新版本会失败。如果一定要使用新的签名,那么要给app换一个包名,然后打包发布,作为一个全新的app发布。而且如果多个app使用同一个签名的话,这些app可以安全地共享数据。所以在一个手机上,不可以安装两个使用不同签名打包同一个app(包名一样)的apk。比如当你的app使用debug的签名,并已安装在手机上,那么如果此时该app用release的签名的话,是不可以安装在该手机上,除非卸载掉刚刚的app。
另外如果你的app要发布到google play的话,签名的有效期要到22 October 2033以后。

签名的私钥是很重要的,如果被他人获取,那么别人可以发布钓鱼app来替换现有的app,或者发布钓鱼app来获取你应用内的用户数据。

参考资料:
Android签名机制之—签名过程详解
android studio签名文件在哪?以及查看签名信息
Sign Your App
apk签名原理及实现
APK Crack

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
如果你希望使用应用程序自己的签名来签署 APK,可以使用 `key` 作为 `LOCAL_CERTIFICATE` 的值。这将会使用你应用程序的签名证书来签署 APK。你需要将签名证书添加到你的 Android 项目中,并在 `AndroidManifest.xml` 文件中配置签名信息。例如,以下代码片段展示了在 `AndroidManifest.xml` 文件中配置签名的示例: ``` <application ... android:debuggable="false" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:networkSecurityConfig="@xml/network_security_config" android:usesCleartextTraffic="true"> <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="@string/admob_app_id"/> <activity android:name=".MainActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:label="@string/app_name" android:launchMode="singleTop" android:theme="@style/AppTheme.NoActionBar" android:windowSoftInputMode="adjustResize"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> ``` 在上面的示例中,我们使用了自己的签名证书来签署项目。你可以在 `build.gradle` 文件中设置签名证书的信息,例如: ``` android { ... signingConfigs { release { storeFile file("your_keystore_file_path") storePassword "your_keystore_password" keyAlias "your_key_alias" keyPassword "your_key_password" } } buildTypes { release { signingConfig signingConfigs.release ... } } } ``` 在这里,你需要将 `your_keystore_file_path`、`your_keystore_password`、`your_key_alias`、`your_key_password` 替换为你的实际值。然后,在使用 `gradle` 命令构建 APK 时,gradle 将使用你设置的签名信息来签署 APK。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值