在Android NDK中使用OpenSSL
從 6.0 開始,Google 要求不要使用系統的 OpenSSL,請見:https://developer.android.com...。因此,請不要再使用本文介紹的方法,請自行交叉編譯 OpenSSL 或者使用別人編譯好的版本。
2017年3月注
由于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
這個文件變化較大,主要的變化包括:
插件名由原來的com.android.application變為com.android.model.application。
所有的配置放置在model { }塊中。
minSdkVersion和targetSdkVersion都需要配置它們的apiLevel屬性。
下面是一個完整的示例:
apply plugin: 'com.android.model.application'model {android {compileSdkVersion 23buildToolsVersion "23.0.2"defaultConfig {applicationId "com.example.openssltest"minSdkVersion.apiLevel 14targetSdkVersion.apiLevel 23versionCode 1versionName "1.0"}ndk {moduleName = "openssl-jni"platformVersion = 14ldFlags.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 arrayjbyte *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 arrayenv->ReleaseByteArrayElements(content, data, JNI_ABORT);// the return valuejbyteArray 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/andr...
需要注意的是,這里只是一個簡單的DEMO,不要直接在項目中保存密鑰之類的信息。
原文鏈接:https://dangfan.me/zh-Hans/po...
總結
以上是生活随笔為你收集整理的在Android NDK中使用OpenSSL的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈RBF函数
- 下一篇: 一站式解决,Android 拍照 图库的