JNI试用记
近两天要用JIN做数据加密系统,所以特别写了这篇。省得以后忘记,顺便造福大家。
下面是核心编码:
//CTX.java
public abstract class CTX {
protected byte[] state = new byte[20];
protected long count;
protected byte[] buffer = new byte[0]; /* input buffer */
protected byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0 };
// 大端点序
protected static void putChar(byte[] b, int off, char val) ;
// 大端点序
protected static void putLong(byte[] b, int off, long val) ;
static {
System.loadLibrary(“cryptogram_jni”);
}
public CTX();
public void Update(String str);
public void Update(char[] input) ;
public void Update(byte[] input);
public void Update(byte[] input, int length) ;
public byte[] Final() ;
public String GetHash() ;
protected abstract void init();
protected abstract void Transform();
}
//MD5_CTX.java
public class MD5_CTX extends CTX {
protected native void init();
protected native void Transform();
}
然后导出h文件,在工程目录下执行这个。记得要先编译过代码,否则会说找不到。
javah -jni com.XXX.MD5_CTX
如果要看Signature的话执行这个。同样需要先编译代码。
javap -s -p com.XXX.MD5_CTX
把.h复制到c的工程目录,然后变换一下。
extern “C”
JNIEXPORT
void
JNICALL
Java_com_anhorn_cryptogram_MD5_1CTX_init(
JNIEnv *env,
jobject obj
){
JavaCTX jctx(env, obj);
jctx.jl_count=0;
jctx.pd_state[0] = 0x67452301L;
jctx.pd_state[1] = 0xefcdab89L;
jctx.pd_state[2] = 0x98badcfeL;
jctx.pd_state[3] = 0x10325476L;
return ;
}
如果按照原来的数据,马上会出现导出函数变成乱码的乌龙场景。其中JavaCTX的定义是这样的。
class JavaClass{
public:
JavaClass(JNIEnv *env, jobject obj){
this->env=env;
this->obj=obj;
this->cls=env->GetObjectClass(obj);
}
protected:
JNIEnv *env;
jobject obj;
jclass cls;
};
class JavaCTX : public JavaClass{
public:
JavaCTX(JNIEnv *env, jobject obj);
~JavaCTX();
protected:
jbyteArray jba_state;
jbyteArray jba_buffer;
jfieldID jfid_count;
public:
jsize js_state_size;
PDWORD pd_state;
jlong jl_count;
jsize js_buffer_size;
PBYTE pb_buffer;
};
JavaCTX::JavaCTX(JNIEnv *env, jobject obj):JavaClass(env, obj){
jfieldID jfid_state, jfid_buffer;
cls=env->GetSuperclass(cls);
jfid_state=env->GetFieldID(cls, “state”, “[B”);
jba_state=(jbyteArray)env->GetObjectField(obj, jfid_state);
js_state_size=env->GetArrayLength(jba_state);
pd_state=(PDWORD)env->GetByteArrayElements(jba_state, JNI_FALSE);
jfid_count=env->GetFieldID(cls, “count”, “J”);
jl_count=env->GetLongField(obj, jfid_count);
jfid_buffer=env->GetFieldID(cls, “buffer”, “[B”);
jba_buffer=(jbyteArray)env->GetObjectField(obj, jfid_buffer);
js_buffer_size=env->GetArrayLength(jba_buffer);
pb_buffer=(PBYTE)env->GetByteArrayElements(jba_buffer,
JNI_FALSE);
return ;
}
JavaCTX::~JavaCTX(){
env->ReleaseByteArrayElements(jba_buffer,
(jbyte*)pb_buffer, JNI_COMMIT);
env->SetLongField(obj, jfid_count, jl_count);
env->ReleaseByteArrayElements(jba_state,
(jbyte*)pd_state, JNI_COMMIT);
}
这样就将Java中的一个特定对象在C++里面读了出来,然后下面大家都知道了。关键的native void Transform();在C++中的实现是Java_com_anhorn_cryptogram_MD5_1CTX_Transform。这个调用了MD5_CTX_Transform, which是我做的一个MD5算法。