Teknik Penerapan Enkripsi pada Session yang Tersimpan di Aplikasi Android

Nanda Adisaputra
10 min readJan 31, 2023

--

Kita akan menggunakan study kasus aplikasi paling sederhana agar mudah dipahami. Pada study kasus Aplikasi ini dapat menambah nama user dan menyimpannya di share preference dalam bentuk enkripsi , kemudian menampilkan session nya di halaman home.

Sebelumnya Berjumpa lagi dengan Saya Nanda Adisaputra, S.Kom. Pada kesempatan kali ini Saya akan sharing mengenai Enkripsi pada Session yang tersimpan pada Aplikasi Android.

Yuk langsung saja Kita bahas.

— — — — — — — —

Langkah awal Kita buat Project baru dengan kriteria seperti dibawah ini.

Kemudian tambahkan library hilt dan security di build.gradle(Module:App) tepatnya didalam dependencies {}

//TODO 1 Add Library
//hilt
implementation 'com.google.dagger:hilt-android:2.44'
kapt 'com.google.dagger:hilt-compiler:2.44'
//Library ini yang akan Kita gunakan untuk mengenkripsi teks yang tersimpan
//di session.
implementation "androidx.security:security-crypto:1.1.0-alpha04"
implementation 'com.scottyab:secure-preferences-lib:0.1.7'

Setelah itu tambahkan source code untuk dapat menggunakan Data Binding.

/    //TODO 2 Add ViewBinding and DataBinding
buildFeatures {
/* untuk mengaktifkan databinding dan viewbinding */
dataBinding true
viewBinding true
}

Sehingga pada keseluruhan Source code di bagian build.gradle ( Module :App) akan menjadi sebagai berikut ini

plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
//TODO 3 Add Plugin
id 'kotlin-kapt'
id 'com.google.dagger.hilt.android'
}

android {
namespace 'com.nandaadisaputra.simpleencryption'
compileSdk 33

defaultConfig {
applicationId "com.nandaadisaputra.simpleencryption"
minSdk 23
targetSdk 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
//TODO 2 Add ViewBinding and DataBinding
buildFeatures {
/* untuk mengaktifkan databinding dan viewbinding */
dataBinding true
viewBinding true
}
}

dependencies {

implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

//TODO 1 Add Library
//hilt
implementation 'com.google.dagger:hilt-android:2.44'
kapt 'com.google.dagger:hilt-compiler:2.44'
//enkripsi
implementation "androidx.security:security-crypto:1.1.0-alpha04"
implementation 'com.scottyab:secure-preferences-lib:0.1.7'

testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

Kita akan berpindah ke build.gradle(Project :App). Tambahkan plugin classpath DI Hilt dan juga Task Clean.

plugins {
id 'com.android.application' version '7.3.1' apply false
id 'com.android.library' version '7.3.1' apply false
id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
//TODO 4 Add Plugin ClassPath DI Hilt
id 'com.google.dagger.hilt.android' version '2.44' apply false
}
//TODO 5 Add Task Clean
task clean(type: Delete) {
delete rootProject.buildDir
}

Setelah menambahkan library dan plugin di gradle jangan lupa klik Sync Now pada pojok kanan atas agar perubahan tersebut dapat terbaca oleh android studio.

Kemudian buatlah package dengan nama base, data, injection dan juga ui. Caranya yaitu dengan Klik kanan pada nama package -> New -> Package

Sehingga tampilan strukturnya akan seperti berikut ini.

Anda dapat drag Class MainActivity.kt ke dalam package ui agar kelihatan lebih rapi dan terstruktur.

Langkah selanjutnya buatlah class App.kt. Caranya yaitu dengan klik kanan pada package base -> New -> Kotlin Class /File -> Beri nama App ->Enter

Tambahkan source code berikut ini di class App.kt

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

//Karena Kita menggunakan DI Hilt maka jangan lupa
//Tambahkan anotasi @HiltAndroidApp
@HiltAndroidApp
class App : Application()

Langkah berikutnya Kita berpindah ke AndroidManifest.xml di folder manifest. Tambahkan source code berikut ini untuk memberitahu bahwa Kita menggunakan core nya Dependency Injection Hilt

android:name=".base.App"

Sehingga tampilan seluruh source code di AndroidManifest.xml akan sebagai berikut.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:name=".base.App"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SimpleEncryption"
tools:targetApi="31">
<activity
android:name=".ui.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>

</manifest>

Kemudian buatlah class Session.kt di package data . Caranya yaitu dengan klik kanan pada package data -> New -> Kotlin Class / File -> beri nama dengan nama Session -> Enter.

Kemudian tambahkan source code berikut ini didalam class Session.kt

class Session(context: Context) {
//deklarasi varabel
private val preferencesName = "SharedPreference"
private val privateMode = 0
val yourUsername = "Username"
val isSession = "Session"
var context: Context
private var pref: SharedPreferences =
context.getSharedPreferences("Session", Context.MODE_PRIVATE)
private var editor: SharedPreferences.Editor = pref.edit()

init {
this.context = context
pref = context.getSharedPreferences(preferencesName, privateMode)
editor = pref.edit()
}
//Untuk Menyimpan session bertipe String
fun savePrefString(key: String, value: String) {
editor.putString(key, value)
editor.commit()
}
//Untuk Menyimpan Pernyataan sudah ada session atau belum
fun savePrefBoolean(key: String, value: Boolean) {
editor.putBoolean(key, value)
editor.commit()
}
//Untuk mengambil session Username
fun getUsername(): String? {
return pref.getString(yourUsername, "")
}
//Untuk Mengecek apakah ada session atau tidak
fun getIsSession(): Boolean {
return pref.getBoolean(isSession, false)
}
}

Langkah berikutnya buatlah class DataModule.kt . Caranya yaitu dengan cara klik kanan pada package injection -> New -> Kotlin Class / File -> Beri nama dengan nama DataModule -> Enter

Selanjutnya tambahkan source code dibawah ini pada class DataModule.kt

import android.content.Context
import com.nandaadisaputra.simpleencryption.data.Session
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent

@InstallIn(SingletonComponent::class)
@Module
class DataModule {
@Provides
fun provideSharedPreferences(@ApplicationContext context: Context) = Session(context)
}

Kemudian modifikasi layout default pada activity_main.xml sebagai berikut ini.

<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="activity"
type="com.nandaadisaputra.simpleencryption.ui.MainActivity" />
</data>

<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:padding="16dp"
tools:context=".ui.MainActivity">

<EditText
android:id="@+id/tv_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints="@string/username"
android:hint="@string/username"
android:text='@={activity.usernameUser}'
android:inputType="textPersonName"
android:padding="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/save"
android:onClick='@{() -> activity.saveUsername()}'
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_username" />

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Langkah berikutnya buatlah class HomeActivity.kt . Caranya yaitu dengan cara klik kanan pada package ui -> New -> Activity -> Empty Activity

Kemudian berilah nama dengan nama HomeActivity, jangan lupa untuk checklist generate a layout File agar otomatis membuat layout activity_home.xml -> Klik Finish.

Selanjutnya kalian dapat modifikasi bagian activity_home.xml seperti pada source code dibawah ini.

<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="activity"
type="com.nandaadisaputra.simpleencryption.ui.HomeActivity" />
</data>
<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"
tools:context=".ui.HomeActivity">

<TextView
android:id="@+id/tv_hallo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/btn_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="48dp"
android:backgroundTint="@android:color/holo_red_light"
android:text="@string/clear"
android:onClick='@{() -> activity.logOut()}'
android:textColor="@android:color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_hallo" />

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Kemudian tambahkan source code berikut ini dibagian strings.xml

<resources>
<string name="app_name">SimpleEncryption</string>
<!--TODO ADD RESOURCE STRING -->
<string name="username">username</string>
<string name="save">Save</string>
<string name="clear">Clear</string>
</resources>

Lalu jangan lupa modifikasi juga source code bagian MainActivity.kt sebagai berikut ini.

import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.nandaadisaputra.simpleencryption.R
import com.nandaadisaputra.simpleencryption.data.Session
import com.nandaadisaputra.simpleencryption.databinding.ActivityMainBinding
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

//Karena Kita pakai DI Hilt jangan lupa tambahkan anotasi
//@AndroidEntryPoint pada setiap class Activity
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
//Karena Kita sudah pakai DI Hilt maka Kita dapat memanggil session
//dengan cara @Inject
@Inject
lateinit var session: Session

/*Kita deklarasikan juga binding yang akan Kita gunakan*/
private val binding: ActivityMainBinding by lazy {
DataBindingUtil.setContentView(this, R.layout.activity_main)
}

/*Karena Kita menerapkan DataBinding*/
var usernameUser = ""

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/*inisialisasi dulu activitynya*/
/*wajib karena Kita memakai DataBinding*/
binding.activity = this
binding.lifecycleOwner = this
/*Kita akan memakai fungsi checkData()
* * maka perlu Kita deklarasikan dulu */
checkData()
}

private fun checkData() {
//Periksa apakah sudah ada session yang masih tersimpan atau belum
if (session.getIsSession()) {
//Jika sudah ada session yang masih tersimpan maka
//akan langsung masuk halaman HomeActivity.kt
//Jika belum ada session maka akan masuk halaman ini
//MainActivity.kt
val intent = Intent(this, HomeActivity::class.java)
startActivity(intent)
finish()
}
}

fun saveUsername() {
/*Simpan Nama User ketika klik button Save */
session.savePrefString(session.yourUsername, usernameUser)
/*Simpan pernyataan bahwa sudah menyimpan session username*/
session.savePrefBoolean(session.isSession, true)
val intent = Intent(this, HomeActivity::class.java)
startActivity(intent)
finish()
}
}

Setelah itu Kita modifikasi juga source code bagian HomeActivity.kt sebagai berikut.

import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.nandaadisaputra.simpleencryption.R
import com.nandaadisaputra.simpleencryption.data.Session
import com.nandaadisaputra.simpleencryption.databinding.ActivityHomeBinding
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

//Karena Kita pakai DI Hilt jangan lupa tambahkan anotasi
//@AndroidEntryPoint pada setiap class Activity
@AndroidEntryPoint
class HomeActivity : AppCompatActivity() {
//Karena Kita sudah pakai DI Hilt maka Kita dapat memanggil session
//dengan cara @Inject
@Inject
lateinit var session: Session

/*Kita deklarasikan juga binding yang akan Kita gunakan*/
private val binding: ActivityHomeBinding by lazy {
DataBindingUtil.setContentView(this, R.layout.activity_home)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/*inisialisasi dulu activitynya*/
/*wajib karena Kita memakai DataBinding*/
binding.activity = this
binding.lifecycleOwner = this

// //mendapatkan username dari session
// kemudian disampungkan dengan layout
binding.tvHallo.text = "Hallo ${session.getUsername()}"
}

fun logOut() {
//Ketika button logout ditekan maka simpan pernyataan bahwa session terhapus
session.savePrefBoolean(session.isSession,false)
//Setelah session terhapus maka akan masuk ke MainActivity.kt
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}
}

Sebelum Kita running Kita cek dulu bagian AndroidManifest.xml karena secara default penambahan class baru seperti HomeActivity.kt akan error.

Nah di android:name=”.HomeActivity" akan error maka Kita perlu modifikasi menjadi sebagai berikut.

<activity
android:name=".ui.HomeActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>

Kemudian Kita akan running aplikasinya.

Setelah Kita running , kemudian Kita inputkan username dan klik button save, maka akan menyimpan session dan menampilkannya di halaman home sebagai berikut.

Silahkan keluar aplikasi tanpa klik button clear, maka akan masuk aplikasi tanpa harus input username lagi. Nah, itu artinya session tersebut masih tersimpan di SharedPreference. sesuai source berikut ini

//Periksa apakah sudah ada session yang masih tersimpan atau belum
if (session.getIsSession()) {
//Jika sudah ada session yang masih tersimpan maka
//akan langsung masuk halaman HomeActivity.kt
//Jika belum ada session maka akan masuk halaman ini
//MainActivity.kt
val intent = Intent(this, HomeActivity::class.java)
startActivity(intent)
finish()
}

Kita akan melihat session yang tersimpan di SharedPreference. Caranya yaitu dengan klik Device File Explorer -> data -> data -> nama package -> SharedPreference.xml

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="Username">Nanda</string>
<boolean name="Session" value="true" />
</map>

Pada gambar diatas data dapat terlihat dan bisa dibaca dengan mudah tanpa ada enkripsi.

Nah , Kita akan melakukan enkripsi data yang masuk ke session tersebut.

Pertama tama Kita modifikasi terlebih dahulu bagian Session.kt. Hapus source code dibawah ini yang ada didalam Session.kt

private var pref: SharedPreferences =
context.getSharedPreferences("Session", Context.MODE_PRIVATE)

Gantilah source code diatas dengan source code dibawah ini

 private var pref: SharedPreferences = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val spec = KeyGenParameterSpec.Builder(
MasterKey.DEFAULT_MASTER_KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setKeySize(MasterKey.DEFAULT_AES_GCM_MASTER_KEY_SIZE)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()
val masterKey = MasterKey.Builder(context)
.setKeyGenParameterSpec(spec)
.build()
//EncryptionSharedPreference adalah nama file shared preference.
EncryptedSharedPreferences
.create(
context,
"SharedPreference",
masterKey,
//algoritma AES GCM 256
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
} else {
SecurePreferences(context)
}

Sehingga keseluruhan code bagian Session.kt akan menjadi sebagai berikut ini.

import android.content.Context
import android.content.SharedPreferences
import android.os.Build
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.securepreferences.SecurePreferences

class Session(context: Context) {
val yourUsername = "Username"
val isSession = "Session"

private var pref: SharedPreferences = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val spec = KeyGenParameterSpec.Builder(
MasterKey.DEFAULT_MASTER_KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setKeySize(MasterKey.DEFAULT_AES_GCM_MASTER_KEY_SIZE)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()
val masterKey = MasterKey.Builder(context)
.setKeyGenParameterSpec(spec)
.build()
//EncryptionSharedPreference adalah nama file shared preference.
EncryptedSharedPreferences
.create(
context,
"SharedPreference",
masterKey,
//algoritma AES GCM 256
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
} else {
SecurePreferences(context)
}
private var editor: SharedPreferences.Editor = pref.edit()

//Untuk Menyimpan session bertipe String
fun savePrefString(key: String, value: String) {
editor.putString(key, value)
editor.commit()
}

//Untuk Menyimpan Pernyataan sudah ada session atau belum
fun savePrefBoolean(key: String, value: Boolean) {
editor.putBoolean(key, value)
editor.commit()
}

//Untuk mengambil session Username
fun getUsername(): String? {
return pref.getString(yourUsername, "")
}

//Untuk Mengecek apakah ada session atau tidak
fun getIsSession(): Boolean {
return pref.getBoolean(isSession, false)
}
}

Catatan : Jetpack Security hanya berjalan di API 23 (Marshmallow) ke atas, Nah, agar Kita dapat terhindar dari error “Manifest merger failed : uses-sdk:minSdkVersion 16 cannot be smaller than version 23 declared in library”. Silahkan dapat Kita tambahkan source code berikut ini pada AndroidManifest.xml:

<uses-sdk tools:overrideLibrary="androidx.security"/>

Sehingga keseluruhan source code yang ada di AndroidManifest.xml akan menjadi sebagai berikut.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-sdk tools:overrideLibrary="androidx.security"/>

<application
android:name=".base.App"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SimpleEncryption"
tools:targetApi="31">
<activity
android:name=".ui.HomeActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".ui.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>

</manifest>

Setelah itu Kita unistall aplikasi yang sebelum Kita install untuk menghindari cache .

Setelah itu running kembali aplikasi yang sudah Kita tambahkan enkripsi . Kemudian inputkan username dan klik save.

Selanjut nya Kita akan melihat session yang tersimpan di SharedPreference kembali. Caranya yaitu dengan klik Device File Explorer -> data -> data -> nama package -> SharedPreference.xml.

Maka akan ditampilkan teks yang sudah terenkripsi seperti yang ada pada gambar dibawah ini.

Sekarang data kalian sudah terenkripsi dengan baik , sehingga tidak dapat terbaca dengan mudah oleh pengguna lain. Apalagi data tersebut juga akan selalu berubah ketika Anda memasukkan/mengganti data baru untuk keamanan.

Untuk source code lengkapnya bisa dilihat melalui link github berikut ini ya temen — temen

Silahkan follow juga Linkedin Saya untuk saling membangun koneksi dan relasi : https://www.linkedin.com/in/nandaadisaputra/

Sekian tutorial singkat dari Saya. Jika ada pertanyaan silahkan tinggal kan kalimat di kolom komentar, semoga bermanfaat…

--

--

No responses yet