最近课程作业完成MD5加密的DLL编写,并使用Java调用DLL,中间遇到几个坑与君共勉。
一、C++编写MD5加密DLL
//定义外部调用宏
#ifdef MD5_DLL
#else
#define MD5_DLL extern "C" _declspec(dllexport) //指的是允许将其给外部调用
#endif
//声明接口,内容暂不展示
MD5_DLL void MD5(unsigned char* input, unsigned char* output);
二、JNA包下载
java native interface JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架,比JNI更好用,JNI偏底层,JNA更友好。
JNA下载地址:https://github.com/java-native-access/jna
找到Download下载第一个就OK
三、DLL转换
以eclipse为例,右键项目->Properties->Java Build Path->Libraries->Add External JARs 选择JNA
1、编写charReference类,该类继承com.sun.jna.ptr.ByReference类,该类主要负责Java数据类型到C++中char *类型对应
import com.sun.jna.ptr.ByReference;
public class charReference extends ByReference{
public charReference() {
this((byte)0);//无
}
public charReference(byte value) {
super(1000);
this.setValue(value);
}
public void setValue(byte value) {
this.getPointer().setByte(0L, value);
}
public byte getValue() {
return this.getPointer().getByte(0L);
}
public void Init(String input) {
for(int i=0;i<input.length();i++) {
this.getPointer().setChar((long)i, input.charAt(i));//字符串初始化
}
}
public void Init(byte[] bytes) {
for(int i=0;i<bytes.length;i++) {
this.getPointer().setByte((long)i, bytes[i]);//字节数组初始化
}
}
}
因为char可能是中文汉字,中文汉字占两个字节,在setChar时并不会将两个字节都传到对象中,所以有中文时需要先将字符串转化成字节数组再传。
2、声明接口
import com.sun.jna.*;
import com.sun.jna.ptr.PointerByReference;
import tools.charReference;
public interface PORT extends Library{
PORT INSTANTCE=(PORT)Native.loadLibrary("MD5",PORT.class);//MD5为DLL文件名
public void MD5(charReference input,charReference output);
}
将DLL文件放在项目bin文件夹下
3、MD5的JAVA实现
import java.io.UnsupportedEncodingException;
import com.sun.jna.*;
import com.sun.jna.ptr.PointerByReference;
import tools.byteToString;
import tools.PORT;
import tools.charReference;
public class MD5Encoder {
//获得byte数组
private static byte[] getBytes(String input) throws UnsupportedEncodingException {
int byteLen=0;
byte[] bytes=new byte[3*input.length()];
for(int i=0;i<input.length();i++) {
char now=input.charAt(i);
byte[] nowCharBytes=null;
if(isChinese(now)) {
nowCharBytes=(""+now).getBytes("utf-8");
}else {
nowCharBytes=(""+now).getBytes();
}
for(int j=0;j<nowCharBytes.length;j++) {
bytes[byteLen++]=nowCharBytes[j];
}
}
return bytes;
}
//判断是否为中文
private static final boolean isChinese(char c) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
return true;
}
return false;
}
//加密
public static String encoder(String inputString) throws UnsupportedEncodingException {
charReference output=new charReference();
charReference input=new charReference();
input.Init(getBytes(inputString));
PORT.INSTANTCE.MD5(input, output);
String outputString="";
for(int i =0;i<16;i++) {
outputString=outputString+byteToString.bytesToHexString(output.getPointer().getByte(i));
}
return outputString;
}
//测试
public static void main(String[] args) throws UnsupportedEncodingException {
charReference output=new charReference();
charReference input=new charReference();
String x="zx哈哈";
input.Init(getBytes(x));
PORT.INSTANTCE.MD5(input, output);
String outputString="";
for(int i =0;i<16;i++) {
outputString=outputString+byteToString.bytesToHexString(output.getPointer().getByte(i));
}
System.out.println(outputString);
}
}
byteToString.byteToHexString为另一个类中的字节数组转化成字符串的函数
public static String bytesToHexString(byte src) {
int v = src & 0xFF;
String hv = Integer.toHexString(v);
if(hv.length()==1) {
return "0"+hv;
}
return hv;
}
运行结果:
与某网站(https://md5jiami.51240.com/)加密结果相同