FULL Guide to Encryption & Decryption in Android (Keystore, Ciphers and more)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys and welcome back to a new cryptographic android video yes i will do some security related android videos because i realized i don't have that on my channel yet and security is of course very important and most of these security related videos will in the end deal with data so in the end encrypting and decrypting data that is also what we will start with today so you will learn how you can actually encrypt a string in android how you can decrypt it you will learn about the android keystore system what that is and how we can actually use it to safely save our keys so just a quick demo here what we will actually build and that is a very simple app where we can enter some kind of string in our text field here and we can then encrypt that and decrypt that so for example hello youtube we can say encrypt you can see that is our encrypted string of course not readable for us if we then close our app we reopen it and now click decrypt we will actually decrypt our saved string so we get hello youtube again and i will also like to show you that this is really uh encrypted so we will save the encrypted content of that string in a separate file where we will then read it from again so much for demonstration of this app before we actually jump into coding a little bit of theory first which is important to understand about the android keystore system so when it comes to encryption and decryption it is very similar as with your house at home so if you have the key for your door then you can actually enter it you can close it and someone else who also gets that key can actually do the same so they can also access your house or they can also lock it and when it comes to encryption decryption is actually the same so there we also have such a key and anybody who gets this key can actually also encrypt and decrypt or rather just decrypt what you encrypted with that key in terms of computers such a key is in the end just a long series of zeros and ones or just long by the way now we have a challenge of course where do we actually store such keys so for example if you have a password in your app that you want to save then of course nobody else other than your app should be able to retrieve that password but if you actually use a key to actually encrypt that password and save that encrypted string then anybody who gets that key can also decrypt that password so where do we actually put this key in android so in general you could think about putting that in the internal storage of your app internal storage means that is the power of the storage only your specific app can actually access no other app however as soon as your device or your android phone actually gets rooted that means that the attacker tries to get access to the whole operating system to basically get root privileges then they can pretty much access the whole storage of all apps including all the internal storage including all shared preferences and all that stuff so in that case if you save the key in internal storage share preferences or whatever then an attacker will be able to easily retrieve that if they actually get root access to your device and as a solution for this problem there is the so-called keystore system and the goal of the keystore system is actually to prevent an attacker from extracting your keys out of the android device so that doesn't mean that the attacker can't use the keystore system to actually decrypt and encrypt with your keys that still works if they have root access and basically access to your whole operating system and you can also not prevent that because if they have root access they can do whatever they want but what they can do is they can't actually read the key and extract it out of the device to do some other stuff with it let's talk about how android actually accomplishes that that it completely prevents an attacker from gaining access to your keys and actually extracting them out of your android device and the way this is solved is with a specific hardware which is usually called like a tee so trusted execution environment and this is basically a separate hardware part that is not part of the android operating system so the android operating system even if you have root access to that you don't have that root access to that separate hardware part which manages the key store and if for example you now have an app for example the one we will build here then we will have such a key that will be stored in this separate hardware part of our android device and our app can actually request decrypts and encrypts using the android operating system so we can say hey we actually want to encrypt this string this will go to the end rating system the android operating system will then kind of form that request to the keystore system to actually kind of on the one hand save a key which will never leave the keystore system and on the other hand to actually just uh encrypt our string with that so to summarize a keystore actually can't prevent an attacker from using our keys nothing can really prevent that but the purpose is to actually prevent an attacker from extracting our keys from the android system so in the end they won't be able to actually use our keys and use them somewhere else outside of our android device so i would say we actually get started with coding here and to actually be able to encrypt and decrypt i will create a little crypto manager class which will just manage all our all of our crypto stuff so crypto manager create that class here and inside of here we will write some functions and variables and we will actually start off with uh getting an instance of the key store getting access to the keystore by saying private val keystore is equal to keystore dot get instance and we need to pass a type the type on android will usually be android key store simply type it exactly like that and we want to say apply because we need to load this key store so we can simply say load and we don't pass any params so we can simply pass null here so that way we have a keystore instance and if we now want to use that if we say that and then you can see we get a bunch of functions we could store something here with this function we could get a key we could check if it contains a specific key or alias it's actually called um we can get an entry that would be whatever we save under specific alias and we will now use this here in this class to actually uh create a key and actually use that to encrypt and decrypt our string the first thing that's actually needed to be able to encrypt and decrypt is a so-called cipher so a cipher in the end just kind of um tells the our app how it should encrypt and decrypt our string so in the end we need to specify a crypto algorithm we want to use for encryption we need to specify uh yes some kind of block types and padding which is yeah just some kind of form how how the encryption should actually happen that is rather cryptographic stuff i won't get into here but let's actually specify some of these values you want to use here and a companion object you can say private cons val first one would be the algorithm we can set that to key properties dot key algorithm aes that is a common synchronous i mean symmetric encryption algorithm to actually just encrypt something using a key we actually need to add this recurse api m annotation so this is only available for android what is that marshmallow onwards we can also take this and put it here since multiple fields will actually require that we can then actually duplicate this four more times or three more times this one would be the block mode which will be set to block mode cbc we want to specify the padding so again those are just values that we can specify how the encryption should happen but if you choose these values then you're good to go here we're going to choose padding pkcs7 and the last one will be the so-called transformation which will basically just uh combine all these values that we specified here for our crypto algorithm in one string so we want to say dollar algorithm slash block mode slash padding and we'll just use these values here in our crypto manager class so as i said the first thing i want to do is we want to create a cipher and we need a cipher for encryption and decryption so let's start with our encrypt cipher which is equal to cipher dot get instance and you can see we need to pass this transformation which we created down below and we can then say dot apply and we need to initialize this cipher here with the init command the up mode is pretty much just saying what we want to do with the cipher so if it's an encryption or decryption cipher this one is an encrypt cipher so we can say safer dot encrypt mode and the second parameter we need to pass here is the key how do we get the key well we want to actually create that using a little function when i say private function create key this will return a so-called secret key and in here we will kind of generate that key and return it in that function and here we can say return key generator dot get instance here we need to pass the algorithm which we specified down below and we can actually can see there is a generate key function but we want to specify some um parameters for this key for this key generator so how we want this key to be generated by saying that apply and in here we can say init and we want this init with the params so we can say uh how is it called keyspec gen parameter spec dot builder and here we can now set one hand the block modes which is our block mode we specified down below we need to set the encryption paddings to our padding we specified down below we want to set user authentication occur to false i think this is actually related to biometric prompts so if you use a fingerprint in your app and you want to say that this key can only be accessed if the user is actually authenticated then you can use this and set this to true but we don't use this here so we can set it to false and we can say randomized encryption required so we actually randomize the encryption well the name already says that and say that build and then after apply here we can say dot generate key which you can see returns a secret key just like that so do we just want to take this create key function and put it in here well that would work but we actually first of all want to check if there is already a key in our keystore so we don't always want to create a new key when we actually want to encrypt something so what we want to say is when i have another function get key which will also return a secret key and it will first of all check if there is an existing key by using our keystore so keystore oops not that one keystore dot get entry and as i said the alias is basically what is used to ask the key store for our key so it's basically like a key in shared preferences you can think of we can say this is our secret key for example and the second parameter the protection parameter we can set that to null we don't need that and we want to cast that as a secret key entry actually as a nullable secret key entry and we can then return the existing key a dot secret key and if that's null we simply create a new key so just what we do here is we check if there is an existing key if so we return its secret key and else we create a new secret key and i'm just saying we need to pass something here what is that um oh we need to pass the alias again which is just secret again and the purpose is like what we want to do with this key is encryption and decryption so we can say key properties that purpose encrypt or key properties that purpose decrypt these two purposes we actually have with this key and then here instead of create key we can say get key and then we already have our encryption cipher now we also want that with the decryption cipher to actually also be able to decrypt something and this will actually be a function why would that be a function because it needs a parameter and the parameter is called an iv or initialization of vector an initialization vector is pretty much just what describes the initial state of our encryption and that is actually generated when we encrypt something and we just need to pass the same iv initialization vector to the decryption function that was generated here after the encryption so in the end that's just again a randomized uh sequence of some bits and bytes so we can call this get decrypt cipher for iv and we can pass this iv which is a byte array and this will return a cipher again so we can then return cipher.getinstance same as above we want to say apply again and initialize this this time it's actually cipher decrypt mode because that's of course what we want to do now we want to pass get keyed again and here at this point we will actually retrieve the existing key because that's of course what we need to decrypt what we encrypted before but when we call when we use this encrypt set for the first time we will actually create a new key here but we of course not always want to do that and now we also need to provide a third parameter which is an iv parameter spec to actually provide this iv value we passed above and that's already it for the getdecrypt74av function now that we have our two ciphers one for encryption and one for decryption we of course need to use them to actually yeah encrypt something and decrypt something and those will be the only functions we expose here so the only public functions which we will specify down below the first one will be a function encrypt we will be passing a byte array here so just the bytes we want to encrypt and we want an output stream so we will basically write the results to of the encryption this will be simply an output stream and we also return a byte array which will be the encrypted byte so we can just show these in a little text and to actually encrypt our byte array that we passed here now we can simply say well encrypted bytes is equal to um we use our encrypt cipher dot do final and that is the function we use to actually use that cipher and do something with it so here we actually pass our bytes array which we have as a parameter here and then here we will actually get another byte array and that is already the encrypted byte array now we also want to take this encrypted byte array and actually put it in this output stream why do we need to do this because when we then again want to decrypt what we encrypted here we actually need this iv value this initialization vector that was generated here during encryption with our cipher because when we then decrypt that we actually need to pass this byte array here and a common way to do this is actually to just append this iv in front of the actual encrypted bytes in our output stream so what i mean with that is we want to say output stream dot use which will just make sure to also automatically close the stream when we're done and then we can say it dot apply we don't need to apply here we can also just say it dot right to write something to this output stream we will first of all say encrypted encrypt cipher dot iv dot size which will write the size of our iv vector to this output stream so we know how how much bytes we actually need to read from that when we actually decrypt again um we want to write the actual iv encrypt encrypted no encrypt cipher iv so that is the actual byte array of our iv vector initialization vector i mean and we then want to actually write our encrypted bytes to that so we can say right encrypted bytes.size again so we also know how long this byte array is when we actually read this and we want to write our encrypted bytes so just the encrypted bytes of our byte array we passed here and then down here we can return our encrypted bytes because that is what we just want to show in our ui and that's it for our encrypt function and the next one will be decrypt also not too difficult here this function will actually take an input stream so which is just the opposite now of our encrypt function and we will then read this input stream so basically just what we want here we will now read this and decrypt that and return the result as a byte array again which you can then also convert back to string so here we can simply return input stream dot use again and then here we can simply read what we just wrote before so first of all the iv size so how how long our iv byte array is we can say input stream or rather just it dot read which will show an integer which is just the size of the first entry it actually reads so it will first of all just read what we wrote here which is the size we can then the next one will actually be the actual initialization vector so we can now say val iv is a byte array with our iv size so we just need this to initialize our byte array and we can then say it.read again and we can read the result directly into our byte array here or a v byte array and that's it for iv next up we also want to do the same for our encrypted byte so we can say val um encrypted bytes size is it.read again and we can then specify a byte array again so encrypted bytes is equal to a byte array with our encrypted byte size and we can then say hit that read and re-read the result into our encrypted bytes array and now we of course only have our encrypted bytes we haven't decrypted them yet so what we want to do is we want to decrypt them so we say a get decrypt cipher for a v so this time we use our decrypt cipher of course we pass our iv or initialization vector which we read above which again was written to this input stream before here in our encryption function so at this point and then we can say dot do final so again to just perform that operation with that cipher to decrypt in our case and the input is our encrypted bytes in this case and that will hopefully successfully decrypt our byte array so what we can now do is we can go to main activity and in here we want to just set up a quick ui which won't look really good but it will serve our purpose so in here let's first of all declare our crypto manager and oncreate cryptomanager and we need to add this request m annotation make sure to only launch it of course on a device running on m or later usually in my code i would add a check for that but for the sake of simplicity i won't do this here and in here we will have two states on the one hand a message to encrypt so just the message we want to encrypt we can say buy remember immutable state off which is just an empty string by default import get value and import this again and we do the same for the message to decrypt but remember mutable state of empty string and then let's build our little ui we first of all want to have a column so yeah we just want to have a text field oh yeah a text field and two buttons below that's all we want to have we want to say a modifier is modifier filmex size and just add some padding of 32 dp and import dp here and then in in here we want to say we have a text field the value will be our message to encrypt and if the value changes we say message to encrypt is equal to whatever we typed let's pass a modifier of modifier fill max with and let's pass a little placeholder which is just a text that says encrypt or encrypt string or so just like that we can add a bit of spacer here let's say atp and then we want to have a row with two buttons so we don't need any parameters here i think let's just have a button if we click this button let's not do this yet let's just first of all build the ui it will say encrypt and we can copy this and let's also add a little bit of spacing with 160p and paste this button here for decrypting okay so the rest what we need to do here is to of course fill in these on click listeners so that they actually do something and as i said the way i will do this here for this simple tutorial is that we will use a file in which we will actually write our um in which we will write the encrypted string or the encrypted bytes that we encrypt after we click this button and then since that is a file of course it will be stored and it will also be able to be retrieved when we relaunch the app when we then click decrypt we will read this file and the contents of that into a stream we will pass this to our crypto manager and we can then actually get what we wrote to this file before so first of all starting with encryption we first of all want to specify our bytes that we actually want to save in our file and the bytes will be the contents of our text field so message to encrypt that and what is called encode2 byte array that is how we just convert a string to a battery and the next thing is we need to create a file which is simply a new file we need to pass a parent and a child the parent will be our files directory so just our apps internal storage and the child will be let's say we call it secret.txt if that file does not exist yet we'll make sure to create this file so we can say file.create new file and if that file was created then we can actually also write something to it so we can say val fos which is a file output stream using our file and we then say our message to decrypt oh that is actually missing that we also show a text below below this row here where is that it's right here so we just want to show a little text that is our message to decrypt so basically just the result of our encryption so message to decrypt is equal to our cryptomanager dot decrypt and the input stream will be of course not decrypt we want to encrypt something the bytes that we want to encrypt will be our message to encrypt that or actually we converted that above we can just say bytes and the output stream will be our file output stream and now since that returns a byte array another string it expects us to pass a string we can say dot decode to string and then we don't have any issues so now we can actually encrypt something and save that in a file now we also need to reverse that to also read the file and decrypt that so here in our other button on click listener we want to say first of all getting in a reference to our file again again secret txt and actually in our file directory and the the file is called secret txt and this time we want to set our message to encrypt to something so whatever we show in the text field to just yeah read our file and decrypt that and that is cryptomanager.decrypt this time and here our input stream is in this case a file input stream passing our file and again decoding that to string so that should be it for our app let's now try this out and launch this i will launch it on my emulator here should also work on your real device here we go that is our app that we just built and before we actually try this i want to show you something and if we go to this device file explorer tab and open this we can actually see all of our files in our device so make sure to select the device you actually run your app on and then you can go to data data again and then here you will find the internal storage of all your apps you need to find your package name now of your of the product here so in my case it's com.plcoding.androidcrypto now which is this one and under files we find our internal storage so right now this is empty but if we actually use this now and let's say we again save something like this will be encrypted and we then say encrypt there you go that is our encrypted string if we go to our file explorer now and say right click synchronize then here is our secret.txt file and if we open this then here is the encrypted string basically so you can see that is really encrypted and yeah that's working if we now actually close our app relaunch that again and then click decrypt we can see this will be encrypted so we successfully decrypted our string again using a key that is saved in the android keystore system so that can't now actually be exposed by next time by an attacker if you like this video and you don't follow this channel yet then i would be very happy if you could do that to simply hit the subscribe button down below it's free and we can maybe hit the 100 000 subscribers at the end of this year that would be amazing i would be very grateful for that thanks for watching enjoy your week and i will see you back in the next video bye bye you
Info
Channel: Philipp Lackner
Views: 51,809
Rating: undefined out of 5
Keywords: android, tutorial, philip, philipp, filipp, filip, fillip, fillipp, phillipp, phillip, lackener, leckener, leckner, lackner, kotlin, mobile, crpto, crypto, encrypt, decrypt, keystore, key, private key, secret key, bytes, message, tring, string, jetpack compose
Id: aaSck7jBDbw
Channel Id: undefined
Length: 27min 53sec (1673 seconds)
Published: Wed Sep 07 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.