你如何转换byte [] - > uint8_t []没有创建JNI问题?

时间:2017-11-20 21:45:12

标签: java c++ c type-conversion java-native-interface

我遇到了一些麻烦。我正在尝试调用基于C的加密库并从Java代码中提供byte[]。它只有在我将Java签名更改为int[]时才有效。是什么给了什么?

我试图调用的实际C库函数是:

ecc_verify(const uint8_t p_publicKey[32], const uint8_t p_hash[32], const uint8_t p_signature[32*2]

我在Java中的JNI类有这个:

public native static boolean jni_verify(byte[] publicKey, byte[] data, byte[] signature);

这导致此头文件签名:

JNIEXPORT jboolean JNICALL Java_com_something_eccjni_EccJniExport_jni_1verify (JNIEnv *, jclass, jbyteArray, jbyteArray, jbyteArray);

我的C实现是:

JNIEXPORT jboolean JNICALL Java_com_something_eccjni_EccJniExport_ecdsa_1verify
(JNIEnv *jniEnv, jclass clazz, jbyteArray publicKeyArray, jbyteArray dataArray, jbyteArray signatureArray){
    jboolean isCopy;

    jbyte* publicKey = (*jniEnv)->GetByteArrayElements(jniEnv, publicKeyArray, &isCopy);
    jbyte* data = (*jniEnv)->GetByteArrayElements(jniEnv, dataArray, &isCopy);
    jbyte* signature = (*jniEnv)->GetByteArrayElements(jniEnv, signatureArray, &isCopy);

    int result = ecdsa_verify((uint8_t *) publicKey,(uint8_t *) data,(uint8_t *) signature);

    (*jniEnv)->ReleaseByteArrayElements(jniEnv, publicKeyArray, publicKey, JNI_ABORT);
    (*jniEnv)->ReleaseByteArrayElements(jniEnv, dataArray, data, JNI_ABORT);
    (*jniEnv)->ReleaseByteArrayElements(jniEnv, signatureArray, signature, JNI_ABORT);

    return result;
}

从不有效。这通常会产生一条消息:

java(9966,0x7000012c8000) malloc: *** error for object 0x7fb7a0614758: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug

但是,如果我将所有内容更改为此内容,则可以:

public native static boolean ecdsa_verify(int[] publicKey, int[] data, int[] signature);

JNIEXPORT jboolean JNICALL Java_com_something_eccjni_EccJniExport_ecdsa_1verify (JNIEnv *, jclass, jintArray, jintArray, jintArray);

JNIEXPORT jboolean JNICALL Java_com_something_eccjni_EccJniExport_ecdsa_1verify
(JNIEnv *jniEnv, jclass clazz, jintArray publicKeyArray, jintArray dataArray, jintArray signatureArray){
    jboolean isCopy;

    jint* publicKey = (*jniEnv)->GetIntArrayElements(jniEnv, publicKeyArray, &isCopy);
    jint* data = (*jniEnv)->GetIntArrayElements(jniEnv, dataArray, &isCopy);
    jint* signature = (*jniEnv)->GetIntArrayElements(jniEnv, signatureArray, &isCopy);

    int result = ecdsa_verify((uint8_t *) publicKey,(uint8_t *) data,(uint8_t *) signature);

    (*jniEnv)->ReleaseIntArrayElements(jniEnv, publicKeyArray, publicKey, JNI_ABORT);
    (*jniEnv)->ReleaseIntArrayElements(jniEnv, dataArray, data, JNI_ABORT);
    (*jniEnv)->ReleaseIntArrayElements(jniEnv, signatureArray, signature, JNI_ABORT);

    return result;
}

发生了什么事?

修改

这是Calling Java:

    System.load(EccJni.class.getResource("/EccJniExport.jnilib").getFile());
    byte[] publicKey = new byte[32];
    byte[] privateKey = new byte[32];
    EccJniExport.ecc_make_key(publicKey, privateKey);

    byte[] data = new byte[32];
    for (int i = 0; i < data.length; i++) {
        data[i] = (byte) i;
    }
    byte[] signature = new byte[32];
    EccJniExport.ecdsa_sign(privateKey, data, signature);

    System.out.println("result:" + EccJniExport.ecdsa_verify(publicKey, data, signature));

同样,如果您将byte[]更改为int[],那么一切都会有效的

1 个答案:

答案 0 :(得分:3)

您没有为signature数组分配足够的字节。

C函数需要32*2个字节用于该参数,但您的Java代码正在分配32个字节。

这解释了当您使用int[]数组而不是byte[]数组时代码的工作原理。在这种情况下,您将分配32*4个字节。