java - 使用 JNI 时 CryptUnprotectData 返回 false

标签 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) 你调用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/

相关文章:

c++ - 使用 Ackermann 函数 C++ 进行内存

c++ - 如何用c语言翻译openssl命令pbkdf2?

c++ - 将结构数据类型传递给 C++ 中的命名管道

java - 使用 SAML 作为未加密 HTTP header 保护站点的桥梁

c++ - MSVC 编译器错误 C2688 : Microsoft C++ ABI corner case issue?

java - Kafka Avro 序列化器和反序列化器异常。 Avro 支持的类型

c++ - 为什么我的非所有者绘制的列表框在添加字符串后出现绘图问题?

c++ - 写入 C :\Program Files 中包含的文件夹的文件名

java - 在 .xml.scala 模板中将 Scala 字符串转换为 Xml

java - 在 Android 中的单独线程上使用循环器