去年在开发一个安卓小游戏的时候,还煞有其事地对apk包做了个人签名。当时只是照猫画虎的按书上说的步骤来做,也没深究为什么。最近比较详细的了解了一下java的安全机制,才发现原来有那么多一知半解的问题。
先从非对称加密的公钥、私钥机制说起。所谓非对称就是指用私钥加密的内容要用公钥来解密(反过来用公钥加密也一样必须要用私钥来解密。公、私其实是对等的一对儿,并非指技术方面,而是针对发布范围来说的)
有了这种加密、解密的唯一性,我们就可以有这样一些结论:用私钥/公钥加密的,只有通过对应的公钥/私钥来解密;而能用某个公钥/私钥解开的,一定是用其私钥/公钥加密的。有点绕嘴,其实不难理解。利用这个特性,我们就可以达到一些互为验证的目的。
然后介绍一下相关操作。先说关于keystore的:
Keystore是存储密钥对集合的文件,所以也叫密钥库文件(之前都不知道可以存储多个)。利用jdk工具是这样生成的:
keytool -genkey -alias mykey1 -keypass <这个key的密码> -validity 1000 -keystore xxx.keystore
如果这个xxx.keystore文件还不存在,那么会新生成一个,同时要求输入一个对xxx.keystore文件进行读写的密码。这个和keypass后的密码参数不需要相同。
继续一条:
keytool -genkey -alias mykey2 -keypass <这个key的密码> -validity 1000 -keystore xxx.keystore
这个时候xxx.keystore文件已经存在了,所以这个命令是再追加进去一个密钥对。所以输入第一次设定的读写密码即可。
从字面意义看会以为alias是个可有可无的别名,但其实不是,这个参数是必须的,是一对密钥的“正式”的名字。即便我们不输入这个参数:-alias mykey1,那么系统也会自动生成一个叫做mykey的密钥对名字;
如果没有这个参数:-keypass <这个key的密码>,那么系统会提示输入。当然直接回车是设定为和库文件的读写密码相同。
那么现在呢,实际上xxx.keystore里已经存了两个密钥对,mykey1和mykey2。可以用这个命令查看:
Keytool –list –keystore xxx.keystore,当然查看也是需要输入密码的
有了这些密钥对,即可以对jar文件进行签名了。命令是这样的:
jarsigner -keystore xxx.keystore -storepass <文件读写密码> -keypass <这个key的密码> xxx.jar mykey1
同样的,如果没有这个参数:-storepass <文件读写密码>,系统会要求输入。没有这个参数:-keypass <这个key的密码>,一种情况是mykey1的密码和库密码相同,那么就可以签名成功。如果不同,那就会报错。
导出公钥为一个证书,命令是:
Keytool –export –file xxx.cer –keystore xxx.keystore –alias mykey1,输入库密码后,会生成一个xxx.cer的证书文件。
一个库里可以有多个密钥,但一个证书里只有一个公钥。用命令keytool -printcert -file xxx.cer查看证书,结果是库密钥列表中的一个。
私钥一般用命令导不出来(也没有导出的必要)。但是可以用写代码来导出。