Java 方法调用为相同参数提供不一致的结果

Java 方法调用为相同参数提供不一致的结果,java,java-native-interface,libsodium,Java,Java Native Interface,Libsodium,blake2b散列是一种函数方法,我得到了不一致的结果。在我看来,问题在于java端,它以某种方式对两个方法调用之间的输入参数执行更改。我不明白两次调用SodiumJNI.crypto_generichash_blake2b_salt_personal_no_input之间的输入参数是怎么回事。本机函数(如下所示)不会对键、盐和信息执行任何更改。因此,输出应该是相同的,但事实并非如此 我的测试方法如下所示: import android.util.Base64; import android

blake2b散列是一种函数方法,我得到了不一致的结果。在我看来,问题在于java端,它以某种方式对两个方法调用之间的输入参数执行更改。我不明白两次调用SodiumJNI.crypto_generichash_blake2b_salt_personal_no_input之间的输入参数是怎么回事。本机函数(如下所示)不会对
信息
执行任何更改。因此,输出应该是相同的,但事实并非如此

我的测试方法如下所示:

 import android.util.Base64;
 import android.util.Log;

 static void kdf() {
        final byte[] key = new byte[32];
        final byte[] salt = new byte[32];
        final byte[] info = Base64.decode("aGFuZHNoYWtl", Base64.DEFAULT);

        byte[] out0 = new byte[64];
        int result0 = SodiumJNI.crypto_generichash_blake2b_salt_personal_no_input(out0, out0.length, key, key.length, salt, info);
        if (result0 == 0) {
            Log.d("Tests", "out0: " + Base64.encodeToString(out0, Base64.DEFAULT));
            //prints:
            //out0: nCzeDcbw1YmdPq+jYnslNDoXKNyXMvIsqx9QJ1PLRNPxh7dvXkTeSkF2REYznHExaWCQP7J0kFvDu9l9ECs4VQ==
        }

        byte[] out1 = new byte[64];
        int result1 = SodiumJNI.crypto_generichash_blake2b_salt_personal_no_input(out1, out1.length, key, key.length, salt, info);
        if (result1 == 0) {
            Log.d("Tests", "out1: " + Base64.encodeToString(out1, Base64.DEFAULT));
             //prints;
             //out1: dNfj+ccfGzTDiTAgzHNE5Hujyxnl6yX2BAPamCBw8X3fPYgbdtNDPoA3JKQGCziJw40wVTr/kPCpVUqMqMiVKw==
        }
    }
奇怪的是,
out0
out1
并不相同

本机函数实现如下所示:

public class SodiumJNI {

    public final static native int sodium_init();
    public final static native int crypto_generichash_blake2b_salt_personal_no_input(byte[] out, int outlen, byte [] key, int keylen, byte[] salt, byte[] personal);

    static {
        try {
            System.loadLibrary("sodiumjni");
            if (sodium_init() == -1) {
                throw new RuntimeException("Sodium could not be initialized.");
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);


        }
    }
}
以及本机函数:

JNIEXPORT jint JNICALL Java_com_app_jni_SodiumJNI_crypto_1generichash_1blake2b_1salt_1personal_1no_1input(JNIEnv *jenv, jclass jcls,
  jbyteArray joutput, jint joutlength, jbyteArray jkey, jint jkeylength, jbyteArray jsalt, jbyteArray jpersonal) {
  jint jresult = 0 ;
  unsigned char *output = (unsigned char *) 0 ;
  size_t outlength ;
  unsigned char *key = (unsigned char *) 0 ;
  size_t keylength ;
  unsigned char *salt = (unsigned char *) 0 ;
  unsigned char *personal = (unsigned char *) 0 ;
  int result;

  (void)jenv;
  (void)jcls;
  {
    output = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, joutput, 0);
  }
  outlength = (size_t)joutlength;
  {
    key = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, jkey, 0);
  }
  keylength = (size_t)jkeylength;
  {
    salt = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, jsalt, 0);
  }
  {
    personal = (unsigned char *) (*jenv)->GetByteArrayElements(jenv, jpersonal, 0);
  }

  result = (int)crypto_generichash_blake2b_salt_personal(output,
      outlength,
      NULL,
      0,
      (unsigned char const *)key,
      keylength,
      (unsigned char const *)salt,
      (unsigned char const *)personal);
  jresult = (jint)result;
  {
    (*jenv)->ReleaseByteArrayElements(jenv, joutput, (jbyte *) output, 0);
  }
  {
    (*jenv)->ReleaseByteArrayElements(jenv, jkey, (jbyte *) key, JNI_ABORT);
  }
  {
    (*jenv)->ReleaseByteArrayElements(jenv, jsalt, (jbyte *) salt, JNI_ABORT);
  }
  {
    (*jenv)->ReleaseByteArrayElements(jenv, jpersonal, (jbyte *) personal, JNI_ABORT);
  }
  return jresult;
}

好。。。out0和out1指向不同的内存位置。因此,您会得到不同的结果。日志不会打印位置,而是打印内容。
GetByteArrayElements
可以返回副本,但不能保证返回副本。它很可能返回指向实际数据的指针。请详细说明。你看到c数组在哪里被释放,在哪里被实例化,或者在哪里被传递到libke2b方法了吗?我的观点是,你似乎认为
GetByteArrayElements
返回一个数据副本,你可以在不改变相应Java数组的情况下修改它。但是,无法保证您得到的是副本,因此您可能必须自己创建副本。
GetByteArrayElements
的最后一个参数可用于确定这一点(即
jboolean*isCopy
)。