Hiding sensitive data using NDK in an Android application

Martin Dina Putra
Bootcampers
Published in
5 min readAug 4, 2022

As we progress through the Industry 4.0 Technology era, there are a lot of ways that an attacker could get around the system that we built and take advantage of the loopholes that we may have accidentally left. In the context of an Android application, there are many ways that we can use to improve our system’s security.

In this post, we’re going to walk through how can we use the NDK(Native Development Kit) to hide those sensitive data.

But first, what exactly is NDK?

The Native Development Kit (NDK) is a set of tools that allows you to use C and C++ code with Android, and provides platform libraries you can use to manage native activities and access physical device components, such as sensors and touch input

In short, NDK allows us to use C/C++ codes and let our app interact with them.

Why do we need NDK?

Oftentimes, a lot of sensitive data are stored locally within the code. Here is a couple of example of them:

  • API Keys from third-party libraries
  • URLs to make server API calls. Example- Base URLs to our private server

There are many ways to store these data, and often times those methods are not ideal. You may have tried to:

  1. Store them as string constants in a Kotlin/Java class
  2. Hardcode them wherever you need them (ex:Retrofit.Builder().baseUrl("https://my.backend.server"))
  3. Store them in Build.Config file

These solutions work just fine at the expense of the application’s security. The attacker could decompile your .apk and easily read these data

AppConstants.kt
Decompiled version of AppConstants

As we can see from the example above, the BASE_URL‘s value can be easily compromised with a simple few clicks of a button

So how does NDK help us with this problem exactly?

We store our sensitive data in a C/C++ class, then we call those classes using the JNI(Java Native Interface) from our Kotlin/Java classes.

The codes that we wrote in the C/C++ class are generated as .so files by the NDK that are much harder to decrypt than a regular Java/Kotlin class. Although reverse engineering the .so files is technically not impossible, it would be very hard to do. Thus, adding a layer of complexity for the attackers.

Let’s jump into it!

First thing first, you need to install the CMake and the NDK itself. You can easily do it by going through the menu Tools > SDK Manager > SDK Tools. You will find these two options, simply check them and wait for them to get installed.

SDK Tools Window

There is another way to install the NDK, which is by manually downloading the NDK from the official website, then adding the folder’s path to your project’s local.properties

Next, create a cpp folder on whichever android module you need to access the file from

cpp folder inside the :mini_projects module

Then, you need to create a .cpp file with the name native-lib (it can be whatever you want). Next, you can copaste the code below.

Now, there are a few things that you need to take note of when you name the function. To make it available in Java/Kotlin code, the format of the function name is Java_package_name_class_name_function_name

  • Java if you use Kotlin folder instead, then you need to rename it to Kotlin
  • class_name is the name of the class of which the native function will be called from
  • package_name is the name of the application’s package name where the class resides.
  • function_name is the name of the function which will be called from Kotlin/Java class.

Here is an example

The C++ Function that I wrote inside the native-lib.cpp will be used in the NdkModule

in this case, then my function will be: Java_com_tanakayu_mini_projects_di_NdkModule_getBaseUrlFromNative

Later on, we will access our C++ function using the getBaseUrlFromNative function from Java/Kotlin file. The name of the function itself can be whatever you want, but you will access them with whatever you put inside the .cpp file.

Next, we need to create a CMakeLists.txt (the name of the file has to be exact) file inside the cpp folder. Then, you can just copaste this code below into your CMakeLists.txt file.

Basically what the add_library command does is that we tell CMake to construct a native library with the name of “native-lib” from the .cpp file that we specify in the third parameter native-lib.cpp

And lastly, we also need to specify externalNativeBuild in the module’s build.gradle file.

this one is using Kotlin DSL, if you don’t use Kotlin DSL then you can copy the one below

And that’s it! We’re finished with the setup for now. The next step will be calling the function from our Kotlin/Java class.

Calling our native method

Finally, inside the file that we target, we call the System.loadLibrary("native-lib") inside the init block (static if you’re using Java)

And that’s it! We are finished. This would dramatically increase our app’s security as when an attacker tries to decompile our app it will be very hard for them to find the data that we store within our C++ file.

What’s Next?

Oftentimes, when we’re working for a big company there would be multiple values that are considered sensitive data. In this blog, we are taking the assumption that the application only has one baseUrl for its interaction with the backend server. But what if it has more than one?? for example, we have separate baseUrls for each deployment environment, which are usually dev, staging, and production.

Well, we would have to refactor our cpp class and make it return a List or Map instead of a single String. In theory, it doesn’t sound so complicated, but in reality, it’s not as straightforward, which I will share in the next blog post.

--

--