加密技术是最常用的安全保密手段,利用技术手段把明文变为密文(加密)传送,到达目的地后再用相同或不同的手段还原(解密)。常见的加密算法可以分成三类,对称加密算法,非对称加密算法和HASH算法。前两类是可逆的,即加密后的密文仍然可以转换成明文,但Hash算法是不可逆的,即使在有源码及密文的情况下也无法将明文还原出来,如MD5算法。

由于Java的语言特点及Android的开放性质,出现了越来越多的恶意程序。谷歌Android市场在也曾多次遭恶意开发者上传基于正常应用篡改后的恶意软件,虽然这些软件已经被查出,但在将其下架前已经造成了几十万用户被感染。这些恶意程序都是以已存在的成名的应用为载体,经过二次处理后植入恶意代码,重新签证后再次向市场发布,诱导用户下载使用。为了避免这种情况的发生,保护自己的应用在未经自己允许的情况下惨遭篡改,保护自己的应用不会被人利用做一些伤害用户的行为,本章节中将介绍这样一种保护机制。

Android系统要求每一个安装进系统的应用程序都是经过数字证书签名的,数字证书的私钥(即.keystore签证文件)则保存在程序开发者的手中,签证后的信息摘要保存在APK包中的.RSA文件中。数字证书用来标识应用程序的作者与应用程序之间建立信任关系。一旦证书被篡改,则.RSA文件被替换了,即表明应用程序的原作者不再为该应用负责。依照这个原理,可以在第一次运行程序时读取APK中的.RSA摘要信息对其进行判断是否是与经应用原作者签名后产生的信息一致。如果一致则让程序正常运行;如果不一致则表明应用被篡改过,提示用户并终止运行。

可以通过以下方法获取APK包中的.RSA信息:

Signature[] sigs = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures;byte[] data = sigs[0].toByteArray();

在Android官方文档中,对Signature类的定义是:在应用程序包及对该包进行签名的证书间建立起不透明的、不可改变的代表关系。执行Signature.toByteArray()将返回.RSA的字节信息。

下面将把这些字节转换成可阅读的数字指纹信息:

// alg参数指定算法MessageDigest algorithm = MessageDigest.getInstance(alg);// 将状态重围到初始化,准备好进行计算Hash值。algorithm.reset();// 返回计算后的Hash值algorithm.update(data);// 将Hash值转为可读的16进制文本byte[] dataHash = algorithm.digest();

通过MessageDigest来计算数字指纹信息,其算法核心是HASH函数。哈希函数提供了这样一种计算过程:输入一个长度不固定的字符串,返回一串定长度的字符串,即HASH值。

HASH函数主要可以解决以下两个问题:一是无法通过HASH值得到原报文;二是不存在不同报文经HASH操作后生成相同HASH值。

这样在数字签名中就可以解决验证签名和用户身份验证、不可抵赖性的问题。在获取MessageDigest时要指定所使用的算法名称,常见的算法是专门用于加密处理的MD5和SHA1。这两种算法产生一种128位信息摘要,除彻底地搜寻外,没有更快的方法对其加以攻击,而其搜索时间一般需要1025年之久,这样即可保证信息在一段时间内的有效性与安全性。

使用MessageDigest时,养成一个良好的习惯是在读取数据前将其reset()置初始化状态,即使这个实例是刚实例化的,这样尽量可以避免之前已读的冗余数据对最后的结果产生负作用。接下来就是使用update()方法读取待计算的数据,完成后调用digest()将返回计算后的HASH值dataHash数组。最后为了可读性,通过自己实现的toHexString()把HASH值由byte转为16进制文本。

在得到dataHash时,即可对应用程序是否正版进行判断了,但一般为了简便,把提前写入的正版的指纹信息与最后HexString值进行比较,从而得出应用程序是否被篡改的结果。比较代码如下:

txtVerify.setText(alg + "\n");String result = "This soft is a pirated software.";if (alg.equals(MD5)) {  txtVerify.append("Original:" + "\n" + HASH_VALUE_MD5 + "\n");  if (HASH_VALUE_MD5.equals(hexInfo)) {      result = "This soft is a genuine software";  }} else if (alg.equals(SHA1)) {  txtVerify.append("Original:" + "\n" + HASH_VALUE_SHA1 + "\n");  if (HASH_VALUE_SHA1.equals(hexInfo)) {      result = "This soft is a genuine software";  }}txtVerify.append("Current:" + ":\n" + hexInfo + "\n");txtVerify.append(result);

以上代码中的HASH_VALUE_MD5和HASH_VALUE_SHA1分别是使用Code_Test_Key.keystore签名后的APK实际计算出的HASH值。






以下信息来自网易:

一、签名方法
方法一.源码签名(android签名方法) 备注:几乎所有的自动化签名工具都是采用的这种方法 (1)生成签名所需要的keypair:公钥与私钥 andoid源码中提供了脚本 build/target/product/security/mkkey.sh 来生成签名所需要的key
            
if ["$1" == ""]; then
echo "Create a test certificate key."
echo "Usage: $0 NAME"
echo "Will generate NAME.pk8 and NAME.x509.pem"
echo " /C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com"
return
fi

openssl genrsa -3 -out $1.pem 2048

openssl req -new -x509 -key $1.pem -out $1.x509.pem -days 10000 \
-subj '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'

openssl pkcs8 -in $1.pem -topk8 -outform DER -out $1.pk8 -nocrypt
从脚本中,我们可以得知,是采用以下步骤生成keypair的。
第一步:生成长度为2048位的RSA私钥

root@bt:~/bubble example# openssl genrsa -3 -out test.pem 2048
Generating RSA private key, 2048 bit long modulus
...+++
...................................................................................+++
e is 3 (0x3)


root@bt:~/bubble example# cat test.pem
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAxJGCXH8i3XgogreH9oMoTaqUR6zTmblWUH3dOg7lV7F+cDDC
P4hPBItEumMGkwhHqdqXMrvAj3RlYVGq6iozWJDluUDzY095G7UuuiPRXr5q0vl4
t0kzPJIAon6kdbAl/0JFJqKLCeyk4aWsa4yRFBi0BWC7qg4ilLdHIZL0CFnRHK6F
9haXVxBBvDPdA06YT5MDqvThs/ZCY1BnGmBb+Srj8YJJ9Nvdxix5Dmqs5JDsn+L0
5OweZqwMcyKVMTrvjj921kJvReuHRRtVwE/xrSkusZITLZ45zySiRAi+NRR9hFlS
efla/8gyCXmCYcvMDOFu827QJpbzWhKgFUWRawIBAwKCAQEAgwusPaoXPlAbAc+v
+azFiRxi2nM3u9DkNak+JrSY5SD+9XXW1QWKAweDJuyvDLAvxpG6IdKAX6LuQOEc
nBwiOwtD0NX3l4pQvSN0fBfg6dRHN1D7JNt3fbarFv8YTnVuqiwuGcGyBp3DQRkd
nQhguBB4A5XScV7BuHova7dNWuVfLWJAgeSUckHZBUHKWkq6ETo63QBW9yqjwUKh
aLAZFbyBMvmhX+9oWgKBTmmr91TIA4z0JbkpPWD8LBuTKKld6FSrOEA432+SNZvW
WMjr2GxyPoE4+6kiB4EhnhQI7hOzSFHW7vD1dlxkDi+B7MvN+cgPqlZ0kvRO2v5V
5uz2GwKBgQD0s9PCzQnsdpOhUHUPAe6ztLk4Uy0y7NoWl7M/P7jEqTC73OP05oGx
FVGLri3l2X7g/NVUtgSEzTUBJH/rEnBJKaCjVgtW0eaIM5Hu3x/evDdUIDeIpe6V
4D4ko6z5XuHddsURO7VOOTQXA8B2xG3bb1y8dCZ3SDN3VMX9TkQbpwKBgQDNpMdi
ZjXMNRna49weee/NgQJzDEcsVFw2Kbk1vZ9xr19mSCfi/nMQKdcrap5FGBLfnbox
9lHbvWWRDHlNYcyZiB/Sq9bDJN2jwR+lXAKxLE8vM5i1DjHw46TLMz23cRUTIRl+
19qclQmE8HHIuiw7ptia/8aqAfUFvM8h7J4EnQKBgQCjIo0siLFITw0WNaNfVp8i
eHt64h4h8zwPD8zU1SXYcMsn6Jf4mavLY4uydB6ZO6nrUzjjJAMDM3irbaqctvWG
G8Bs5AePNpmwImFJ6hU/KCTiwCUFw/Rj6tQYbR37lJaTpINg0nje0M1krSr52Ek8
9Oh9osRPhXek4y6o3tgSbwKBgQCJGITsRCPdeLvnQpK++/Uzq1b3XYTIOD15cSYj
07+hH5Tu2sVB/vdgG+THnGmDZWHqaSbL+Yvn05kLXaYzlohmWr/hx+SCGJPCgL/D
kqx2HYofd7sjXsv17RiHd356S2NiFhD/OpG9uLEDSvaF0XLSbzsR/9nGq/iufd9r
8xQDEwKBgHVOxkAoYn4Q3DXhfeTrxpZEmg7lBTuZAg8A52xH/eVMVTSKwqw+NxfZ
wrU+fGQeruGm5mmOzwOuTDwywcM8qs0/gQVsUVliCMd6IbwDnN4dsNLsZdZp1nV7
rbi0sCmk218gLOQ9p2jv9i0BS8etSEkBwRzF99KgruMGtyd4R39b
-----END RSA PRIVATE KEY-----


第二步:生成x509格式的公钥证书

root@bt:~/bubble example# openssl req -new -x509 -key test.pem -out test.x509.pem -days 10000
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:California
Locality Name (eg, city) []:Mountain View
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Android
Organizational Unit Name (eg, section) []:Android
Common Name (eg, YOUR name) []:Android
Email Address []:android@android.com


root@bt:~/bubble example# cat test.x509.pem
-----BEGIN CERTIFICATE-----
MIIEqjCCA5KgAwIBAgIJALNXgLhW3YPbMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAg
Fw0xMjEyMTMwNzQ1MDZaGA8xOTA0MDMyNTAxMTY1MFowgZQxCzAJBgNVBAYTAlVT
MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRAw
DgYDVQQKEwdBbmRyb2lkMRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQDEwdBbmRy
b2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMIIBIDANBgkq
hkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAxJGCXH8i3XgogreH9oMoTaqUR6zTmblW
UH3dOg7lV7F+cDDCP4hPBItEumMGkwhHqdqXMrvAj3RlYVGq6iozWJDluUDzY095
G7UuuiPRXr5q0vl4t0kzPJIAon6kdbAl/0JFJqKLCeyk4aWsa4yRFBi0BWC7qg4i
lLdHIZL0CFnRHK6F9haXVxBBvDPdA06YT5MDqvThs/ZCY1BnGmBb+Srj8YJJ9Nvd
xix5Dmqs5JDsn+L05OweZqwMcyKVMTrvjj921kJvReuHRRtVwE/xrSkusZITLZ45
zySiRAi+NRR9hFlSefla/8gyCXmCYcvMDOFu827QJpbzWhKgFUWRawIBA6OB/DCB
+TAdBgNVHQ4EFgQU1aCdtEBdGQLhO7nqnaR4pCJW0q0wgckGA1UdIwSBwTCBvoAU
1aCdtEBdGQLhO7nqnaR4pCJW0q2hgZqkgZcwgZQxCzAJBgNVBAYTAlVTMRMwEQYD
VQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRAwDgYDVQQK
EwdBbmRyb2lkMRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQDEwdBbmRyb2lkMSIw
IAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tggkAs1eAuFbdg9swDAYD
VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAq/BUGCGWpF1E7WQ/vmoDrZ4r
2XTmyHycQSFpvozeKjvlBD1ESNchEWvxOSFiFrCX/OqFwEn8sQRMClpR4fdXmKrv
5GxrXN3M6ZNOmr7cNGINNeJkKhQfepaUE9bdcdSyzQsgajF0rhYosyW48k7DW5J8
zXoBIrUgGV1KhnIPci+Jg7+QBhXGZxIOyVqDg8q8h8CJgMldyyPNdmhHDAH497Sp
EgIioD/95Gk5DnrHDwlTo54vh5hT2KEjcfkMNEhXpQFgYJog+HYcJwjdFoH0ZA+P
2lZ9o6hT3Dkc1PzdgzehVVa+ys0SZ4pHMPpx2z5T9cR25wO15mC8inkcA5onqQ==
-----END CERTIFICATE-----


第三步:生成符合PKCS8标注的私钥文件

root@bt:~/bubble example# openssl pkcs8 -in test.pem -topk8 -outform DER -out test.pk8 -nocrypt


可以在http://blog.csdn.net/anxuegang/article/details/6157927看到不同证书的格式的介绍
(2)用keypair签名 android源码中提供了签名生成工具,和签名所需要的公钥,私钥文件。其中 sigapk.jar为签名工具,platform.x509.pem为公钥文件,platform.pk8为私钥文件。 网上较流行的AutoSign工具就是采用的这种方法。
#!/bin/sh
MY_SDK_HOME=~/platform/android/main/mydroid/
PEM=${MY_SDK_HOME}/build/target/product/security/platform.x509.pem
PK8=${MY_SDK_HOME}/build/target/product/security/platform.pk8

if [ $# -ne 2 ]
then
echo Usage $0 in.apk out.apk
exit 1
fi
java -jar
${MY_SDK_HOME}/out/host/linux-x86/framework/signapk.jar \
${PEM} ${PK8} $1 $2


第四步:签名

root@bt:~/bubble example/dis# java -jar signapk.jar test.x509.pem test.pk8 unsig.apk signapk.apk



第五步:优化,主要是为了 数据边界与文件的开始是内存对齐的

root@bt:~/bubble example# zipalign -v 4 your_project_name-unaligned.apk your_project_name.apk



方法二、命令行签名(Sun 签名方法) 工具:keytool,jarsigner 第一步:生成keystore

root@bt:~# keytool -genkey -alias dani.keystore -keyalg RSA -validity 4000 -keystore dani.keystore

第二步:签名

oot@bt:~/bubble example/dis/FrozenBubbleSignapk/META-INF# jarsigner -keystore dani.keystore -digestalg SHA1 -sigalg MD5withRSA -signedjar signed.apk unsigend.apk dani.keystore


第三步:优化

root@bt:~/bubble example# zipalign -v 4 your_project_name-unaligned.apk your_project_name.apk


二、签名过程分析 无论采取哪种签名方法,都会APK中生成META-INF文件夹,该文件夹包含三个文件 1. MANIFEST.MF 2.CERT.SF 3.CERT.RSA
生成过程如下: 第一步:.首先对文件夹中的文件采用sha1-base64生成摘要,将这些摘要信息保存在MANIFEST.MF中 我使用以下脚本对比了 MANIFEST.MF中对应的值,符合

#!/usr/bin/perl
use Digest::SHA1 qw(sha1 sha1_hex sha1_base64);

die "$0 requires one arguments (file pathname) . \n" if $#ARGV !=0;

$filename=shift;

open FH,$filename or die "cannot open $filename";


$sha1 = Digest::SHA1->new;

$sha1->addfile(*FH);

$digest= $sha1->b64digest;

print $digest,"\n";

close FH;


第二步:.对包括 MANIFEST.MF文件在内的所有文件采用 sha1-base64生成摘要,方法如下。



SHA1("Name:
filename"+CR+LF+"SHA1-Digest: "+SHA1(
file_content)+CR+LF+CR+LF)



然后将 这些摘要信息保存在CERT.MF中。 备注:采用android(Android signapk.jar与Sun jarsigner两种签名方法生成的CERT.MF文件弱有不同。

3. 对第二步中的摘要信息,采用选取的签名算法(SHA1-RSA或者MD5-RSA),用私钥进行签名,同时把公钥证书与签名信息存放在CERT.RSA中
Signaturesignature=Signature.getInstance("SHA1withRSA");
signature.initSign(privateKey);
je=newJarEntry(CERT_SF_NAME);
je.setTime(timestamp);
outputJar.putNextEntry(je);
writeSignatureFile(manifest,
newSignatureOutputStream(outputJar,signature));

je=newJarEntry(CERT_RSA_NAME);
je.setTime(timestamp);
outputJar.putNextEntry(je);
writeSignatureBlock(signature,publicKey,outputJar);


三、签名校验 由签名生成过程,我们可以知道签名做了两件事情: 1. 完整性校验,可以发现APK包中的文件是否存在变动。 如果对文件进行修改,对应的SHA1值会发生变动。
2.APK发布作者身份唯一性校验 当在android设备上安装apk包时,会从存放在CERT.RSA中的公钥证书中提取公钥,进行RSA解密来校验安装包的身份。
使用以下命令,可以校验APk包的签名状况

root@bt:~/bubble example/dis# jarsigner -verify -certs -verbose FrozenBubble-modify-sig.apk

4689 Wed Dec 12 15:56:44 CST 2012 META-INF/MANIFEST.MF
4810 Wed Dec 12 15:56:44 CST 2012 META-INF/DANI_KEY.SF
913 Wed Dec 12 15:56:44 CST 2012 META-INF/DANI_KEY.RSA
sm 29099 Wed Dec 12 15:10:22 CST 2012 assets/levels.txt

X.509, CN=dani lee, OU=taomee, O=taomee, L=shanghai, ST=CA, C=CA
[certificate is valid from 12/12/12 3:43 PM to 11/25/23 3:43 PM]

sm 25213 Wed Dec 12 15:20:14 CST 2012 res/drawable/app_frozen_bubble.png


使用不同的key生成的签名信息会不同, 不同的私钥对应不同的公钥,因此 最大的区别是签名证书中存放的公钥会不同 ,所以我们可以通过提取CERT.RSA中的公钥来检查安装包是否被重新签名了。
具体的APk签名对比实现方法ttp://www.blogjava.net/zh-weir/archive/2011/07/19/354663.html 可以在这里查看到, 非常佩服这位博主,是个java高手,几乎每天都在更新博客。
参考: http://www.blogjava.net/MEYE/articles/357174.html http://www.blogjava.net/zh-weir/archive/2011/07/19/354663.html

更多相关文章

  1. Android的Soong介绍
  2. AndroidStudio使用GreenDao的方法
  3. 64Ubuntu报错Failed to get the adb version:
  4. 【Android】常用的adb命令
  5. 搭建OPhone开发环境
  6. Android(安卓)LayoutInflater.inflate()方法的参数用途
  7. 下载Android(安卓)source 问题
  8. Android(安卓)-----color.xml
  9. Android(安卓)APT 技术浅谈

随机推荐

  1. Android中文件的读写
  2. android APK反编译入门
  3. android ndk 开发之 在 应用程序中使用 j
  4. Android(安卓)NDK 使用第一步,编译c文件,声
  5. android数据库
  6. 谈谈Android的那些事
  7. Android安全加密:对称加密
  8. android:scaleType、android:layout_alig
  9. 搭建 Android(安卓)2.2 开发环境
  10. android 小知识