在上篇"java调用vc6写的dll - 关于jni应用中的字符串参数传递"中,接收到字符串后再解密时,有时候不能将密文完全复原成明文.经过一轮加密和解密后,得到的明文和原始明文长度不一致,且后半段为乱码.经过检查并核实,基本找到了该问题的成因.这些问题是由错误的字符串处理方法造成的.
第一个细节,在c里面,strlen, strcpy和strcmp等函数,都是基于字符串处理的.系统判断字符串的依据是结束字符"/0".只要遇到"/0",就认为一个字符串结束.第二个细节,ascii码范围是0-255,通常字符串使用的都是可显示字符,其ascii码范围在0-127之间.( /0是结束字符, /127是del),而128-255之间的符号,则被显示为乱码.第三个细节,由编码为1-126的字符组成的字符串,经过DES加密后,生成的字符串里,其字符编码从0到255不一,可能包含多个"/0"字符.
至此真相大白.即我们不能简单的用strlen和strcpy等字符串函数,来处理加密后的字符串.因为这些函数一碰到结束字符"/0",就停止处理,而实际上,"/0"后面可能还有一堆字符没有被囊括进来.如何解决这个问题?可以使用字符指针(char *)配合自加(++)或者自减(--)运算符,来复制和传递加密后的字符串,然后针对字符指针进行我们需要的操作.
容易被忽视的语法:
char b=0; //b表示结束字符"/0"。
strlen()函数得到的是包括了“/0”的长度。
strcpy()函数复制的时候,连源字符串里的“/0”一起复制。
VC(DLL)范例代码:
-------------------------------------------------------------------------------------------------------
// 加密函数
JNIEXPORT jbyteArray JNICALL Java_DESInvokeLib_encrypt
(JNIEnv *jniEnv, jclass, jint length, jbyteArray jarrByte, jint lengthK, jbyteArray jarrByteK)
{
///获取明文
jbyte* pJbyte = jniEnv->GetByteArrayElements(jarrByte, 0);
char* szByte = (char *)pJbyte;
long datalen = length; // 从参数中获得明文长度
char *buf = new char[datalen +1];
for (int j =0;j< datalen;j++) buf[j] = szByte[j];
buf[datalen] = '/0'; // 强制加上结束标志,以防传输产生的乱码
///获取key
jbyte* pJbyteK = jniEnv->GetByteArrayElements(jarrByteK, 0);
char* szByteK = (char *)pJbyteK;
int datalenK = lengthK;
char bufK[255];
memset(bufK,0,255);
for (int k =0;k< datalenK;k++) bufK[k] = szByteK[k];
///加密
CDes myDes;
myDes.Des_Go( buf, buf, datalen, bufK, datalenK, ENCRYPT );
///返回密文
int newdatalen =(datalen+7)&0xfffffff8;
jbyteArray jarrRet = jniEnv->NewByteArray( newdatalen );
jniEnv->SetByteArrayRegion( jarrRet, 0, newdatalen, (jbyte *)buf );
return jarrRet;
}
//解密函数
JNIEXPORT jbyteArray JNICALL Java_DESInvokeLib_decrypt
(JNIEnv *jniEnv, jclass, jint length, jbyteArray jarrByte, jint lengthK, jbyteArray jarrByteK)
{
///获取密文
jbyte* pJbyte = jniEnv->GetByteArrayElements(jarrByte, 0);
char* szByte = (char *)pJbyte;
long datalen = length;
char *buf = new char[datalen +1];
for (int j =0;j< datalen;j++) buf[j] = szByte[j];
buf[datalen] = '/0';
///获取key
jbyte* pJbyteK = jniEnv->GetByteArrayElements(jarrByteK, 0);
char* szByteK = (char *)pJbyteK;
int datalenK = lengthK;
char bufK[255];
memset(bufK,0,255);
for (int k =0;k< datalenK;k++) bufK[k] = szByteK[k];
///解密
CDes myDes;
myDes.Des_Go( buf, buf, datalen, bufK, datalenK, DECRYPT );
///返回明文
jbyteArray jarrRet = jniEnv->NewByteArray( strlen(buf) );
jniEnv->SetByteArrayRegion( jarrRet, 0, strlen(buf), (jbyte *)buf );
return jarrRet;
}
ps: 由于jni在vc与java程序间传输,可能会产生乱码,因此java调用dll时将明文长度做参数传递给dll,同时,dll收到字符串并做(char *)处理后,在结尾后"/0"强制结束字符串.
-------------------------------------------------------------------------------------------------------
原"java调用vc6写的dll - 关于jni应用中的字符串参数传递"地址:
http://blog.csdn.net/vinchwang/archive/2007/04/25/1584384.aspx