我正在尝试编写一个使用WinAPI CryptprotectData和CryptUnprotectData函数的java应用程序。我试图通过使用java JNI来实现这一目标。这是我第一次使用JNI,我遇到了解密数据的问题。我在Visual Studio中调试了这个,发现对CryptUnprotectData的调用返回false并且函数返回NULL。我不知道为什么会这样做。
以下是代码:
JNIEXPORT jbyteArray JNICALL Java_Caller_Decrypt(JNIEnv * env, jobject obj, jbyteArray bytes)
{
int len = env->GetArrayLength(bytes);
jbyte * data = env->GetByteArrayElements(bytes,NULL);
env->ReleaseByteArrayElements(bytes, data, 0);
DATA_BLOB inData = {len, reinterpret_cast<unsigned char *>(data)};
DATA_BLOB outData = {0,NULL};
if(CryptUnprotectData(&inData,NULL,NULL,NULL,NULL,0,&outData))
{
LocalFree(inData.pbData);
jbyteArray buff= env->NewByteArray(len);
env->SetByteArrayRegion(buff,0,len,reinterpret_cast<jbyte *>(outData.pbData));
return buff;
}
else
{
return NULL;
}
}
这里是相关的java代码:
String password = "Password";
Caller c = new Caller();
System.out.println("Password");
byte[] buffer = c.Encrypt(password.getBytes());
System.out.println("Encrypted: " + new String(buffer));
System.out.println("Decrypted: " + new String(c.Decrypt(buffer)));
我不知道为什么CryptUnprotectData函数返回false。自从我使用c ++并迷上java以来已经过去了大约一年,所以我有点生疏,所以我可能会错过一些东西,但我想知道我是否只是错过了一步,因为这是我第一次使用JNI。任何帮助/建议将不胜感激!
答案 0 :(得分:2)
此程序中存在几个大的内存管理错误。
1)您调用env->ReleaseByteArrayElements(bytes, data, 0)
然后继续使用数据指针指向的内存内容。此方法可能已释放其内存,可能会使用内存管理信息覆盖其部分数据。这可能解释了为什么CryptUnprotectedData()
失败了。您必须在env->ReleaseByteArrayElements()
之后或在复制完数据后致电CryptUnprotectedData()
。
2)你在inData.pbData上调用LocalFree()
。这是指向env->GetByteArrayElements(bytes,NULL)
的指针,由JNI API管理。并且必须由JNI API发布(使用ReleaseByteArrayElements
BTW,您很快就会发布)。
3)您没有在outData.pbData上调用LocalFree(),只有在使用SetByteArrayRegion
另外,我对Windows Crypto API的了解不足以确定您是否正确调用它,但它看起来对我来说。