在JNI中返回错误的MD5哈希值

3
我正在尝试使用原始/未修改的md5.h和md5c.c(github源文件:https://github.com/sinhpn92/encryption-in-C/tree/master/app/src/main/cpp)为字符串生成MD5哈希。但我的结果从未正确过。当我使用三星Galaxy J设备进行测试时,我的结果是正确的。但是,当我使用三星Galaxy S7设备进行测试时,我的结果就是错误的。我的代码有什么问题?有什么建议可以解决这个问题吗?感谢您的支持。
这是我的项目:https://github.com/sinhpn92/encryption-in-C 我使用cmake配置jni lib:
cmake_minimum_required(VERSION 3.4.1)

set(MD5SOURCES
    src/main/cpp/md5.c)


add_library(native-lib
             SHARED
             src/main/cpp/native-lib.cpp
              ${MD5SOURCES})


find_library(log-lib
              log )

target_link_libraries(native-lib
                       ${log-lib} )

这是 native-lib 文件:

#include <jni.h>
#include <string>
#include "md5.h"

extern "C"
jstring
Java_test_sinhpn_md5test_MainActivity_stringFromJNI(JNIEnv *env, jobject /* this */, jstring data) {
    char *cstr = (char *) (env)->GetStringUTFChars(data, 0);

    MD5_CTX context = {0};
    MD5Init(&context);
    MD5Update(&context, (unsigned char *) cstr, strlen(cstr));
    unsigned char dest[16] = {0};
    MD5Final(dest, &context);
    env->ReleaseStringUTFChars(data, cstr);

    int i;
    char destination[32] = {0};
    for (i = 0; i < 16; i++) {
        sprintf(destination, "%s%02x", destination, dest[i]);
    }
    return env->NewStringUTF(destination);
}

我的build.gradle文件:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "test.sinhpn.md5test"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags "-frtti -fexceptions"
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.1.1'
    testCompile 'junit:junit:4.12'
}

以下是我的测试结果:

这是一个图片描述

这是一个图片描述


1
值得验证行为差异不是由于第三方 MD5 库的缺陷造成的。建议在 C 源代码中明确(并数值化)表示一些字节序列上测试该库,以确认它在两个系统上产生相同的结果。 - John Bollinger
你发布的MD5代码中存在问题:/* UINT4定义了一个四字节的单词 */ typedef unsigned long int UINT4; 在64位平台上,使用64位的long值时,这个定义是不正确的。 - Andrew Henle
@John Bollinger:感谢您的评论。 我理解您的建议是我必须使用几个字节进行测试,而不是使用字符串?对吗? - Phan Sinh
@PhanSinh,你找到解决方案了吗?能否请您提及如何解决这个问题? - Om Infowave Developers
@OmInfowaveDevelopers:是的,我已经解决了。您可以在下面看到我的答案。 - Phan Sinh
显示剩余4条评论
2个回答

5

我已经通过替换代码中的:

typedef unsigned long int UINT4;typedef uint32_t UINT4;解决了我的问题。

我在两台设备上进行了测试,一切正常。在64位机器上,long int通常是64位而不是32位。


当我从这个typedef unsigned long int UINT4中删除long时,它就起作用了;现在它看起来像是typedef unsigned int UINT4,现在它可以工作了,感谢您将我引向正确的方向。 - Sunil Chaudhary

0

这两个手机使用不同的ARM指令集。Galaxy J使用armeabi-v7a,而S7使用arm64-v8a。

根据您上面的构建,cmake会为所有架构制作.so文件,这会导致本地代码中的32位与64位转换问题。

然而,在您的情况下存在一个简单的解决方法。您可以像下面这样将构建限制为abiFilters“armeabi-v7a”、“armeabi”在您的默认配置中。

    externalNativeBuild {
        cmake {
            cppFlags "-frtti -fexceptions"
            abiFilters "armeabi-v7a", "armeabi"
        }
    }

这应该仍然可以工作,因为arm64v8a与旧的v7a架构向后兼容。


1
架构差异是一个重要的观察点,但你是否在本地代码中看到任何实际的强制类型转换问题,还是这部分是推测的? - John Bollinger
@Bharat Kumar Molleti:感谢您的评论,但它并没有起作用。 - Phan Sinh
@JohnBollinger请查看andrew上面的评论。/* UINT4定义了一个四字节的单词 */typedef unsigned long int UINT4; 在64位平台上,使用64位长整型值时这将不再成立...,像上面提到的问题一样,建议在这种转换和强制类型转换中要小心。 - Bharat Kumar Molleti
@BharatKumarMolleti,所以它确实是一种推测,但你的推测结果是正确的?我赞扬你的洞察力。然而,如果它指出了有问题的代码的实际问题而不是猜测问题的一般性质,那么它将是一个更好的答案。 - John Bollinger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接