thiru
thiru

Reputation: 13

How can I store values in Java parameters that are passed to JNI native C call

I am writing a program which does security modules such as encryption, signing, etc... I had written library in C which does the above mentioned functionality. Now I am calling this C native functions from java by using jni.

The problem I am facing is I am unable to store the result(signed data or encrypted data)into the parameters passed by java. I want to store the result in parameters which I receive. please help me. Thanks alot in advance.

The following are the API that I use in java to call native functions

sign("sign",byte[] file,int filelen,byte[] output,int outputlen)

In native C call I will perform the sign on "file" which is a buffer consists of input file contents and I want to store it to the output. How can I do it can anyone help me I did not found any related information.

Upvotes: 1

Views: 2836

Answers (2)

technomage
technomage

Reputation: 10069

The following code allows your native code to directly access the contents of both primitive byte array inputs.

JNIEXPORT void JNICALL Java_*mypackage*_sign(JNIEnv* env, jbytearray input, jint ilen, jbytearray output, jint olen) {
  char* pinput = (*env)->GetByteArrayElements(env, input, NULL);
  char* poutput = (*env)->GetByteArrayElements(env, output, NULL);

  sign(pinput, ilen, poutput, olen);

  (*env)->ReleaseByteArrayElements(env, input, pinput, 0);
  (*env)->ReleaseByteArrayElements(env, output, poutput, 0);
}

Depending on your performance considerations (i.e. if you want to ensure that you avoid copying the array data, or avoid concurrent access to the byte arrays), here is an example of using GetPrimitiveArrayCritical.

An NIO/direct buffer is only recommended if you need the buffer to be shared between native and Java code for longer than the duration of a single function call.

Upvotes: 0

tbroberg
tbroberg

Reputation: 635

Typically, native libraries are called with a direct ByteBuffer.

Interface is MyClass.submit(ByteBuffer source, ByteBuffer dest)

static jmethodID ByteBuffer_position;
static jmethodID ByteBuffer_limit;

// Find method id's for ByteBuffer methods.
JNIEXPORT jint JNICALL Java_MyClass_initAPI
    (JNIEnv *env, jclass thisj) {
  jint error = 0;

  ByteBuffer_position = (*env)->GetMethodID(env, byteBufferClass, "position", "()I");
  if (ByteBuffer_position == NULL) error = -1;
  ByteBuffer_limit = (*env)->GetMethodID(env, byteBufferClass, "limit", "()I");
  if (ByteBuffer_limit == NULL) error = -1;

  return error;
}

// Get ByteBuffer pointers and sizes and encrypt
// Expects source buffer's position to indicate end of source
// Expects dest buffer's limit to indicate max output length
JNIEXPORT jint JNICALL Java_MyClass_submit (JNIEnv *env, jobject thisj,
    jobject sourceBuffer, jobject destBuffer ) {
    jint error = 0;

    unsigned char* sourcePtr = (*env)->GetDirectBufferAddress(env, source);
    unsigned char* destPtr = (*env)->GetDirectBufferAddress(env, dest);
    jlong sourceLen = (*env)->CallIntMethod(env, source, ByteBuffer_position);
    jlong destLen = (*env)->CallIntMethod(env, dest, ByteBuffer_limit);

    // Encrypt sourcePtr --> destPtr

    return error;
}

This should be enough to get the idea across. It's paraphrased from working code, but untested in current form.

Upvotes: 1

Related Questions