【问题标题】:Returning wrong md5 hash in jni在 jni 中返回错误的 md5 哈希
【发布时间】:2017-07-07 07:33:24
【问题描述】:

我正在尝试使用原始/未触及的 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} )

这是原生库:

#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'
}

这是我的测试结果:

【问题讨论】:

  • 值得验证行为差异是否归因于您的第三方 MD5 库中的缺陷。我建议在 C 源代码中明确(和数字)表达的几个字节序列上测试该库,以确认它在两个系统上产生相同的结果。
  • 这在您发布的 MD5 代码中看起来有问题:/* UINT4 defines a four byte word */ typedef unsigned long int UINT4; 在具有 64 位 long 值的 64 位平台上,情况并非如此......
  • @John Bollinger:感谢您的评论。我理解您的建议,我必须用几个字节而不是字符串进行测试?对吗?
  • @Andrew Henle 感谢您的评论。所以我的 md5 库错了?你能帮我分享一下好的 md5 代码吗?
  • @PhanSinh 你找到解决方案了吗?你能说说如何解决这个问题吗?

标签: android c hash java-native-interface md5


【解决方案1】:

这两款手机使用不同的 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 架构。

【讨论】:

  • 架构差异是一个重要的观察结果,但您是否在本机代码中看到任何 实际 转换问题,或者那部分是推测性的?
  • @Bharat Kumar Molleti:感谢您的评论。但这行不通。
  • @JohnBollinger 请参阅上面的安德鲁评论。 /* UINT4 定义了一个四字节字 */ typedef unsigned long int UINT4;在具有 64 位长值的 64 位平台上,情况并非如此......,存在上述问题,建议谨慎处理此类转换和强制转换。
  • @BharatKumarMolleti,所以这确实是推测性的,但你的推测结果是正确的?我赞扬你的洞察力。但是,如果它参考有问题的代码指出实际问题而不是猜测问题的一般性质,那将是一个更好的答案。
【解决方案2】:

我已经通过替换解决了我的问题:

typedef unsigned long int UINT4; 在 md5.c -> typedef uint32_t UINT4;

我在两台设备上再次测试,一切正常。在 64 位机器上 long int (通常)是 64 位而不是 32

【讨论】:

  • 当我从这个 typedef unsigned long int UINT4 中删除 long 时工作;现在它看起来像 typedef unsigned int UINT4 this ,现在可以工作了,谢谢你让我正确的方向
猜你喜欢
  • 2013-03-30
  • 1970-01-01
  • 2020-06-01
  • 2015-04-13
  • 2018-03-23
  • 2012-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多