Securing API Keys inside Android Apps using Android NDK

Securing third party library API key secret in Android application completely is difficult by traditional methods (storing them in strings.xml or in Gradle etc.), since they can be easily exposed by reverse engineering the app. Losing keys not only affects the billing for the API access, but may also lead to privacy issues with the user base of the app.

Today, I am going to show you how to store API keys in the native C/C++ class and accessing them in our Java classes. Android NDK libraries/classes can’t be easily decompiled making the information harder to find. Although the NDK compiled code can still be opened with a hexadecimal editor, but by the nature of the API key they are harder to pick out in a hexadecimal editor.

Requirements

  • The Android Native Development Kit (NDK): a toolset that allows you to use C and C++ code with Android, and provides platform libraries that allow you to manage native activities and access physical device components, such as sensors and touch input.
  • CMake: an external build tool that works alongside Gradle to build your native library. You do not need this component if you only plan to use ndk-build.

You can install these components using the SDK Manager:

  • From an open project, select Tools > Android > SDK Manager from the menu bar.
  • Click the SDK Tools tab.
  • Check the boxes next to LLDB, CMake, and NDK, as shown in below figure:
  • Click Apply, and then click OK in the pop-up dialog.
  • When the installation is complete, click Finish, and then click OK.

Steps:

  • Create a new project or use existing project
  • Create a folder “native” under src/main
  • Create the C/C++ file “native-lib.cpp” and add it under “native” folder.

Add the following content to it:

Here, Java_com_squareboat_secretkeys_MainActivity_getAPIKey represents the Java code with package name “com.squareboatsecretkeys” followed by Activity name “MainActivity” where we want to call the native function and the static method “getAPIKey” to fetch the API key from the native function. In the above code, I have encoded the actual API key using Base64 encoding and will decode it while fetching.

  • Create a CMake build script: If your native sources don’t already have a CMake build script, you need to create one yourself and include the appropriate CMake commands.

A CMake build script is a plain text file that you must name CMakeLists.txt under src folder and add following content to it:

  • In the Activity where you want to access the keys (in our case MainActivity), create a static block and load the library “native” like:
static {
System.loadLibrary("native-lib");
}
  • Declare the member function of type “native” to access the keys from the C/C++ file.
public native String getAPIKey();
  • For example, access the keys in the code like:
String apiKey = Base64.decode(getAPIKey(), Base64.DEFAULT);
  • Now, our C/C++ native files and Java code are ready. But to compile or make the native build using NDK, we need to add entry into the gradle file:
externalNativeBuild {
cmake {
path 'src/CMakeLists.txt'
}
}
  • Now, sync and build the project. Make sure, you have pointed the NDK path correctly in your module settings.
  • On successful run you will see the decoded keys from the Native C/C++ code as:

Please refer to the GitHub project for the full app.

Show your support

Clapping shows how much you appreciated Vipul Asri’s story.