Home > Software engineering >  Use NDK/JNI to keep secret keys in Android with high security
Use NDK/JNI to keep secret keys in Android with high security

Time:06-30

We can write methods to get the key as below both Method 1 and Method 2 for the Android app

Are both Methods have the same security strength? or is there any security weakness in one of the below Methods while decompile/reverse engineering or other app cracking procedures?

Method 1

declare/assign key inside the method in the lib.cpp file

lib.cpp file

extern "C"
JNIEXPORT jstring JNICALL
Java_com_app_keytest_KeyHelper_getKey(JNIEnv *env, jobject) {
    std::string API_KEY = "YOUR_API_KEY";
    return env->NewStringUTF(API_KEY.c_str());
}

Method 2

declare/assign keys in separate keys.h file in the same directory with lib.cpp and import to lib.cpp file

keys.h file

std::string API_KEY = "YOUR_API_KEY";

lib.cpp file

#include "keys.h"

extern "C"
JNIEXPORT jstring JNICALL
Java_com_app_keytest_KeyHelper_getKey(JNIEnv *env, jobject) {
    return env->NewStringUTF(API_KEY.c_str());
}

CodePudding user response:

Your two snippets compile to nearly the exact same code. In both cases the API key is present in plain text in the compiled library. Even if you took pains to obfuscate the native code, an attacker can just attach a debugger and catch the return value of getKey.

You need to rethink your approach and decide if it is actually worth the effort on your part.

CodePudding user response:

You can achieve a good result in another way:

  1. you have to obfuscate JNI function name because "getKey()" is too much self-explained and easy to understand during reverse engineering
  2. add unused parameters to "getKey()" to make it more complex when scrolling while viewing reversed code
  3. getKey() haven't to return the Key but have to call a Java method or set a specific Java variable

About #3: I'm using a dedicated Thread on JNI to receive a "command" and a "callback" for its results:

  1. Java calls JNI's "getKey(fakeArg1, fakeArg2, fn_callback, fakeArg3)"
  2. getKey() sends a request to JNI dedicated Thread and pass even "fn_callback" as part of that request
  3. the dedicated Thread process the request and then call Java Callback

In this way event during normal debugging it's very difficult to follow the Flow because debugging won't go inside dedicated Thread automatically using StepInto/Over key/button.

Update: callback is the first approach but create a link between caller and the result. To avoid this you could call a completly separated Java method from JNI to pass the variable to.

  • Related