There are a lot of methods to safe your key when producing APKs. However for now, I need to clarify one solution to safe your key: retailer the important thing within the NDK and double safe it with an encrypted key.
I consider this isn’t a 100% assure that your secret is safe. However at the very least make it arduous for an attacker to get your keys or any delicate knowledge out of your APK.
Learn this doc about NDK from Google.
Including C++ to Modules
In Android Studio, you’ll be able to simply add a C++ module to your app module by proper clicking on the app module and clicking Add C++ to Module. Alternatively you are able to do it by double clicking the shift button in your keyboard and typing Add C++ to Module
.
Once you’re achieved, you’ll be able to create a CMakeLists.txt and put it beneath app/src/most important/cpp
.
Lastly, from these processes it would do just a few issues:
- Generate CMakeLists.txt. we will depart it as for CMakeLists.txt.
# CMakeLists.txt
# For extra details about utilizing CMake with Android Studio, learn the
# documentation: https://d.android.com/studio/initiatives/add-native-code.html
# Units the minimal model of CMake required to construct the native library.
cmake_minimum_required(VERSION 3.18.1)
# Declares and names the mission.
mission("encryptedndk")
# Creates and names a library, units it as both STATIC
# or SHARED, and gives the relative paths to its supply code.
# You possibly can outline a number of libraries, and CMake builds them for you.
# Gradle robotically packages shared libraries along with your APK.
add_library( # Units the identify of the library.
encryptedndk
# Units the library as a shared library.
SHARED
# Supplies a relative path to your supply file(s).
encryptedndk.cpp )
# Searches for a specified prebuilt library and shops the trail as a
# variable. As a result of CMake consists of system libraries within the search path by
# default, you solely must specify the identify of the general public NDK library
# you need to add. CMake verifies that the library exists earlier than
# finishing its construct.
find_library( # Units the identify of the trail variable.
log-lib
# Specifies the identify of the NDK library that
# you need CMake to find.
log )
# Specifies libraries CMake ought to hyperlink to your goal library. You
# can hyperlink a number of libraries, equivalent to libraries you outline on this
# construct script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the goal library.
encryptedndk
# Hyperlinks the goal library to the log library
# included within the NDK.
${log-lib} )
- Generate encryptionndk.cpp. On this file we’ll add some code to set API_TOKEN This.
// encryptedndk.cpp
#embrace
extern "C" JNIEXPORT jstring JNICALL
// Java_{package_name}_{class_name}_{method_name}
Java_com_adefruandta_encryptedndk_EncryptedNdk_apiTokenNative(JNIEnv *env, jobject object) {
// API_TOKEN is a continuing that will probably be handed from gradle
return env->NewStringUTF(API_TOKEN);
}
- your modification app/construct.gradle
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {
// That is the way in which we go our API_TOKEN from gradle to cpp
cppFlags '-DAPI_TOKEN="This_is_API_TOKEN_from_native"'
}
}
}
// This part is auto up to date from Add C++ to module course of
externalNativeBuild {
cmake {
path file('src/most important/cpp/CMakeLists.txt')
model '3.18.1'
}
}
}
Simply tried to sync and construct the mission. Be sure there aren’t any errors.
Hyperlink cpp with kotlin class
After we have now the cpp file to retailer API_TOKENwe will create a category with similar bundle identify, class identify and technique identify as in your cpp file.
bundle com.adefruandta.encryptedndk
object EncryptedNdk {
init {
System.loadLibrary("encryptedndk");
}
exterior enjoyable apiTokenNative(): String
}
// or for those who desire, use class as a substitute of object
class EncryptedNdk {
companion object {
init {
System.loadLibrary("encryptedndk");
}
}
exterior enjoyable apiTokenNative(): String
}
Be sure there may be an icon to the left of your modal apiTokenNative()
. Meaning you’ve got succeeded in connecting your cpp to the Kotlin class.
You possibly can then do some testing by printing it to your exercise or displaying a toast.
class MainActivity : AppCompatActivity() {
override enjoyable onCreate(savedInstanceState: Bundle?) {
tremendous.onCreate(savedInstanceState)
Toast.makeText(this, EncryptedNdk.apiTokenNative(), Toast.LENGTH_LONG).present()
}
}
All achieved, you’ve got efficiently booked your first time API_TOKEN into the NDK.
Encrypt API_TOKEN
To have an encoding API_TOKEN, you want an encode perform that you’ll use earlier than passing it to cppFlags in your Gradle script. Create encoder.gradle within the unique mission.
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
def algorithm = "AES/CBC/PKCS5Padding"
def iv = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] as byte[]
def ivSpec = new IvParameterSpec(iv)
ext.encrypt = { textual content, key ->
def cipher = Cipher.getInstance(algorithm)
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.bytes, "AES"), ivSpec)
def cipherText = cipher.doFinal(textual content.bytes)
return cipherText.encodeBase64()
}
Extra details about the algorithm will be discovered This. You possibly can change it to one thing appropriate on your mission. Totally different algorithms have totally different necessities on your key. Within the earlier instance, utilizing AES/CBC/PKCS5 . padding algorithm for producing a key of 16 characters (or 16 bytes).
Then you should utilize it in app/construct.gradle.
apply from: '../encryptor.gradle'
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {
// encrypt when passing to cppFlags
cppFlags '-DAPI_TOKEN="' + encrypt("This_is_API_TOKEN_from_native", "1234567890123456") + '"'
}
}
}
}
Simply attempt operating it and see the outcomes. The API_TOKEN will probably be displayed encoded.
Decode API_TOKEN
After you efficiently encode API_TOKENit is advisable decode it to get the precise worth of API_TOKEN. So it is advisable have a perform on EncryptionNdk class to decode apiTokenNative()
.
object EncryptedNdk {
...
exterior enjoyable apiTokenNative(): String
enjoyable apiToken(): String = decrypt(apiTokenNative())
// area Decryptor
// The algorithm needs to be the identical with encryptor
personal const val algorithm = "AES/CBC/PKCS5Padding"
personal val cipher = Cipher.getInstance(algorithm)
personal val iv = ByteArray(16)
personal val ivSpec = IvParameterSpec(iv)
personal val keySpec = SecretKeySpec("1234567890123456".toByteArray(), "AES")
personal enjoyable decrypt(
textual content: String
): String {
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec)
val plainText = cipher.doFinal(Base64.decode(textual content, Base64.DEFAULT))
return String(plainText)
}
// endregion
}
And at last, change the phrase EncryptedNdk.apiTokenNative() ARRIVE EncryptedNdk.apiToken() ABOVE MainActivity.kt.
class MainActivity : AppCompatActivity() {
override enjoyable onCreate(savedInstanceState: Bundle?) {
tremendous.onCreate(savedInstanceState)
Toast.makeText(this, EncryptedNdk.apiToken(), Toast.LENGTH_LONG).present()
}
}
It can present actuality API_TOKEN On toast.
Safety guidelines
As a result of we write bundle identify, class identify and technique identify on cpp file, we’d like a guard rule to maintain bundle identify, class identify and technique identify for you EncryptionNdk class.
-keep class com.adefruandta.encryptedndk.EncryptedNdk {
native ;
}
Final contact
Since you’ve got c++ in your module, if you construct the mission it would create a cxx folder in your module. So it is advisable ignore it from git. Alternatively, you’ll be able to add a customized Gradle activity to take away the cxx folder when operating a clear activity.
// app/construct.gradle
mission.activity("cleanCxx") {
delete '.cxx'
}
mission.duties.findByName("clear").finalizedBy("cleanCxx")