使用JNI时,CryptUnprotectData返回false

时间:2013-02-03 00:27:37

标签: java c++ winapi java-native-interface

我正在尝试编写一个使用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。任何帮助/建议将不胜感激!

1 个答案:

答案 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的了解不足以确定您是否正确调用它,但它看起来对我来说。