应用签名(或代码签名)使得Android设备、Android市场及其他发布方式能够清楚应用属于哪个签名所有人,并可以确保代码在签名后没有被修改。
公钥加密和加密签名
公钥加密的数学原理是,大的素数相乘很容易,但是求大素数的因子很困难。计算大素数乘积可能只需要微秒级的时间,而求大素数的因子可能需要数百万年,需要天文数字般大的计算能力。
求乘积和求因子之间的天壤之别意味着由两个大素数生成的乘积所得到的钥匙可以作为公钥。对加密的消息进行解密就是求两个大素数因子,这两个因子就是私钥。这意味着由公钥加密的文件是安全的,只有持有私钥才能够破解。
在Android应用中所要生成的签名取决于公钥加密的相关属性。
对文件签名的步骤如下:
1.根据文件计算唯一散列值。这也称为消息摘要(message digest)。
2.根据签名者的私钥对消息摘要进行“加密”。这样就得到了签名。
好了!现在有了数值签名——对文件通过散列函数求值,并且和签名者的私钥相关。
验证一个签名文件的步骤如下:
1.根据文件计算唯一散列值。
2.使用公钥对签名进行“解密”,其结果值和散列值应该相同。
你可能注意到一个有趣的现象,文件(在我们这里即应用)源于私钥所有者,该私钥和在校验中使用的公钥对应。除非文件没有发生改变,否则对签名进行解密所求得的散列值会不同于从文件中计算出的散列值。
验证签名也确保了签名没有拷贝错误。签名是和其创建文件唯一相关的。
注意:你可能已经注意到我们在谈到对消息摘要或散列加密时,对“加密”和“解密”两个词加了引号。这是因为它和你通常在公钥和私钥系统中所使用的加密和解密不同——通过公钥对消息进行加密,从而只有私钥持有者才能够读懂该消息。
这里,“加密”表示的是“计算一个数值”。通过私钥对散列或消息摘要进行“加密”并不是把消息隐藏起来。使用加密和解密这两个词的原因是当你使用公钥进行解密时,你得到通用的散列或消息摘要。
任何持有公钥和发布算法的人都可以对消息“解密“——这正是验证的意义:看到你获得和发布人提供的同样的散列签名,也证实了发布人确实持有和公钥对应的私钥,并能证实文件和发布人一致。
因为可以通过公钥来计算验证,你的Android系统,以及任何其他相关方,可以验证应用是使用某个特定键(key)计算的签名,而且在生成该签名后就没有被修改过。
更普遍的是,任何电子文档(任意数据)都可以对其加密签名,而加密后的签名即“数字签名”可以用于对文件进行签署,就相当于法律意义上的手写签名。
签名是如何做到保护软件用户、发布商和安全通信的
作为计算机软件用户,你可能一直在思考:“如果能够知道我使用的软件来自哪里,并且在我的设备上没有被修改,那将是一件很好的事情。”带签名的应用就可以达到这个目的。该信心来自于这个签名,原理类似于你可能用过的图形签名。当你浏览Web时,你已经依赖于图形签名来确认你正在浏览的电子网站是真实的,而不是冒名骗钱之后就开溜的流氓网站。在电子商务中,客户使用第三方证书颁发机构提供的公钥来验证服务器的证书签名。浏览器内置了一些证书颁发机构提供的这类密钥。
证书颁发机构的作用是巩固各方的信任关系:信任浏览器供应商只使用信誉良好的证书颁发机构的密钥,电子商务服务提供商从浏览器供应商信任的颁发机构获取证书。证书颁发机构有责任核实信息的真实性,如Amazon.com确实是真正的Amazon.com。现在,当你的浏览器向Amazon.com发起安全会话时,你清楚两件事:加密之后进行传输的数据是安全的,只有电子商务服务商能对数据进行解密。你可以相信正在访问的服务器,因为它所使用的证书是由证书颁发机构发布的,并且证书颁发机构已经采取各种措施确保自己是向已知的另一方发布证书。
Android软件的自签名证书
对于Android软件签名,其签名证书不需要来自证书颁发机构。Android签名可以由软件发布商创建——在这个例子中,软件发布商就是你。和电子商务中的交易不同,Android软件不需要确保和浏览器的每一次连接都是真实可信的,例如连接到真正的Amazon.com,Android软件可能会使用未知出处的连接,使用软件也不需要严格了解签署方的身份。
对于考虑使用由证书颁发机构所发布的签名的企业,Google文档明确指出应用没有必要使用证书颁发机构提供的签名,而自我认证是Android应用的非正式标准。
除了初步验证应用开发者的身份,Android软件在升级应用时也会使用Android数字签名,从而确保升级时能够访问历史版本所创建的文件,而应用升级也并非恶意使用应用,没有试图窃取用户数据。
只要确定软件升级和初次获取软件来自相同的发布商,就可以充分相信正在使用的软件是安全的,而且软件的分发商即Android市场,是知道该软件的发布商的。
除了确保更新来源于原始发布商之外,Android应用是沙盒式的,需要获得许可才能访问可能损坏你的数据或造成在移动设备上收费的功能,详细说明请参考下面这条链接:http://developer.android.com/guide/topics/security/security.html。
应用签名
加密签名背后的概念是微妙和复杂的。但是其复杂性是由SDK工具管理的。当你在设备或模拟器上编译和运行Android代码时,运行的是带签名的代码。
证书调试
如果你对本书给出的例子都做过实际练习,创建Android项目并在模拟器或设备上运行它。你可能已经注意到,虽然所有的Android代码都必须签署签名,但你不需要创建证书,并且你的应用仍然可以安装在Android手机上。有这种便利性是因为使用了自动创建的调试证书。我们一起来看看调试证书。
首先查看home目录下的android目录。在该目录下,应该可以找到一个名为debug.keystore的文件。使用keytool命令,可以查看该文件中的内容:
keytool -list -keystore debug.keystore
当需要密码时,输入android。则可以看到如下的输出:
Keystore type: JKSKeystore provider: SUNYour keystore contains 1 entryandroiddebugkey, May 13, 2010, PrivateKeyEntry,Certificate fingerprint (MD5): 95:04:04:F4:51:0B:98:46:14:74:58:15:D3:CA:73:CE
keystore类型和提供商表明keystore是Java keystore,兼容Java加密架构和使得Android得以使用代码签名和其他加密工具的Java类。关于Java加密架构的更多信息可以访问下面这条链接:http://download.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html。
keytool命令是JDK的一部分,在P30“keytool”一节做了简要描述,要查看更详细的说明可以访问链接http://developer.android.com/guide/publishing/app-signing.html#cert。查阅keytool详细的文档说明可以访问下面这条链接:http://download.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html。
keytool的list选项最后一行输出是证书指纹。证书指纹是根据密钥生成的唯一编号。在P124“应用签名”一节中,可以看到该编号的一种使用方式,通过该编号获取API密钥。
该证书在很短的时间间隔内就会过期失效,因此不能用于Android软件分发,而只能用于测试。不要误认为可以使用调试证书来对软件进行签名就意味着你在分发软件时可以不需要对软件进行签名!
创建自签名的证书
准备对代码进行签名以便发布了吗?首先,使用keytool工具创建私钥:
keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 50000
注意:字符“”表示换行符,在Unix和Mac OS X系统上可以使用该字符来表示多行命令。但是,在Windows系统上,必须在一行上输出整条命令,不能使用“”来表示。
对于my-release-key和alias_name,可以选择一个名字进行替换。参数-keysize和-validity应该保留,正如前面的代码所示。
如下面代码所示,keytool命令会要求输入keystore的密码。在访问keystore时,需要记住该密码及关于你个人、组织结构和地理位置的一系列问题。keytool工具生成一个私钥作为证书签名,其有效期大约是150年,保存在文件my-release_key.keystore中:
[email protected]:~$ keytool -genkey -v -keystore example-release-key.keystore -alias example_alias_name -keyalg RSA -keysize 2048 -validity 50000Enter keystore password:Re-enter new password:What is your first and last name? [Unknown]: Example ExamplenikWhat is the name of your organizational unit? [Unknown]: ExampleWhat is the name of your organization? [Unknown]: ExampleWhat is the name of your City or Locality? [Unknown]: ExampleWhat is the name of your State or Province? [Unknown]: MassachusettsWhat is the two-letter country code for this unit? [Unknown]: USIs CN=Example Examplenik, OU=Example, O=Example, L=Example, ST=Massachusetts, C=US correct? [no]: yesGenerating 2,048 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 50,000 days for: CN=Example Examplenik, OU=Example, O=Example, L=Example, ST=Massachusetts, C=USEnter key password for <example_alias_name> (RETURN if same as keystore password):Re-enter new password:[Storing example-release-key.keystore]
现在,有了keystore的有效密钥。
千万别丢失密钥
虽然加密的数字签名在很多方面要比手写的签名更可靠和安全,但是它也有不足:无法对文件进行数字签名。
如果你丢掉了签名的证书,你就失去了在Android设备和Android市场上的“身份证”。这意味着即使你编译和发布的代码和之前完全相同,你也无法使用这些新编译的应用来更新之前的应用,因为Android设备和Android市场都无法识别出你是之前的发布商。
要在多个地理位置的多种类型的媒体上保存多份签名证书副本,包括纸质文件。要保证这些备份文件的安全性。如果你的签名证书被其他人使用,他们可以替换你的客户的Android设备的程序。
关于确保签名证书安全性的详细建议可以通过Android Developer站点查阅:http://developer.android.com/guide/publishing/app-signing.html#secure-key。
注意:相反,你的加密签名是仅属于你的签名,因为它归你所有。在你想要发布Android应用并继续作为该应用的发布商时,你可以随意生成、使用和丢弃签名。不要害怕尝试和学习!
使用自签名的证书对应用进行签名
现在开始对应用签名。在Eclipse中,选择要发布的应用的项目,并选择File→Export命令。你可能会问,“为什么要选择export命令?”毕竟,如果你想让别人尝试你的应用,你可以给其一份bin下的.apk文件副本。它看起来很随意:export对话框中提供了一系列功能,这是一个放置与deploying有一些差别的处理过程的合适地方。
在这个例子中,我们使用的是TestActivity项目,但是实际上可以使用任意一个项目——你自己创建的项目,或者本书示例中给出的任意项目。
Eclipse会提供一个选项列表,这些选项以文件形式组织。选择Android文件夹,然后选择Export Android Application选项(如图4-1所示),最后单击Next按钮。
首先,需要查看应用在配置上是否存在任何错误,有些错误信息会妨碍应用的发布,例如在manifest文件中把debuggable属性设置成了true。如果应用已经准备就绪,那么在如图4-2所示的对话框中不会显示任何错误。
应用的签署发布包含多个步骤,后续对话框主要集中于签名。所请求的信息跟你为创建在P128“创建自签名的证书”一节中所描述的发布密钥输入的信息一致。
下一步,选择keystore,如图4-3所示。keystore是个文件夹,保存着你的密钥。
图4-1:导出Android应用
图4-2:Android应用,它在签名和发布上没有任何问题
图4-3:选择keystore
输入keystore名称和密码之后,单击Next按钮进行下一步操作:选择密钥的别名,输入该别名的密码,如图4-4所示。
图4-4:选择密钥别名
如果你实际练习过了P128“创建自签名的证书”一节中所描述的各个步骤,那么在你的keystore文件中,只会有一个密钥及一个别名。输入密钥,单击Next按钮。下一步是指定目标.apk文件,检查确定你的应用是否包含一些错误。如果一切准备顺利,将会看到图4-5所示的结果。
图4-5:选择目标路径及最后的检查
单击Finish按钮,在指定的路径下面就可以看到所指定的.apk文件已经生成好了。