1. linux安装openssl库
参见《精通PKI网络安全认证技术与编程实现》2.3.2节 Linux下搭建OpenSSL开发环境
Linux下面解压tar.bz2文件:tar jxvf android-ndk-r5c-linux-x86.tar.bz2
2. 配置NDK的环境变量
在~/.bashrc文件末尾添加:
NDK=~/android-ndk-r4b
export NDK
执行source ~/.bashrc
如果有终端已经运行,需要在重启终端才能使用NDK变量
3. JNI介绍
JNI主要功能就是能够调用到C库,在这里我们需要用C或C++调用openssl库实现加密签名等功能,然后编译成arm体系的so库,用java调用提供的接口。
详细介绍参见此书:《TheJava Native Interface: Programmer’s Guide and Specification》
4. 下载android版本的openssl,编译
现在网上我看见过3种版本的android-openssl,fries版本,eighthave版本以及guardianproject版本,前面两个版本有测试过但是没有尝试成功,guardianproject版本编译成静态库再给android的JNI动态库程序调用的话会找不到方法,不清楚是什么原因,但是直接将JNI程序与openssl工程一起编译就可以实现。
下面这个blog有说编译openssl静态库给android用,但是不知道他用的是什么版本的Openssl,我按照他的方法尝试没有成功。
http://blog.youkuaiyun.com/someonea/article/details/6312213
guardianproject版本原版下载地址:
https://github.com/guardianproject/openssl-android
我修改过的版本:
http://download.youkuaiyun.com/source/3408214
在我修改过的版本中可以直接在myAPP文件夹下编写JNI程序,与Openssl一起打包编译成动态库就行了。
编译时可能出现一些undefined reference,大部分可能是没有添加链接库,有些情况也可能是NDK版本问题,最好用最新版本的NDK(我用的r5c),注意有没添加以下两个静态库
LOCAL_LDLIBS := -lz –ldl
注明下:如果是下的本人修改的openssl源码,使用android-8的版本,在本人上传的openssl源码中default.properties可以更改版本
5. 将编译完的so库放置android工程目录的libs/armeabi目录下
6. JAVA调用动态库
下面是本人测试时写的一个两数相加的:
- native方法:
- public native int add(int a,int b);
- load库:
- static {
- System.loadLibrary("add");//编译完的都是带Lib开头的,这里Load不要加
- }
7. 在c程序中调用android的log,记录运行信息
表示完全不会用gdb调试这玩意,只好用log一步步记录了…..
- #include<android/log.h>
- #define LOG_TAG"show infomation" //这个是log标签,内容自己设置
- #define LOGW(a) __android_log_write(ANDROID_LOG_WARN,LOG_TAG,a) //除了这个方法还有__android_log_print方法,跟printf很像,具体可以看android/log.h里面
- Makefile中LOCAL_LDLIBS:= -L$(SYSROOT)/usr/lib –llog
8. bouncyCastle结合openssl进行密钥管理
参见这个博客的介绍
http://blog.youkuaiyun.com/zhenyongyuan123/article/details/5558562
本人已经尝试成功用bouncyCastle在android上生成密钥库和密钥对,
这里需要注意的是Android上本身有bouncyCastle包,如果直接导入包会在运行时报找不到类等错误
我们需要下载bouncyCastle源码,修改包名比如org.bouncyCastle2等,编译打包成jar
Build Path->Add External Archives添加包,不然运行时也会报找不到类错误,这个可能是因为没有将jar包打入apk中。
9. openssl与cryptoAPI对称加密的兼容问题
cryptoAPI本身不支持传明文密钥进去,需要通过genKey或者DeriveKey得到Key句柄,
而这里面不仅仅只是对传进去的密钥进行hash算法,具体可参见MSDN
http://msdn.microsoft.com/en-us/library/aa379916%28v=VS.85%29.aspx
Remarks里面的
If the hash is not a member of the SHA-2 family and therequired key is for either 3DES or AES, the key is derived as follows:下面六个步骤。
我们可以通过公钥加密,私钥解密查看到cryptoAPI进行对称加密的会话密钥,这里已经有完整的代码:
http://www.codeproject.com/KB/security/plaintextsessionkey.aspx
在使用openssl的evp封装好的对称加密时貌似有点问题,可能是我使用错了,使用下面这种方式可以与cryptoAPI的加密匹配上
http://blog.youkuaiyun.com/lyjinger/article/details/1722570
10. 有些时候可能只需要NDK编译出静态库,但是如果不加上动态库会什么都不编译
这里只编译静态库需要在JNI下面建立一个Application.mk,需要在该文件中加上一句:
APP_MODULES := libexample(模块名称)
11. 另外,Android上面有一个证书安装的功能,没有真机,不了解什么用途,
在android模拟器的setting里面可以找到Location&security栏,里面可以install from SD card安装加密的证书,p12格式的,带私钥的。安装后可以在Data/misc/keystore找到对应的证书,密钥等文件,代码操作没有权限。
----------------------------------------以下内容被修改--------------------------------------------------
System/etc/security下面存在cacerts.bks,BouncyCastle密钥库,读取时提示完整性检查失败,这个文件也应该是没有权限访问的
---------------------------------------------------------------------------------------------------------------
cacerts.bks是有权限读取的,默认密码时changeit,如果密码错误则出现完整性检查失败
如果需要修改cacerts.bks可以尝试使用remount或者chmod修改读写权限,再访问
certInstaller安装的证书还未找到方法操作,看过CertInstaller的源码,模拟做了一遍依然无效
有朋友说这个只提供给wifi或者vpn使用,隐隐中感觉还是有办法获取,只是没用对
(有兴趣的朋友可以再试试android.security.KeyStore中的方法,模拟empty返回的false,说明可以获取正确数值
但是有些方法需要参数key,试了很多依然没有成功)