Skip to content
This repository was archived by the owner on Apr 25, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
compileSdkVersion 27
compileSdkVersion 29

defaultConfig {
applicationId "dk.nodes.locksmith.example"
minSdkVersion 21
targetSdkVersion 27
minSdkVersion 23
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

vectorDrawables.useSupportLibrary = true
}
Expand All @@ -30,20 +30,21 @@ android {
}

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:1.2.31"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:design:27.1.1'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0'

implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

implementation project(":locksmith")
implementation project(":biometric")

implementation 'com.android.support:support-v4:27.1.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'

androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package dk.nodes.locksmith.core.example

import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package dk.nodes.locksmith.example.activities

import android.os.Build
import android.os.Bundle
import android.support.design.widget.TabLayout
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import com.google.android.material.tabs.TabLayout
import dk.nodes.locksmith.example.R
import dk.nodes.locksmith.example.fragments.BiometricEncryptionFragment
import dk.nodes.locksmith.example.fragments.EncryptionFragment
import dk.nodes.locksmith.example.fragments.FingerprintEncryptionFragment
import kotlinx.android.synthetic.main.activity_main.*
Expand All @@ -15,13 +16,17 @@ class MainActivity : AppCompatActivity(), TabLayout.OnTabSelectedListener {
private val tag = MainActivity::class.simpleName
private val tabEncryption = "Encryption"
private val tabFingerprintEncryption = "Fingerprint Encryption"
private val tabBiometricEncryption = "Biometric Encryption"

private val encryptionFragment: EncryptionFragment by lazy {
EncryptionFragment()
}
private val fingerprintEncryptionFragment: FingerprintEncryptionFragment by lazy {
FingerprintEncryptionFragment()
}
private val biometricEncryptionFragment by lazy {
BiometricEncryptionFragment()
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -44,6 +49,11 @@ class MainActivity : AppCompatActivity(), TabLayout.OnTabSelectedListener {
fingerprintTab.text = tabFingerprintEncryption
fingerprintTab.tag = tabFingerprintEncryption
mainTabLayout.addTab(fingerprintTab)

val biometricTab = mainTabLayout.newTab()
biometricTab.text = tabBiometricEncryption
biometricTab.tag = tabBiometricEncryption
mainTabLayout.addTab(biometricTab)
}

mainTabLayout.addOnTabSelectedListener(this)
Expand All @@ -59,20 +69,25 @@ class MainActivity : AppCompatActivity(), TabLayout.OnTabSelectedListener {
setCurrentFragment(fingerprintEncryptionFragment)
}

private fun showBiometricEncryptionFragment() {
Log.d(tag, "showFingerprintEncryptionDialog")
setCurrentFragment(biometricEncryptionFragment)
}

private fun setCurrentFragment(fragment: Fragment) {
supportFragmentManager.beginTransaction()
.replace(R.id.mainFragmentContainer, fragment, fragment.javaClass.simpleName)
.commit()
.replace(R.id.mainFragmentContainer, fragment, fragment.javaClass.simpleName)
.commit()
}

override fun onTabSelected(tab: TabLayout.Tab) {
Log.d(tag, "onTabSelected ${tab.text}")

when (tab.tag) {
tabEncryption -> showEncryptionFragment()
tabEncryption -> showEncryptionFragment()
tabFingerprintEncryption -> showFingerprintEncryptionDialog()
else -> {
tabBiometricEncryption -> showBiometricEncryptionFragment()
else -> {
Log.d(tag, "Else tab selected")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package dk.nodes.locksmith.example.dialogs
import android.content.Context
import android.os.Build
import android.os.Handler
import android.support.annotation.RequiresApi
import android.support.annotation.StyleRes
import androidx.annotation.RequiresApi
import androidx.annotation.StyleRes
import android.view.View
import android.widget.Button
import android.widget.TextView
Expand Down Expand Up @@ -33,6 +33,7 @@ class CustomFingerprintDialog(context: Context) : FingerprintAlertDialogBase(con


private fun setupViews() {
val window = window ?: return
tvTitle = window.findViewById(R.id.dialogCustomFingerprintTvTitle)
tvDescription = window.findViewById(R.id.dialogCustomFingerprintTvDescription)
tvSubtitle = window.findViewById(R.id.dialogCustomFingerprintTvSubtitle)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package dk.nodes.locksmith.example.fragments

import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.View
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import dk.nodes.locksmith.BiometricCryptManager
import dk.nodes.locksmith.BiometricEncryptionManager
import dk.nodes.locksmith.core.encryption.handlers.EncryptionHandlerImpl
import dk.nodes.locksmith.core.encryption.providers.AndroidKeyProviderImpl
import dk.nodes.locksmith.core.encryption.providers.KeyProvider
import dk.nodes.locksmith.core.exceptions.LocksmithException
import dk.nodes.locksmith.example.R
import kotlinx.android.synthetic.main.fragment_encryption.*
import java.util.concurrent.Executor
import javax.crypto.Cipher

class BiometricEncryptionFragment : Fragment(R.layout.fragment_encryption) {

private val defaultData = "Mary had a little lamb\n" +
"It's fleece was white as snow, yeah\n" +
"Everywhere the child went\n" +
"The lamb, the lamb was sure to go, yeah"

private var encryptedData: String = ""

private lateinit var executor: Executor
private lateinit var biometricPrompt: BiometricPrompt
private lateinit var promptInfo: BiometricPrompt.PromptInfo
private var keyProvider: KeyProvider? = null
private var biometricManager: BiometricEncryptionManager? = null

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
encryptedData = defaultData
fragmentEtData.setText(defaultData)
setupBiometric()
setupListeners()
}

private fun setupListeners() {
fragmentTvData.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
encryptedData = s.toString()
}

override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})

fragmentBtnEncrypt.setOnClickListener {
encryptData()
}

fragmentBtnDecrypt.setOnClickListener {
decryptData()
}
}

private fun setupBiometric() {
executor = ContextCompat.getMainExecutor(requireContext())
biometricPrompt = BiometricPrompt(this, executor,
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
}

override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
biometricManager = BiometricEncryptionManager(
EncryptionHandlerImpl(
object : AndroidKeyProviderImpl(true) {
override fun getCipher(): Cipher {
return result.cryptoObject?.cipher!!
}
})
)
}

override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
}
})

promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric login for my app")
.setSubtitle("Log in using your biometric credential")
.setNegativeButtonText("Use account password")
.build()
}

private fun decryptData() {
if (biometricManager == null) {
biometricPrompt.authenticate(promptInfo)
} else {
try {
encryptedData = biometricManager!!.decryptString(encryptedData)
updateTextView()
} catch (e: LocksmithException) {
handleException(e)
}
}
}

private fun updateTextView() {
fragmentTvData.text = encryptedData
}

private fun encryptData() {
if (biometricManager == null) {
val b = BiometricCryptManager()
biometricPrompt.authenticate(
promptInfo,
b.getCryptoObject()
)
} else {
try {
encryptedData = biometricManager!!.encryptString(encryptedData)
updateTextView()
} catch (e: LocksmithException) {
handleException(e)
}
}
}

private fun handleException(e: LocksmithException) {
Log.e(tag, "handleException")
e.printStackTrace()

when (e.type) {
LocksmithException.Type.Initiation,
LocksmithException.Type.Uninitiated -> {
Log.e(tag, "Uninitiated")
}
LocksmithException.Type.Unauthenticated -> {
Log.e(tag, "Unauthenticated")
}
LocksmithException.Type.InvalidData -> {
}
LocksmithException.Type.EncryptionError -> {
Log.e(tag, "Encryption error")
}
LocksmithException.Type.Generic -> {
Log.e(tag, "Generic", e)
}
}
}

private val KEY_NAME = "LockSmithBiometricEncryptionKey"
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package dk.nodes.locksmith.example.fragments

import android.os.Bundle
import android.support.annotation.StringRes
import android.support.design.widget.Snackbar
import android.support.v4.app.Fragment
import androidx.annotation.StringRes
import com.google.android.material.snackbar.Snackbar
import androidx.fragment.app.Fragment
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package dk.nodes.locksmith.example.fragments

import android.os.Build
import android.os.Bundle
import android.support.annotation.RequiresApi
import android.support.annotation.StringRes
import android.support.design.widget.Snackbar
import android.support.v4.app.Fragment
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import com.google.android.material.snackbar.Snackbar
import androidx.fragment.app.Fragment
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
Expand Down Expand Up @@ -123,7 +123,8 @@ class FingerprintEncryptionFragment : Fragment(), OnFingerprintDialogEventListen
showSnackbar(R.string.errorInvalidData)
}
EncryptionError -> {
showSnackbar(R.string.errorGeneric)
showDialog()
Log.e(tag, "Encryption error")
}
Generic -> {
Log.e(tag, "Generic", e)
Expand Down
12 changes: 6 additions & 6 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:id="@+id/mainRootContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.MainActivity">

<android.support.design.widget.AppBarLayout
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">

<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/mainToolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="?android:attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />

<android.support.design.widget.TabLayout
<com.google.android.material.tabs.TabLayout
android:id="@+id/mainTabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/colorPrimary"
android:minHeight="?android:attr/actionBarSize"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

</android.support.design.widget.AppBarLayout>
</com.google.android.material.appbar.AppBarLayout>

<LinearLayout
android:id="@+id/mainFragmentContainer"
Expand All @@ -36,4 +36,4 @@
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Loading