近两天要用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算法。