在Android NDK中使用OpenSSL

AustinSmith 8年前發布 | 51K 次閱讀 OpenSSL 安卓開發 移動開發

來自: https://segmentfault.com/a/1190000004522943

由于Java較為容易被反編譯,因此把一些重要代碼放在so文件中成為了一個代價不太高的選擇。雖然so文件依舊可以反編譯,但對so進行逆向分析的門檻則要比分析Java字節碼的門檻高出不少。很多安全相關的代碼都依賴OpenSSL,然而網絡上在NDK中使用OpenSSL的教程并不多見,經過一天的探索,我終于可以成功在NDK中調用OpenSSL了。本文將以調用OpenSSL中的HMAC算法為例,介紹如何使用Gradle配置NDK并在NDK中使用OpenSSL。

在Gradle中配置NDK

2015年7月,Google發布了新的Gradle插件,提供了對NDK的支持,從此,編寫NDK程序不再需要編寫 Android.mk 文件,也不再需要使用 ndk-build 腳本,只需要在Gradle中簡單的配置一下,即可方便的編譯程序了。

目前,新的插件仍處在beta版本,本文選用當前時間(2016年3月2日)最新的 0.6.0-beta5 作介紹。要獲取最新的更新,請訪問 這里

從傳統的Android Gradle插件遷移到新的插件并不困難,只需要修改原有目錄結構中的三個文件即可。以如下目錄為例:

.
├── app/
│   ├── build.gradle
│   └── src/
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle

需要修改的文件包括兩個 build.gradle 、 gradle-wrapper.properties 和 local.properties 文件。

分別來看對它們的修改:

每個版本的插件都只支持特定的Gradle版本,因此請務必對照上文給出的鏈接填寫正確的版本。

  • ./local.properties

需要在文件中指定 ndk.dir 屬性,指向 NDK 的路徑。

  • ./gradle/wrapper/gradle-wrapper.properties

這個文件定義了Gradle的版本,這里需要使用 gradle-2.10 ,因此需要把最后一行的版本替換掉。

  • ./build.gradle

這里定義了構建時使用的插件,需要替換為 com.android.tools.build:gradle-experimental:0.6.0-beta5 。

  • ./app/build.gradle

這個文件變化較大,主要的變化包括:

  1. 插件名由原來的 com.android.application 變為 com.android.model.application 。

  2. 所有的配置放置在 model { } 塊中。

  3. minSdkVersion 和 targetSdkVersion 都需要配置它們的 apiLevel 屬性。

下面是一個完整的示例:

apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion 23
        buildToolsVersion "23.0.2"

        defaultConfig {
            applicationId "com.example.openssltest"
            minSdkVersion.apiLevel 14
            targetSdkVersion.apiLevel 23
            versionCode 1
            versionName "1.0"
        }

        ndk {
            moduleName = "openssl-jni"
            platformVersion = 14
            ldFlags.add("-lcrypto")
            abiFilters.add("armeabi-v7a")
        }
    }
}

dependencies {
    compile 'com.android.support:appcompat-v7:23.1.1'
}

這個配置中,多出了 ndk 部分,下面就來解釋一下這部分的配置:

  • moduleName 決定了編譯出來的庫的名稱,這個選項是必須的。

  • platformVersion 指定了NDK的platform版本,這里使用14是因為 minSdkVersion 使用14。

  • ldFlags 指定了鏈接時的參數,由于本例中只用到了HMAC算法,因此這里添加了對 crypto ,如果還需要TLS的支持,這里需要改為 ldFlags.addAll(["-lcrypto", "-lssl"]) 。

  • abiFilters 里指定了abi的版本 armeabi-v7a ,

在NDK中使用OpenSSL

Android里已經內置了OpenSSL,但NDK中并沒有提供相應的庫。只需要把OpenSSL的 .so 文件放在NDK中即可:

$adb pull /system/lib/libssl.so /myndk/platforms/android-14/arch-arm/usr/lib

$adb pull /system/lib/libcrypto.so /myndk/platforms/android-14/arch-arm/usr/lib

然后把OpenSSL的頭文件放在 /myndk/platforms/android-14/arch-arm/usr/include 目錄中即可。

編寫代碼請參考JNI的文檔,下面給出一個調用 HMAC-SHA256 的實現:

#include <jni.h>
#include <openssl/hmac.h>

#ifdef __cplusplus
extern "C" {
#endif
jbyteArray
Java_com_example_openssltest_MainActivity_hmacSha256(JNIEnv *env,
                                                     jobject obj,
                                                     jbyteArray content) {
  unsigned char key[] = {0x6B, 0x65, 0x79};

  unsigned int result_len;
  unsigned char result[EVP_MAX_MD_SIZE];

  // get data from java array
  jbyte *data = env->GetByteArrayElements(content, NULL);
  size_t dataLength = env->GetArrayLength(content);

  HMAC(EVP_sha256(),
       key, 3,
       (unsigned char *) data, dataLength,
       result, &result_len);

  // release the array
  env->ReleaseByteArrayElements(content, data, JNI_ABORT);

  // the return value
  jbyteArray return_val = env->NewByteArray(result_len);
  env->SetByteArrayRegion(return_val, 0, result_len, (jbyte *) result);
  return return_val;
}
#ifdef __cplusplus
}
#endif

在Java中調用也很容易,只需要引用 build.gradle 中指定的庫即可:

public native byte[] hmacSha256(byte[] data);

static {
    System.loadLibrary("openssl-jni");
}

DEMO項目鏈接

https://github.com/terro/android-ndk-openssl

需要注意的是,這里只是一個簡單的DEMO,不要直接在項目中保存密鑰之類的信息。

原文鏈接: https://dangfan.me/zh-Hans/posts/android-ndk-openssl
 本文由用戶 AustinSmith 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!