LOCAL ENCRYPTION WITH ANDROID
15.03.2017 | Pierre Leonard
In the real world, what are safe boxes for? All of them are breakable if someone spends enough time and effort on it. However, if the time and efforts needed become long enough, then it might not be worth even trying to crack the safe. A good safe is a safe that will take more time and effort than its content is worth for the attacker.
This is still true when it comes to encryption in digital devices. Some encryption algorithms literally take hundreds of years to crack. However, relying on a single encryption method is risky. Computers are more and more powerful making it possible to crack algorithms that were considered safe yesterday. Also, it is not impossible that mathematic tools will be developed that will reduce the time needed to crack specific algorithms. As an example, Google recently announced they found a way to provoke collisions with the SHA1 hashing algorithm.
Apps may have to handle confidential data, credit card numbers, messages and so on. Keeping this data safe should be a primary concern of the developers. This post will describe a few methods to encrypt data on Android devices.
The first line of defence is the encryption of the memory of the device. Apps can check if the memory is encrypted or not and recommend the user to do it if it is not the case. Note that the encryption strength depends on the Android version but also on the hardware available on the device. It is enabled by default from Android 6.
STORING UNENCRYPTED DATA IN LOCAL STORAGE
Apps usually store data in the internal storage so that data should only be accessible by the app owning it. However, it is quite straightforward to go around this restriction, for instance by rooting the device (an operation meant to give more control on the device to power users). Therefore, confidential data shouldn’t be stored unencrypted.
No matter what is the encryption algorithm, it will rely on a key or a password that will be used to decrypt data. Obviously, this key should also be saved, but saving it unencrypted in the internal storage would be a nonsense. Hardcoding it is also a bad idea. It is quite easy to decompile the code of an app, even if it is obfuscated. The key will then appear in clear.
The solution here is to use the system keystore introduced in Android 4.3. On first run, the app will generate a random key pair that will be stored in the keystore. The app will be able to retrieve the key in subsequent runs. Even if the device is rooted, the access to the keystore will be limited to your app. Note that many new algorithms for the key generation have been added in Android 6. For apps that must support older versions, it is possible to use the keystore in conjunction with SpongyCastle to access more secure algorithms.
So, if the keystore is a safe place to keep sensitive data in, why can’t we use it to store all the information our app needs? Simply because the keystore can only store keys (so small data) and not arbitrary data.
Databases are also located in the local storage. Thus, they should also be encrypted if they contain sensitive information. Luckily, there’s an easy way to do that thanks to SQLCipher. SQLCipher uses the same API than the regular SQLite. The only difference is that SQLCipher requires a password to create and open the database. This password should be randomly generated, encrypted thanks to the key pair stored in the keystore and stored encrypted in the local storage (using preferences for instance).
Keep in mind that none of these methods is 100% safe! One day or another, they will be broken so apps should regularly be updated to match the security standards of the day. This post only discussed local encryption of data so that it will be harder for an attacker to read data stored in an app. However, there’s more than that to consider when developing a secure app like networking (don’t transmit your credentials unencrypted!) or even RAM management (a password remaining in the RAM can be retrieved by dumping the memory).