在 Android 上通过 jni 将 byte[] 传递到 C 时出现问题

发布于 2024-11-29 07:01:53 字数 1218 浏览 1 评论 0原文

我在 Java 中有一个 byte[] ,它报告其长度为 256 个字节,我将其传递给 C 中的本机函数。

当我尝试从该数组中获取数据时,这是完全错误的,当我打印出来它与我在将其传递给 C 之前打印出来的数据不匹配。

我尝试了几种访问数据的方法,包括 GetByteArrayRegionGetByteArrayElements 但没有任何结果似乎给了我我期望的数据。

当我调查这个问题时,我尝试查看 JNI 认为 jbyteArray 的长度与 GetArrayLength 的关系 - 它报告的长度为 1079142960,远远超过我的 256 字节预期的。而且每次调用函数时该值都不同,例如另一次 GetArrayLength 返回 1079145720。

这是我用来访问数组的代码:

JNIEXPORT jbyteArray function(JNIEnv* env, jbyteArray array) {
    int length = (*env)->GetArrayLength(env, array);

    jbyte data[256];

    (*env)->GetByteArrayRegion(env, array, 0, 256, data);
    //also tried
    //jbyte *data = (jbyte*) (*env)->GetByteArrayElements(env, array, NULL);
}

这看起来很简单,所以我不是真的确定发生了什么事。该数组在 Java 中看起来很好,但它是在 C 中生成并传回的,所以我想那里可能出了问题,Java 不关心,但当它返回到 C 时会破坏数组。

这是我用来生成的代码数组并将其传回 Java:

//there is some openSSL stuff here that sets up a pointer to an RSA struct called keys that is size bytes large

jbyteArray result = (*env)->NewByteArray(env, size);

(*env)->SetByteArrayRegion(env, result, 0, size, (jbyte*)keys;

我错过了什么吗?

谢谢

I have a byte[] in Java which reports its length as 256 bytes which I pass to a native function in C.

When I tried to get the data out of this array it was completely wrong and when I printed it out it did not match the data I printed out right before I passed it to C.

I tried a few ways to access the data including both GetByteArrayRegion and GetByteArrayElements but nothing seems to give me the data I expect.

As I was investigating this I tried to look at what JNI believed the jbyteArray's length was with GetArrayLength - it reported the length as 1079142960, far more than the 256 bytes I expected. Also the value was different each time the function was called, for example another time GetArrayLength returned 1079145720.

Here is the code I am using to access the array:

JNIEXPORT jbyteArray function(JNIEnv* env, jbyteArray array) {
    int length = (*env)->GetArrayLength(env, array);

    jbyte data[256];

    (*env)->GetByteArrayRegion(env, array, 0, 256, data);
    //also tried
    //jbyte *data = (jbyte*) (*env)->GetByteArrayElements(env, array, NULL);
}

This seems pretty straight forward so I'm not really sure what is going on. The array seems fine from Java but it was generated in C and passed back so I suppose something might have gone wrong there that Java doesn't care about but breaks the array when it comes back to C.

Here is the code I used to generate the array and pass it back to Java:

//there is some openSSL stuff here that sets up a pointer to an RSA struct called keys that is size bytes large

jbyteArray result = (*env)->NewByteArray(env, size);

(*env)->SetByteArrayRegion(env, result, 0, size, (jbyte*)keys;

Am I missing something?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

吃素的狼 2024-12-06 07:01:53

此函数原型不正确:

JNIEXPORT jbyteArray function(JNIEnv* env, jbyteArray array)

第二个参数是 jclassjobject。如果您的方法是静态的,则应该是:

JNIEXPORT jbyteArray function(JNIEnv* env, jclass cls, jbyteArray array)

如果它不是静态的:

JNIEXPORT jbyteArray function(JNIEnv* env, jobject obj, jbyteArray array)

您将类或对象视为数组,这解释了您得到的意外结果。

This function prototype is incorrect:

JNIEXPORT jbyteArray function(JNIEnv* env, jbyteArray array)

The second argument is either a jclass or a jobject. If your method is static, it should be:

JNIEXPORT jbyteArray function(JNIEnv* env, jclass cls, jbyteArray array)

And if it's not static:

JNIEXPORT jbyteArray function(JNIEnv* env, jobject obj, jbyteArray array)

You are treating the class or object as an array, which explains the unexpected results that you get.

暖心男生 2024-12-06 07:01:53

我认为主要问题是您将 OpenSSL 结构强制转换为字节数组。随着时间的推移,这个结构很可能会被释放。这可以解释当您返回到 C 时向您报告的奇怪且不同的长度。向 Java 生成 RSA* 也不会对您有太大帮助 - Java 不了解该特定结构和d将无法识别它。

您应该尝试使用

  • i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, char *kstr, int klen, pem_password_cb *cb, void *u)
  • int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp 之一)

取决于您是否只想将公钥信息或私有信息传递给 Java (另请参阅此处)。这样您就可以确保从一开始就处理字节数组。

一旦这对您有用(使用您已经尝试过的技术),回到 Java 中您就可以将字节数组解析为有意义的内容。这在公钥情况下很简单:使用 X509EncodedKeySpec 与您的数组并使用 KeyFactory#generatePublic

私钥的情况稍微复杂一些。 Java 仅理解 PKCS#8 格式 而 OpenSSL 默认情况下根据 PKCS#1 格式对其 RSA 私钥进行编码。但您已经可以使用 i2d_PKCS8PrivateKey_bio 将密钥转换为 PKCS#8。不过,您需要首先将 RSA* 包装为 EVP_PKEY*

EVP_pkey *pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);

请勿加密您的密钥并使用 内存中 BIO,然后将生成的字节数组传递给 Java 并传递给构造函数PKCS8EncodedKeySpec 并最终使用 KeyFactory 生成您的私钥。

I assume the main problem is that you force an OpenSSL struct into a byte array. Most likely this struct will get freed over time. That would explain the weird and differing lengths being reported back to you when you return back to C. Yielding an RSA* to Java will also not help you very much - Java has no knowledge about that particular struct andd won't be able to recognize it.

What you should try is using one of

  • i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, char *kstr, int klen, pem_password_cb *cb, void *u)
  • int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp)

depending on whether you want to just pass the public key information or also the private information to Java (see also here). This way you can be sure to deal with a byte array right from the beginning.

Once this works for you (using the techniques you already tried), back in Java you can parse the byte array into something meaningful. This is straight-forward in the public key case: Use X509EncodedKeySpec with your array and generate a public key using KeyFactory#generatePublic.

Things are slightly more complicated in the private key case. Java only understands the PKCS#8 format whereas OpenSSL encodes its private RSA keys according to the PKCS#1 format by default. But you can already convert your key to PKCS#8 using i2d_PKCS8PrivateKey_bio. You need to wrap your RSA* as an EVP_PKEY* first, though:

EVP_pkey *pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);

Do not encrypt your key and use an in-memory BIO, then pass the resulting byte array over to Java and there to the constructor of PKCS8EncodedKeySpec and finally generate your private key with the KeyFactory.

黯淡〆 2024-12-06 07:01:53

尝试在字符串后附加“\0”字符。可能它无法识别字符串的结尾。

Try appending the string with '\0' character. Probably its not able to identify the end of string.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文