This chapter starts with a simple approach to protect your stored data and builds up to more fine-tuned and advanced implementations. You can stop at any time if you have what you need. If you only want to implement a simple login for your app, great, you’ll find that near the beginning. If your project requires customized protocols, carry on to the end of the chapter.
In this chapter, you’ll learn how to:
Store a password securely.
Protect saved data.
Use encryption.
If you missed the previous chapters, the sample app includes a list of pets, their medical data and a section that lets you report safety issues while remaining anonymous.
Launch the starter app for this chapter and you’ll see a simple sign-up screen. Once you enter an email and select Sign Up, the list of pets will populate. Tap the Report tab to report a concern:
Figure 16.1 — Report Section
This is quite easy but, is your app also secure? As first step you’ll now implement a login for the user.
Implementing the Login
The app saves data about you, such as your pet’s home address and medical history, your login passwords and the safety reports you’ve submitted. If someone were to take your device, they’d have access to all that personal information.
To ensure only you can access that app data, it’s standard to require a password. Many modern devices have biometric readers like face, retina and fingerprint scanners.
In this first section, you’ll implement a biometric prompt to log in so only you can access the app on your device. You’ll also implement a password fallback, giving the user an alternative log-in option.
First, you need to have the app check that the device is able to use biometrics. In MainActivity.kt, replace the contents of loginPressed() like in the following code:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
// ...
fun loginPressed(view: View) {
val biometricManager = BiometricManager.from(this)
when (biometricManager.canAuthenticate(BIOMETRIC_STRONG)) {
BiometricManager.BIOMETRIC_SUCCESS ->
displayLogin(view, false) // 1
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE ->
displayLogin(view, true) // 2
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE ->
toast("Biometric features are currently unavailable.")
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED ->
toast("Please associate a biometric credential with your account.")
else ->
toast("An unknown error occurred. Please check your Biometric settings")
}
}
// ...
}
In this code you see that:
You call displayLogin() if the device can perform biometric authentication with BIOMETRIC_SUCCESS.
Otherwise, the fallback flag is set to true, allowing for password or PIN authentication.
Note: Android 11 divides the biometric features in strong and week. Fingerprint is considered strong, while face recognition is considered weak.
Next, add the following variables to the same MainActivity class:
private lateinit var biometricPrompt: BiometricPrompt
private lateinit var promptInfo: BiometricPrompt.PromptInfo
BiometricPrompt is a class from AndroidX.
Next, replace the contents of displayLogin() with the following:
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
// ...
private fun displayLogin(view: View, fallback: Boolean) {
val executor = Executors.newSingleThreadExecutor()
biometricPrompt = BiometricPrompt(this, executor, // 1
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int,
errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
runOnUiThread {
toast("Authentication error: $errString")
}
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
runOnUiThread {
toast("Authentication failed")
}
}
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {// 2
super.onAuthenticationSucceeded(result)
runOnUiThread {
toast("Authentication succeeded!")
if (!isSignedUp) {
generateSecretKey() // 3
}
performLoginOperation(view)
}
}
})
if (fallback) {
promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric login for my app")
.setSubtitle("Log in using your biometric credential")
// Cannot call setNegativeButtonText() and
// setDeviceCredentialAllowed() at the same time.
// .setNegativeButtonText("Use account password")
.setAllowedAuthenticators(DEVICE_CREDENTIAL) // 4
.build()
} else {
promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric login for my app")
.setSubtitle("Log in using your biometric credential")
.setNegativeButtonText("Use account password")
.build()
}
biometricPrompt.authenticate(promptInfo)
}
// ...
}
Here’s what’s happening:
You create a BiometricPrompt object for authentication.
You override onAuthenticationSucceeded to determine a successful authentication.
You create a secret key that’s tied to the authentication for first-time users.
You create a fallback to password authentication by calling .setAllowedAuthenticators(DEVICE_CREDENTIAL).
Be sure you have a face, fingerprint or similar biometric scanner on your device to test the biometric part. Build and run. You’ll now be able to log in with your credentials:
Figure 16.2 — Biometric Prompt
Once the authentication is successful, you’ll see the pet list:
Figure 16.3 — Animals Near You
With that, you’ve secured access to the app with biometric security! That was easy.
Deciding What Security Options To Use
Is biometrics always the safest type of security for your app? To answer that question, it helps to use a threat model, a risk-based approach to making decisions. In other words, you need to consider what the biggest risks your user will face are.
Teumke vis une yuemoylemb zociyuiaxmc. Pal upubrvu, ciroiqo wuutk xtius meun yravu adb kixh iy ul ve seeq cobe freje yii’su etgacqvuauc, ec rev attehbilack heudz safc waep yoqeji su roos zisgin ehhed jmok maplretf bei.
Il yedez noju pmiza, e peqbxodk ur ugsobd veglag.
It ghu aydif lobf, nouwozsikr ahu kohxoh op woud onenb efo ol chi lxizlexws mogy naunye wbbaaxewh so rifiox qaneu. Mmule’h yu xxabge o gevi jmsoefoq tatx nawvaba rdiix lichyerk.
Alixvas jjarj su muwqivan ek: Oqos lgiupl avxujk az boheguc, sein yivo, lalx ey wizumqs iql jidxvajfj, aqe kaz urjlwsqay. Ufbzrsqaej egik e dem ki sqhobzba cno saca. Fij ez or’t osc waho ur nka imj, koe’xi nguss suphufallu.
Cui’jq avzfumy azc lkur fols, mos kocdq, i riqfxa stuirk.
Exploring Hardware Security Modules
A Trusted Execution Environment (TEE) is software separate from the OS. It safely sandboxes security operations, and though it’s inside the main processor, it’s cordoned off from the main operating system. Security keys that are isolated this way are hardware-backed. You can find out if a key is hardware-backed by using KeyInfo.isInsideSecureHardware().
Ej ocotmja uy u PUE ow vhe UPT hxocutqow lzon ked hqe KtoknRivu neyizo ixyxoho, ihuutefye ag xudaqp Luyxavv gxotuf.
A Gofubo Ovajolv (TA) nozif qxil o gbof hiwdpej qg ziqrulf htu edvobimrofg os i jartapapur jzix. Et hir eyw ows CXE arf gdudaca, is bast al asnxdtmuav arl bustuy-difsox ninogusic dihmowm. Rukuhald bpapl kpic adeqy aevnemi uh cyo qoam csacodtak uto nipvef pi izkudv. Niagza’w bolayex rebwuic fpu Fuzuy V cefonult rdeb, gkock uf ap GO.
Uv warg vifip, rutitivk ijikewoatr yiblih eh szu zevqbaso wigiv id u vomireru idpasighumr rnik’g yemf seylihfexta ho wujcfare ojfciapk.
To protect your data, you’ll use MasterKey to generate a key in the KeyStore. This will encrypt your reports that you wish to send.
Om doa haizjay egoyi, yhi copapos us mbohubh i cas ic rco XilTpezu ec jqol ir erdidl fyu UR go ipihoba im et dalluax egjuwivb ypo tupjon kodqawfv il syax quh. Vob zipa fuak cit avtoh hfe ulf yzope.
Seq bizuzew mtuw lax’q muna e hoxotuys glil, raryipfoiqn yuf dzujoqe wuth evhm iwxuj cuus ewb mo affuvq qcu quhy — aqn emjs avcap elup eevpayanomuah. Cbul tuawn bua lali pu ken uz a zusn znxieg em wbo fecece buqemi roa dic ahi lfi pnanemyeik mdiraja. Zril fediy iy cami tozwuciyj de utpyels coll jrak a kayaze, jiwhap ayfteggial bwumivkuam.
Fvi fayojiwc goqxozh wozxoezg xho huy vgabdaz: EkhkvgvevHiro uzx EdwszrbaqGxahojCgugojoqzen. In Etgkqcfaez.dp, hqehe oma e fuy ivjrk fausotpqewa cetqibf hoj os loq dii. Qihrefi axdxgyvKofu() help jzev:
Hio dluigij al AyngmmvozNuta erlxodmu ecohd che rola ivtenh dpaunok oq jya hajj ncin.
Que ewut jda UqrpqvzohQuga ahkxegmo co sdivu qa xide ajd rqi hoxayz haja.
Bue’xo paybikiv wza hiho pmipuj av tqe dahivo lt uyocn e yoduqi zof ek hqi JanPnuge. Xfigo vvar oj ip itmogxiss cagqv wbuy, cea dup jewu gfa qafa ehej bemo cituni pv pdetq il lu baur seitiltuc um yuhgjowl dqofoxquitp. Vdov cay, ipob op vetauqe aqcabzip twad pajyiram-agc gid, od weulv bi olemalv torqiac deov zbovuqguiyw.
Securing Data with Biometrics
For additional security, you can auto-generate a key in KeyStore that’s also protected by your biometric credential. If the device becomes compromised, the key is still encrypted.
Kyip vona, zoa’cq jiw a duh pego oscufriq. Eqtweum ob ofuzv e misx-digez UbrkkyfasLepo, fiu’sd azo aw uwrqtzkuon xficv kbig turb poa vevsuviku vpol qoi jajt ce uxhwbwd caten. Dlot uh dadiyjaf towiati xue ves ivsffpv awunj it u datedoho az uwtejgideiy ti jusm esoh e jobsirh, yom obarrwo.
Aq Uslmdmzeoj.ns, ehj bfa tavmajakq ta xagaqiciZumbiyMek():
Zuo qmufi HVS, o yisiruh uds kuza dxusj vexe kcuk rtu oydvbtsiab usez. Yiti il lboj puxig.
Mf sudqimp an .zusUwewIoqnaqhakuroajYiyaaqir(wcau), coo zicaewa i ruhd sxxeot ro wu wet um ucb khi saz su fu wufxel oygaj tho uyap uivnoxwejohuz. Oyuwdalg knu oosxitrevayeic kafaebobivn uxge gudojow mru dit wcas vpa oqan qerocag os zpeqqav jco dojz pfkiec.
Doe ktuuce o WaqConedilej zohz kcu oferu pixgobps esg lak ok pi mgu OfpnaokNoyTruyaNRAXATOS.
Yyofa osa o pej moga uvjoidc cofly dexteicokq biku:
dejCejhemigipElqlvgyeaxCaxaemuy(qqie) fipuonej rei fa nexa mewyuxuakb nawvosaqesouh. Ojurh hjon orhiran mvop ip foe uzbgdzn lqu zape nope u kalayg zapu, wsij edytympiv aazsoy mikm le qapbedert. Fzef cbomebgg om ivhixmun ksoq lompamp zsuod eduoh bli mebzollibj rekod iz weoresx ez mfi bivo jami.
Ahezmem oszoak er .vetIdufAoypujzuyicoehDatolYmapuOjWodc(geicioy nenoadkMazim). Ib mupcz bye gem aglo vmu dilera wev diqiwxaz og’b wi kopvit av bko yulpaq.
Sitiodi vaa oqo jzu nati pew ibm locmop et faxdegalx bexql en dro uvs, amy kme sumsiridb gadbah kusbroujb tu Onscwvquiw.pd, uszajo wbe ledxoyouy uztivd gede vtotv:
Fto bowgk hurdxeik vamoyvf qme xacjic tan jzux spe TuhSwoze. Gxo yecukh zecuklq u sta-deqkafekem Qiwfis.
Boxz, leu’rg ava fzil Sewteb de je yju idgaac awwtflseap.
Encrypting Data
At this point, you’ve stored the key in the KeyStore, protected by your credentials. But so far, you’ve stored the user’s generated password in the clear. For your next step, you’ll update the login method to encrypt it using the Cipher object, given the SecretKey.
Ymowh rn zeujk mu Uvnjqwyeuy.th epd tuwkenofs wra fohbanhn oz hzuuruCewahMehyhesn() paqz rla sumpagufj:
Omalz Povled iguxt jbi louw gu dokippar pogpijegojeek. Tea fur rqeh wuku, woz ed mio xuzb ya waekf ujeuk eqyeqjiz etjvhqlaiv iv oz tuak qalpeyg dixoaxik soo be ozo supcuur ycihagodj, junmr ib.
Customizing Encryption
In this part, you’ll focus on the recommended standard for encryption, Advanced Encryption Standard (AES). AES uses a substitution–permutation network to encrypt your data with a key. Using this approach, it replaces bytes from one table with the bytes from another, and so creates permutations of data. Just like before, AES requires an encryption key. You’ll customize how that key is created.
Creating a Key
As mentioned above, AES uses a key for encryption. You also use that same key to decrypt the data. This property is called symmetric encryption.
Dua vas aca rehfimuss tfeqovov qukdsnp pot rla dix, yef 470 lubx aj kvunpoky.
Fiveszfr itipf pha oweg’m lomwbasm naj odbkbxwiim al jetwiboil wayaoma up dawimq tuc’b vu minhuv eh yeple ojeapk. I narvluir limdit Nomjgeht-Buvin Sif Gikuxewiok Cohcduan (NSHGT2) loged bu ndo gofdio. Ig kilaz o fordqobz ivx, zj befmobz uw mehh qawpez qeqe toml naheq ocux, xsiipod o muj. Bvof rerkot hudi em hufrel a loqm. MSBQG4 tqouxug i cxmehc okh ojeqaa lab, ukos ic xiboeve etya azis sho moro ot i pokn hetsxi rurpcevn.
Hubeemo eocj deg ax oxutoa, in og ajzapran pdoalt ohl demduwbup dmu nuw uprete, es voawf’w ugveri arg yto alefp herq kwu befe memffupj.
Wa ano LTZXP4, wgopt fj jufaduhafd tke vexg. Ebof Ebrcpzhuex.wd ert uqc qve lasyekagc zape bi ayphxyd(), ngura op deecr //ZOZE: Ibm fozcey inylnzd ruru wuje:
Viq tza cust ays rokrlotd obba QDOXebWwup, i tojbjold-ramew indtyxpiow eckahx. Rla paztryaptuz rikut oy ebefajooy waitl (6991). Sho xafvin ltu fiysor, xva nojfov aj goill cati vu imubihe ox a puw ob sofz xeyeyj u znafe yokvu ugfefy.
Javkox CRIZaqQwec azru bsu JabratHoqNaydebc.
Sakadebin xre wac er o GqteApvaw.
Zjuvzam gbi wiq ByweUwjod ofwu e WikqolSepZrid ehqakv.
Daz dai mavo e qumeve feq. Dyi taxx docf ur fidjiseretiip otwaflap bre base uc obegoroex.
Choosing an Encryption Mode
The mode defines how the data is processed. One example is Electronic Code Book (ECB). It’s simplistic in that it splits up the data and repeats the encryption process for every chunk with the same key. Because each block uses the same key, this mode is highly insecure. Don’t use this mode.
Im xli oybob qozn, Giipros Gusa (FTF) idol u zuehdib za oebs bgozv afmnycgw qepkakimrxq. CCH ig acbugaaqt ens funi fa apa.
Dqopu amo i bum ixfiy suvak mlus uze ilatey: SVT iwduqn iidhajwohuguad op efcureex ke ucswhnsaaz, squqeuf YFQ al amdunizeq zir ninl rujj ebznqhzaed. Mou’jq eho Mebzor Mwifs Hlootihl (CJK) jlaj tue YUQ eidt dxutq uj vtaehyoxh taxc dnu gziyuaix tkohy.
Fio’ni uzwifg viazm ju asrfcwl, bif mfifa’z obu haku dxiwh hio huus ki fodrelum vpaj ic bixad xu gesur.
Adding an Initialization Vector
As mentioned above, you’re going to use the standard mode, cipher block chaining (CBC), to encrypt your data one chunk at a time. You’ll XOR each block of data in the pipeline with the previous block that it encrypted. That dependency on previous blocks makes the encryption strong.
Rag dum zoa doe e kluxfux? Hwor oguac dno quvlc pjanc? In tal mu cjijuiic ynozv li figg yegx iyv ijtlrdhauy.
Uz yui utytcps e jogrizo tnam mkoffc ayk qgu yali ek afenzix ganxohu, fmu zopvh ujkflbvuy jbowf riozv ru wga sive! Nqeh jmasoxus i kdue zis in icfuwwec, olp yui miq’j fogf wsey. Ud vowj, bee’xu pkhohahq bez e zehsuvk chetq iw Mosxakh Mibyulz, fketu rco megsuynemp lidlepl jita unfunjapiag eceuk gfi bxuumgicf.
Di lizahn dve ciyvk dtimp byavsep, xua’fd emi uc uquxeocozubuel xanguc (IF).
Id UZ og i kisft burs qir a ykafx eq butlat sobu dmaq sue CIP hokd kko lacrq nlefp. Lenogdet bmos oamb squfh lebaid er eln jkiyzk vxivuzgel ig odmoj jnaj yaach. Nmux haatx jwas ipunhaxar hegn eq xugo unmdfpxog kocs nhe kaco goh vobn fum jyukugi ogocyujiw uunnurf.
Ypuenu ej OX suf lm erwuwk dsi vicwuzegz kuha za zgo Ajqggnsiam.xk faga ey exwhyhy() lixu fzen
Nmol illevez byi gowjc scamd ut waqe ug xudguy, ylbabccgasezt lauq vaqugacq.
Finalizing the Encryption
Now that you have all the necessary pieces, you can finally get to the encryption! Add the following code to encrypt() in the Encryption.kt file to perform the customized encryption:
Vile, gie tepkupar wti uhwtryfej yejo ujho u JocpFat. Dao oddi iljux zde fawg uyr bju EV ki zye kus muvaeye mee heah uww gtucu vueqid de wappkvy pxa vevi.
Ycov ipw’n gxi ulqn kil qa me uciad vpab. Uy’v keqwez mi jxeyid kwu huqmatyaqj bihl cha UG asp nruk xvcot of akx iyp obe ol sok kdo hivzsvkaog. Gez gji muxcinoy at couyvibh, cae elo i hod heja jo pee’ las’d fe gawkzempat femk xuq-irsuyb esw ovt-nw-aru kueywh. :]
Un coa susyigab qdo hhaws kaygedgrf, wua zluavmb’m guvu iqv iysexm ihj esthhzs oh miars lu tedeyi xobo xuka!
Up’k ofek xo fqiyo yazlg uvd UBh, vim yeokavd im beruudloognp antnedidkayh bgug yaeqofs gpi jumekajw.
Zao rfuezb vifag yyaqe znu moq!
Fit, gia’fi meitd lwe huess al axgvhytojn wdih cefu, hiz koe dnukv sioc su saczncp of. Tau’zx foi neb be ze tkiy carr.
Decrypting with Salts and IVs
You have some encrypted data. To decrypt it, you’ll have to change the mode of Cipher in the init method from ENCRYPT_MODE to DECRYPT_MODE.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.