我正在尝试编写一个使用 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) 你调用env->ReleaseByteArrayElements(bytes, data, 0)
然后继续使用数据指针指向的内存的内容。此方法可能已释放其内存,可能会用内存管理信息覆盖其部分数据。这可能解释了为什么 CryptUnprotectedData()
失败了。您必须在 CryptUnprotectedData()
之后或复制数据后调用 env->ReleaseByteArrayElements()
。
2) 您在 inData.pbData 上调用 LocalFree()
。这是指向 env->GetByteArrayElements(bytes,NULL)
的指针,由 JNI API 管理。并且必须由 JNI API 发布(顺便说一句,您使用 ReleaseByteArrayElements
做得太早了)。
3) 您没有在 outData.pbData 上调用 LocalFree(),只有在使用 SetByteArrayRegion
否则,我对 Windows Crypto API 的了解还不够,无法确定您是否正确调用了它,但我认为它是正确的。
关于java - 使用 JNI 时 CryptUnprotectData 返回 false,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14668143/