【问题标题】:AES/CBC/PKCS5Padding different results in JAVA and JNIAES/CBC/PKCS5Padding 在 JAVA 和 JNI 中的不同结果
【发布时间】:2015-05-18 10:11:18
【问题描述】:

我有一个用于加密的 Java 代码,如下所示

byte[] encrypt(byte[] clearData) {
   byte[] passwordKey = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,0x0f};
   byte[] rawSecretKey = new byte[]{0x34, (byte) 0xA4, 0x16, 0x09, 0x77, (byte) 0x85, (byte) 0xB4, 0x31,
                                                0x75, 0x12, (byte) 0x92, (byte) 0xDD, (byte) 0xCA, 0x15, (byte) 0xAB, (byte) 0xBA};
   secretKey = new SecretKeySpec(passwordKey, "AES");
   ivParameterSpec = new IvParameterSpec(rawSecretKey);
   Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
   aesCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);

   byte[] encryptedData;
   encryptedData = aesCipher.doFinal(clearData);

   return encryptedData;
}

我必须将此代码移植到 JNI。我已经构建了 openssl 并制作了 JNI 包装函数,如下所示:

JNIEXPORT jbyteArray JNICALL Java_axon_voiceassistant_utils_JNIUtils_getcr(JNIEnv *env, jclass cls, jbyteArray srcData)
    {
        int srcLen=env->GetArrayLength(srcData);
        unsigned char* indata = new unsigned char[srcLen];
        env->GetByteArrayRegion (srcData, 0, srcLen, reinterpret_cast<jbyte*>(indata));

        const unsigned char ukey[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,0x0f};
        unsigned char iv [] = {0x34, 0xA4, 0x16, 0x09, 0x77,0x85, 0xB4, 0x31,
                               0x75, 0x12, 0x92,0xDD, 0xCA, 0x15, 0xAB, 0xBA};

        const size_t encs_length = ((srcLen + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
        unsigned char enc_data[encs_length];
        memset(enc_data, 0, sizeof(enc_data));


        AES_KEY key;
        memset(&key, 0, sizeof(AES_KEY));

        AES_set_encrypt_key(ukey, 128, &key);
        AES_cbc_encrypt(indata, enc_data, srcLen, &key, iv, AES_ENCRYPT);

        jbyteArray bArray = env->NewByteArray(encs_length);
        jboolean isCopy;
        void *enc_copy = env->GetPrimitiveArrayCritical((jarray)bArray, &isCopy);
        memcpy(enc_copy, enc_data, encs_length);

        env->ReleasePrimitiveArrayCritical( bArray, enc_copy, 0);

        return bArray;

    }

但是 JNI 版本与 Java 版本的结果不同。可能是什么问题?

【问题讨论】:

  • 没有得到相同的结果,是指整个加密结果不同,还是只是结尾不同?
  • 整个加密结果不同
  • 这可能部分是填充问题。根据一些研究,我认为AES_cbc_encrypt 会进行零填充。这只会影响密文的最后 16 个字节,因此,如果您的数据比这更长并且看起来都不同,那么至少还有一个问题。
  • @Duncan 当我问这个问题时,我只用简短的输入进行测试。我刚刚尝试过更长的输入,最后 16 个字节不同。这个填充问题有解决方案吗?
  • @sinisha 好吧,一种选择是自己在 JNI 代码中添加填充。 PKCS #7 填充非常简单(在 wikipedia 上查看)。零填充是个坏消息,所以我们不想更改您的 Java 代码来使用它。或者,您可以使用似乎可以理解填充的更高级别的 EVP 函数之一。

标签: java android encryption android-ndk openssl


【解决方案1】:

您在 JNI 代码中对纯文本进行了零填充:

const size_t encs_length = ((srcLen + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
unsigned char enc_data[encs_length];
memset(enc_data, 0, sizeof(enc_data));

但是您的 Java 代码正在使用 PKCS #7 填充。其中一项需要更改。

注意:我认为(基于一些研究)AES_cbc_encrypt 默认情况下会进行零填充,因此您自己完成此操作的步骤可能是多余的。

要解决这个问题,要么在 JNI 代码中手动实现 PKCS #7 填充(实际上非​​常简单),要么考虑使用更高级别的 EVP 函数,它了解如何填充数据。

【讨论】:

    猜你喜欢
    • 2022-11-16
    • 1970-01-01
    • 2017-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-04
    • 2012-06-06
    • 2021-08-13
    相关资源
    最近更新 更多