How To Secure Secret API Key In Android Studio
Reverse Engineering Is Increasing Day By Day Due To Which Normal Applications Are Not Safe Enough. In This Post , We Will Learn How To Secure Your App's Secret Strings , API From Being Reverse Engineered.
Hide Secret API Key In Android Studio
Generally We Declare API Key In A Variable , Then Call It When It Is Required. But Doing This Makes Easy For Reverse Engineers To Extract The Exact API Key (Or Any Import Data / Strings) Which Any Developer Never Wants. Then The Extracted Detail Can Be Used For Any Wrong Purpose Or One Can Abuse The API Which Can Leads To Down The Service. To Make Sure This Would Never Happen With You , You Need To Hide / Secure Your Important Strings Including API Keys , User , Pass Or Any Secret JSON URL.
Creating A Simple API App In Android Studio
Lets Create An Application Using Android Studio Which Will Show An API String On Button Press . Create An Empty Activity , Name The Project As HideAPIKey , Choose com.nd.hideapikey As Package Name And Select Java As The Language.
Lets Create activity_main.xml As Follows :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Secure API Key Tutorial\nNarendraDwivedi.Org"
android:textColor="@color/black"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.274"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.065" />
<Button
android:id="@+id/btnshow"
android:layout_width="210dp"
android:layout_height="67dp"
android:backgroundTint="@color/black"
android:text="Show API Key"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.124"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.168" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click The Button To Show API"
android:id="@+id/txtoutput"
android:textColor="@color/black"
android:textSize="15sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.115"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnshow"
app:layout_constraintVertical_bias="0.122" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_main.xml |
Now Initialize Button & TextView
package com.nd.hideapikey;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
Button btnshow;
TextView txtoutput;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnshow=findViewById(R.id.btnshow);
txtoutput=findViewById(R.id.txtoutput);
}
}
Lets Create A Method Using Which A Sample API Will Be Shown In txtoutput And This Method Will Be Called on Clicking Button btnshowpackage com.nd.hideapikey;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
Button btnshow;
TextView txtoutput;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnshow=findViewById(R.id.btnshow);
txtoutput=findViewById(R.id.txtoutput);
btnshow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showresult();
}
});
}
public void showresult()
{
String apikey="https://link.narendradwivedi.org/";
txtoutput.setText("The API Key Is "+apikey);
}
}
Lets Build The App , Install & Run It.Reverse Engineering Application To Find API Key (Non Secured App)
Now Lets Try To Extract The API Key Of This Application By Reverse Engineering It.
The Application Got Easily Reversed And I Extracted The API Key Very Easily. So Now You May Have Understood That Declaring The Important Secrets (Like API) Without Protecting Is Unsafe. Now Lets Learn How To Secure These Important Secrets.
How To Secure API Key In Java (Android Studio)
To Secure Your API Key (Or Any Other Secrets) , Open The Desired Project In Android Studio. In Our Case We Have Opened This Same Project (HideAPIKey).
Now Make Sure That You Have Installed NDK & CMake. If It Is Not Installed In Your System , Install It From SDK Manager Of Android Studio
In jni Directory , We Need To Create Three Files
- Android.mk [Right Click On main -> New ->File]. Enter Following Code In It And Save It
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := keys
LOCAL_SRC_FILES := keys.c
include $(BUILD_SHARED_LIBRARY)
- Application.mk [Right Click On main -> New ->File]
APP_ABI := all
- keys.c [Right Click On main -> New ->File]
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_nd_hideapikey_MainActivity_getAPIKey(JNIEnv *env, jobject instance) {
return (*env)-> NewStringUTF(env, "aHR0cHM6Ly9saW5rLm5hcmVuZHJhZHdpdmVkaS5vcmcv");
}
In keys.c File , Replace com_nd_hideapikey With Your Package Name. Here MainActivity Indicate The Name Of The Activity In Which We Need The API , So Replace It According To Your Project. getAPIKey Is The Name Of The Method We Are Creating Here Which We Will Call To Get The API. Here aHR0cHM6Ly9saW5rLm5hcmVuZHJhZHdpdmVkaS5vcmcv Is The Encrypted Base64 Of Secret API Which We Are Protecting. Go to https://base64.narendradwivedi.org And Enter The Secret String/ API Key Which You Want To Protect And Click On Encode Button. Replace aHR0cHM6Ly9saW5rLm5hcmVuZHJhZHdpdmVkaS5vcmcv With Your Base64If You Want To Protect Multiple Contents , Then You Have To Create Multiple Methods. You Can Copy The Code From JNIEXPORT ..... Java_com_... newMethod2 ... ..... To return ... } And Can Append In The Above Code To Create New Methods. (Make Sure To Change Method Names )
So Our Project Looks Like This
Lets Again Change The Project View From Project To Android. We Need To Add Some Entries In build.gradle (Module) [ After buildTypes ]
ndkVersion '25.0.8775105'
externalNativeBuild {
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
Here We Need To Specify The ndkversion (In My Case , The Version Is 25.0.8775105). Also We Need To Specify The Path Of Android.mk File. If All Cases , The Path Will Be Same If You Have Followed This Tutorial.To Find Your NDK Version , Open SDK Manager , Go To SDK Tools And Check Show Package Detail Option
Now Sync The Gradle File To Save The Changes.
The Complete Code For build.gradle (Module) File :
plugins {
id 'com.android.application'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.nd.hideapikey"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
ndkVersion '25.0.8775105'
externalNativeBuild {
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
Retrieving API Key In Our Application
Open The Activity In Which We Have To Get The API Key. In Our Case It Is MainActivity.java
Create A Static Block And Load keys Library
static {
System.loadLibrary("keys");
}
After That , We Need To Call The Method Which We Have Created In keys.c File Using Native Function.public native String getAPIKey();
Now Call getAPIKey() In showresult() Method. The API Key Was Stored In Base64 Format , So Will Need To Decode It.String apikey = new String(Base64.decode(getAPIKey(),Base64.DEFAULT));
Make Sure To Import Base64 In Project [ Using import android.util.Base64; ]Complete MainActivity.java Code :
package com.nd.hideapikey;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
Button btnshow;
TextView txtoutput;
static {
System.loadLibrary("keys");
}
public native String getAPIKey();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnshow=findViewById(R.id.btnshow);
txtoutput=findViewById(R.id.txtoutput);
btnshow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showresult();
}
});
}
public void showresult()
{
String apikey = new String(Base64.decode(getAPIKey(),Base64.DEFAULT));
txtoutput.setText("The API Key Is "+apikey);
}
}
Lets Build The App , Install & Run It.Reverse Engineering Application To Find API Key (Secured App)
After Protecting The API Key , Lets Try To Extract API Key By Reverse Engineering The APK
Here It Is Impossible To Get The API Key. In This Way , We Have Successfully Protected Our Application's Secret API Key.
Download Android Studio Project Of Hiding API Key [Android Studio , JAVA]
Download This Whole Project Discussed In This Post
FAQ
Why To Hide API Key
The API Keys Can Be Used To Make Unwanted Changes To Your Account. It Can Also Used To Abuse [Malicious Massive Request] The Service Of API Key Provider
Can I Use Any Other Name Instead Of jni
No , You Cannot. You Must Have To Use The Directory Name As jni
How To Encode And Decode String As Base64
By Visiting https://base64.narendradwivedi.org , You Can Encode Data As Base64. You Can Also Decode It
Can I Protect String Instead Of API In Android Application
Yes , You Can Protect Any Strings Also By Following The Steps Mentioned In This Post
Conclusion
I Hope You Have Learnt The Method To Protect Android Application's API / String From Being Extracted By Reverse Engineering. If You Have Any Doubt , Comment Below.
1 comment