NDK+OpenSSl,通过JNI技术开发so加密库
来源:互联网 发布:北京通州淘宝城 编辑:程序博客网 时间:2024/06/05 15:07
以下是个人在做加密算法库时一些经验总结,今天把它写下来分享给大家,希望对大家以后再做类似的开发工作时能有所帮助,少走些弯路。
主要从以下5个方面进行阐述:
1. Openssl安装,1.0.1与1.0.2使用时的区别
2. Linux下gcc的使用方法,及可能遇到的问题
3. JNI开发,开发流程
4. NDK使用方法,以及打包so库时如何编写Application.mk文件
5.IOS打包基于openssl库的静态库时需注意那些
一. Openssl安装,1.0.1与1.0.2使用时的区别
参考网上的教程:
① 到openssl官网下载openssl包openssl-1.0.1e.tar.gz
② 使用tar命令将其解压到/usr/local/src下
③ Cd进入openssl-1.0.1e目录下,执行
./config --prefix=/usr/local --openssldir=/usr/local/ssl
make && make install
./config shared --prefix=/usr/local --openssldir=/usr/local/ssl
make clean
make && make install
以上方法是我从网上copy下来的,若自己的机器上没有openssl,可以参考安装。
查看自己机器上是否已经安装openssl的方法,执行openssl version,若有版本信息则已安装,否则未安装。
在使用Openssl库开发时,需要注意1.0.1和1.0.2中有些方法的参数是不同的。例如1.0.1的bio.h中有个方法BIO *BIO_new_mem_buf(void *buf, int len),而其在1.0.2中则是BIO *BIO_new_mem_buf(const void *buf, int len)。所以在打包时要注意,开发环境和打包环境中的库是不是同一个版本,若不是需要在调用某些方法时稍作改动,一般使用指针类型强转下就可以解决。
二. Linux下gcc的使用方法,及可能遇到的问题
gcc主要是用来编译.c文件,编译.cpp文件可以使用g++。先介绍下一般会用到的几个命令参数:
-o指定输出文件名
-c只编译不连接
-g产生供gdb调试用的可执行文件
-l链接库,后跟库名,linux下的库名一般是lib+库名+.so形式
-L指定连接库路径
-I指定include文件路径
-fPIC在编译阶段使用,告诉编译器产生与位置无关代码,一般在编译动态共享库用到。
-shared设置共享,一般是在编译动态共享库时会用到。
用例:hello.c
编译成可执行文件:gcc hello.c –o main,这要求hello.c中必须有int main()函数的实现。
编译生成中间文件:gcc hello.c -o hello.o,hello.c中不需要有main函数的实现,生成的.o文件可以用于编译动态库或者是静态库。
gcc编译基于openssl开发的.c文件时,可能会遇到的问题
① 在编译的阶段提示找不到openssl/aes.h头文件
原因:openssl的include文件未加入系统路径,导致gcc在编译时搜索不到
解决方法:先找到openssl文件夹路径,一般是在/usr/include/下,在编译时使用-I命令指定路径-I/usr/include/openssl即可。
② 在生成动态库时提示文件中使用的openssl库中方法undefined
原因:在生成动态库时,未指定依赖的第三方库
解决方法:-lssl即可,若是还需要依赖自己的其他库,还需要使用-L命令指定自己的库路径。
三. JNI开发,以及开发流程
JNI开发流程主要如下:
① 编写java文件,申明native方法,例如helloworld.java
public class helloworld{
public native void say();
static {
System.loadLibrary("hello");
}
public static void main(String[] args){
new helloworld().say();
}
}
② javac helloworld.java生成helloworld.class文件
③ javah helloworld生成helloworld.h文件
④ 编写hello.c文件,#include“helloworld.h”,实现文件中的方法
⑤ 生成编译文件gcc -fPIC -g -c hello.c -o libhello.o
⑥ 生成共享库gcc -shared libhello.o -o libhello.so
⑦ java hellworld
可能存在的问题:
(1) 在第⑤步可能会报找不到jni.h文件
原因: jni.h文件为加入到系统路径中,gcc在编译时找不到jni.h文件
解决方法:-I/opt/soft/java/include –l/opt/soft/java/include/linux。不同系统路径不一样,这是我的系统路径。
(2) 在第⑦步会报找不到hello库
原因:生成的共享库未加入到系统路径中
解决方法:export LD_LIBRARY_PATH=第⑥步生成的共享库路径
(3) 第④步可能会生成不成功
原因:在.java中有package语句,这会导致在本路径下生成.h不成功
解决方法:可以手动书写.java对应的.h文件,书写规则如下:
(a) 样版
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class hello */
#ifndef _Included_com_test_demo_hello
#define _Included_com_test_demo_hello
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_test_demo_hello
* Method: say
* Signature: (Landroid/content/Context;)V
*/
JNIEXPORT void JNICALL Java_ com_test_demo_hello_say
(JNIEnv *, jclass, jobject);
#ifdef __cplusplus
}
#endif
#endif
(b) 其中红色表示的是该类的全路径名,浅蓝色表示的是类的方法,紫色表示的是jni环境指针,橙色表示的是该类对象(若是静态方法,则是jclass,若是非静态方法则是jobject),浅绿色是方法的参数。
(c) JNI中类型对照表:JNI类型——》JAVA类型
V
void
void
N/A
Z
jboolean
boolean
8 unsigned
I
jint
int
32
J
jlong
long
64
D
jdouble
double
64
F
jfloat
float
32
B
jbyte
byte
8
C
jchar
char
16 unsigned
S
jshort
short
16
[I
jintArray
int[]
[F
jfloatArray
float[]
[B
jbyteArray
byte[]
[C
jcharArray
char[]
[S
jshortArray
short[]
[D
jdoubleArray
double[]
[J
jlongArray
long[]
[Z
jbooleanArray
Boolean[]
jchar -> jstring
jstring result = env->NewString(jchar *, jsize); 直接将jchar转换为jstring(Java String)可直接由JNI返回给Java使用。
jcharArray -> jchar*
jchar * jc = (*env)->GetCharArrayElements(env,jcharArray,0);
jbyteArray -> jbyte
jbyte * jby = (*env)->GetByteArrayElements(env,jbyteArray,0);
注意jchar并不能强转成c中的char,只有jbyte才与c中的char对应。
(d) JNI中一些常用的方法:
GetStringUTFChars将jstring转换成为UTF-8格式的char*
GetStringChars将jstring转换成为Unicode格式的char*
ReleaseStringUTFChars释放指向UTF-8格式的char*的指针
ReleaseStringChars释放指向Unicode格式的char*的指针
NewStringUTF创建一个UTF-8格式的String对象
NewString创建一个Unicode格式的String对象
GetStringUTFLengt获取UTF-8格式的char*的长度
GetStringLength获取Unicode格式的char*的长度
jsize len = (*env)->GetArrayLength(env, arr);
释放对象指针:
ReleaseBooleanArrayElements
ReleaseByteArrayElements
ReleaseCharArrayElements
ReleaseShortArrayElements
ReleaseIntArrayElements
ReleaseLongArrayElements
ReleaseFloatArrayElements
ReleaseDoubleArrayElements
四. NDK使用方法,以及打包so库时如何编写Application.mk
① NDK是android提供的用于编译c程序的编译器,按装很简单,从官网上下载下来,解压到自己的目录中,然后设置文件权限为777,最后编辑/etc/profile文件,在文件尾添加NDK=/ndk解压路径
export PATH=$NDK:$PATH,然后保存,执行source /etc/profile,然后执行echo $NDK若输出不为空,则配置成功。
② cd到自己的jni项目路径下,执行$NDK/ndk-build即可。注意你的.c文件的父目录一定要是jni,即/…/jni/hello.c,生成的.o文件是在../obj/目录下,生成的库文件是在../libs/目录下。
NDK编译生成库文件的主要难点是编写Application.mk文件,下面给出一个链接,供大家学习:http://www.cnblogs.com/leaven/archive/2011/01/25/1944688.html
五. IOS打包基于openssl库的静态库时需注意那些
最好不要使用内存分配,即不要使用malloc,limux下使用malloc分配内存后会使用delete或者free释放内存,但是移植到ios下后会出现内存释放异常情况,不兼容,建议改成在栈空间上分配,或者使用Object C去实现。若本地没有openssl可以通过以下方式导入pod search openssl 或者 pod 引入 git@github.com:openssl/openssl.git
- NDK+OpenSSl,通过JNI技术开发so加密库
- 通过 JNI 调用 OpenSSL 实现加密解密
- [JNI学习]----NDK生成so库
- 开发so动态库模版(NDK、JNI)
- android ndk jni so库生成
- JNI NDK SO DLL
- NDK 生成 .so ,jni 调用
- Ndk(jni)调用第三方的so库
- JNI入门,使用NDK编写自己的SO库
- JNI-NDK编程,so如何支持X86?
- Android studio NDK-JNI 编译so文件
- Android NDK、cygwin安装及通过示例导出so库
- Android studio通过JNI调用动态链接库SO
- android通过Jni加载so库遇到UnsatisfiedLinkError问题!!!
- NDK编译第三方库,通过JNI调用。
- android(NDK+JNI)---NDK编译生成so文件
- Android 使用NDK-build生成so文件 C++ JNI NDK
- NDK编译.so库
- mssql查询某字段的值为空的语句
- 说一说开源许可协议
- Android手机修改分辨率
- 9 MATLAB参数估计与假设检验-核密度估计
- 理解VAO与VBO的关系
- NDK+OpenSSl,通过JNI技术开发so加密库
- Ubuntu备份与还原
- Thrift 封装
- 声学模型训练-嵌入式训练
- 【转载】线性相位滤波器
- 解决在硬件加速下WebView切换闪屏的问题
- linux或windows部署多个项目不同端口号
- 搬家
- 基于LBS的地理位置附近的搜索以及由近及远的排序(MYSQL)