Проблема передачи байта [] через jni в C на Android - PullRequest
8 голосов
/ 13 августа 2011

У меня есть byte[] в Java, который сообщает его длину в 256 байтов, которую я передаю нативной функции в C.

Когда я пытался вытащить данные из этого массива, это было совершенно неправильно, и когда я их распечатывал, они не соответствовали данным, которые я распечатал, перед тем как передать их в C.

Я пробовал несколько способов получить доступ к данным, включая GetByteArrayRegion и GetByteArrayElements, но, похоже, ничто не дает мне ожидаемых данных.

Когда я исследовал это, я попытался выяснить, что, по мнению 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;

Я что-то упустил?

Спасибо

Ответы [ 3 ]

12 голосов
/ 13 августа 2011

Этот прототип функции неверен:

JNIEXPORT jbyteArray function(JNIEnv* env, jbyteArray array)

Второй аргумент - либо jclass, либо jobject.Если ваш метод статический, он должен быть:

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

А если он не статический:

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

Вы рассматриваете класс или объект как массив, который объясняет неожиданные результатычто вы получаете.

1 голос
/ 13 августа 2011

Я полагаю, что основная проблема заключается в том, что вы заставляете структуру OpenSSL в байтовый массив. Скорее всего, эта структура будет освобождена с течением времени. Это объяснило бы странную и различную длину, о которой вам сообщают, когда вы вернетесь обратно в C. Возвращение RSA* в Java также не очень вам поможет - Java не знает об этой конкретной структуре и не сможет признать это.

То, что вы должны попробовать, это использовать один из

  • 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, беззнаковый символ ** pp)

в зависимости от того, хотите ли вы просто передать информацию открытого ключа или личную информацию в Java ( см. Также здесь ). Таким образом, вы можете быть уверены, что имеете дело с байтовым массивом с самого начала.

Как только это сработает для вас (используя методы, которые вы уже попробовали), вернувшись в Java, вы сможете разобрать массив байтов во что-то осмысленное. Это просто в случае с открытым ключом: используйте X509EncodedKeySpec с вашим массивом и сгенерируйте открытый ключ, используя KeyFactory # generatePublic .

В случае с секретным ключом все немного сложнее. Java понимает только формат PKCS # 8 , тогда как OpenSSL по умолчанию кодирует свои частные ключи RSA в соответствии с форматом PKCS # 1. Но вы уже можете преобразовать свой ключ в PKCS # 8, используя i2d_PKCS8PrivateKey_bio . Вам нужно сначала обернуть RSA* как EVP_PKEY*, хотя:

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

Не шифруйте свой ключ и не используйте в памяти BIO, затем передайте полученный байтовый массив в Java и там конструктору PKCS8EncodedKeySpec и, наконец, сгенерируйте свой закрытый ключ с помощью KeyFactory.

0 голосов
/ 13 августа 2011

Попробуйте добавить строку с символом '\ 0'. Вероятно, он не может определить конец строки.

...