Photo by Kenneth Rougeau
If you don't work with mobile security on a daily basis, you might feel stuck when it comes to how the app you are working on needs to deal with sensitive data that cannot be exposed to third parties. Googling “mobile security practices” might scare you even more but, actually, in most cases there is no need run penetration tests or use sophisticated security testing techniques. A number of simple steps will do fine.
We have blogged earlier about the general guidelines of secure mobile development, and today we’ll focus on specific, practical tips for protecting data.
The steps below are the practices we use at Azoft to secure our own mobile data. They can be applied to projects with various security requirements, from high-level such as a healthcare application’s storing of patients’ medical records, to the mid/low-level needs of, for example, games transmitting social network account credentials.
The focus here is to restrict malicious access to a user's confidential information on a lost or stolen device as well as while transmitting data over the Internet. In this article we cover three main topics:
- Data encryption
- Potential security weaknesses
- Useful tools and libraries
Data encryption is the most obvious and also the best thing you can do as a first line of defense. Even if a malicious hacker gets access to a device’s hard disk, there’ll still be a chance for the data to remain safe.
Our goal as developers is to effectively increase this chance. We suggest doing the following:
Step 1. Installation phase
- Require a user password for the app (plainPassword) during installation.
- Just after the password is set, use Password-Based Key Derivation Function 2 (PBKDF2) to calculate the passwordHash.
For PBKDF2 a rather long — approximately 64-bit — salt (passwordSalt) is generated. The number of PBKDF2 iterations depends on device performance/processor capacity: the app chooses the maximum number of iterations possible while maintaining smooth performance.
When installation is finished, the app has both a passwordSalt and passwordHash stored locally on the device.
Step 2. Authentication procedure
Safe user authentication is implemented as follows:
- Using the entered password and saved passwordSalt, a hash is calculated.
- The hash is compared to the saved passwordHash.
Note: The user password entered is stored unencrypted in cache memory.
Step 3. Data storage and encryption
- When an app saves data for the first time, a random masterKey and initialization vector (IV) are generated. We'll use them later to encrypt the data.
- A masterSalt is generated and saved locally.
- Using plainPassword and masterSalt, a hash (PBKDF2) is calculated.
- Using the AES256 algorithm, the calculated hash is used to encrypt both MasterKey and IV.
- Encrypted MasterKey and IV are saved locally.
- Decrypt the MasterKey and IV using plainPassword and masterSalt hash (PBKDF2).
Now, we are ready to encrypt the data with MasterKey and IV using the AES256 algorithm.
Step 4. Decryption of data
Decryption of data requires two steps:
- Decrypt MasterKey and IV using plainPassword and masterSalt hash (PBKDF2).
- Use MasterKey and IV to decrypt the data.
5. Data transfer
If you plan to send confidential data to a server or share it with other devices, some extra measures should be added:
- Send data encrypted along with masterSalt and encrypted MasterKey and IV.
- Use secure channels when transferring data via the Internet: Secure Sockets Layer (SSL) or HTTPS.
In this way, only the following keys and hashes are stored on the device locally:
- passwordSalt and passwordHash — for authentication;
- masterSalt and encrypted MasterKey and IV — for data encryption and decryption.
Strengthening potential weak points
1. Concealing encryption algorithms
One of the potential weak points in mobile security is that a password can be hacked if the saved passwordHash and passwordSalt are known to a malicious attacker. But this is only possible if the hacker also knows which encryption algorithms to use. So, the first measure of protection is to conceal these algorithms.
Since developing an algorithm on your own is a complex task, in most of cases we have to choose from existing ones, and remain unique in how we choose to combine them.
2. Increase the number of password combinations
If the succession of algorithms used is already known to the malicious hacker, they might proceed to using brute force methods to hack the password. But brute-forcing a password via its hash takes time, namely in performing:
N * t
— where “N” is the number of password variants and “t” is the average time of a generated hash.
The method is simple: the more possible variants, the better. You can increase the number of variants by increasing the password’s:
- increase length — the more characters the better
- use characters in upper- and lowercase, numbers, special symbols, etc.
Both of these factors should be used in tandem, since a long password with a succession of neighboring characters alone like qwerty123 could be hacked quickly. Plus, you can increase the time required to generate a hash by using a considerable amount of encryption function iterations.
For example, Extreme GPU Bruteforcer states it can brute-force passwords when attaching hash SHA-256 at a speed 80 billion (8*10^7) variants per second on a NVIDIA GTX650Ti graphics card. The number of variants for passwords that contain a mixture of characters in lower- and uppercase along with numbers and special symbols is roughly calculated as 4.6*10^10. Thus, hacking a 6-character password will take no more than 10 minutes; a 7-character password takes 60 times longer at 10 hours; and an 8-character password would take about a month.
If you increase the number of iterations in the hash function from one to several thousand, then the time required to hack even a 6-character password will increase drastically, enough so to deter even the most malicious hacker from having any interest in decrypting the data.
You can also try to complicate a hacker’s life by using passwordSalt when working with rainbow tables.
3. Preventing reverse engineering
It's important to implement certain anti-debugging measures to make any attempt to use reverse engineering as difficult as possible. For example, a malicious hacker could attempt to examine the schemes and working algorithms of the app with the aim of finding weak points to exploit. As well, a hacker can try to create a memory dump while a user is working with the app in order to obtain the user's password, masterSalt hash, unencrypted MasterKey and IV and, possibly, a portion of encrypted data.
To prevent this, you should implement automatic clearing of all cached data with any change in app activity, whether it’s sending an app into background mode or the activation of sleep mode, etc.
Additionally, we recommend using various protectors — obfuscators — that can conceal the real code of an app while not only detecting debugger utilities but also noticing the occurrence of an app itself being debugged.
Alternative data-encrypting algorithms
As alternatives to the data-encrypting algorithms mentioned above we suggest using Serpent, Blowfish, and Twofish — along with their cascades. For the hash-to-PBKDF2-encoding function we recommend RIPEMD-160, Whirlpool, and SHA-2.
Here are the must-have tools for developers of secure mobile apps:
- sqlite — for local data storage
- wxSQLite — A wxWidgets style c++ wrapper that also implements SQLite's encryption
- SQLCipher — Uses openSSL's libcrypto to implement
- SQLiteCrypt — Custom implementation, modified API
- botansqlite3 — botansqlite3 is an encryption codec for SQLite3 that can use any algorithms in Botan for encryption
You can always combine the solutions above with each other or with algorithms of your own. As for the programming language, we strongly recommend to choose C++ as the main language, and the Boost, Crypto++ libraries.