📜 ⬆️ ⬇️

Encryption and generation of random numbers in Android applications. Test cases

In this article, we present test code snippets that implement two fundamental security functions in Android applications: random number generation and data encryption. We recommend trying all the above options, and after reading the text - compile the test application by downloading it from the link.

Data encryption

Encryption is important because it allows you to hide from prying eyes something that they should not see. Mobile devices store more and more relevant information, and protecting it is the direct responsibility of each developer.
There are two options for encrypting data for Android: using the Java Crypto API and the OpenSSL API (native code). We will consider both.



Java Crypto API
Using Java Crypto API for Android is very simple. First you need to generate an encryption key. The KeyGenerator class in the javax.crypto package is responsible for this.
')
mKey = null; try { kgen = KeyGenerator.getInstance("AES"); mKey = kgen.generateKey(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } 

Now you can use the generated key to encrypt data files. To do this, we encrypt the blocks of bytes using the AES algorithm using javax.crypto.

 // open stream to read origFilepath. We are going to save encrypted contents to outfile InputStream fis = new FileInputStream(origFilepath); File outfile = new File(encFilepath); int read = 0; if (!outfile.exists()) outfile.createNewFile(); FileOutputStream encfos = new FileOutputStream(outfile); // Create Cipher using "AES" provider Cipher encipher = Cipher.getInstance("AES"); encipher.init(Cipher.ENCRYPT_MODE, mKey); CipherOutputStream cos = new CipherOutputStream(encfos, encipher); // capture time it takes to encrypt file start = System.nanoTime(); Log.d(TAG, String.valueOf(start)); byte[] block = new byte[mBlocksize]; while ((read = fis.read(block,0,mBlocksize)) != -1) { cos.write(block,0, read); } cos.close(); stop = System.nanoTime(); Log.d(TAG, String.valueOf(stop)); seconds = (stop - start) / 1000000;// for milliseconds Log.d(TAG, String.valueOf(seconds)); fis.close(); 


OpenSSL API
Encrypting data through OpenSSL for Android requires writing native C code, which is available in Java through JNI calls. This takes more time, but as a result, the speed will be higher.
First, generate the key and iv.

 unsigned char cKeyBuffer[KEYSIZE/sizeof(unsigned char)]; unsigned char iv[] = "01234567890123456"; int opensslIsSeeded = 0; if (!opensslIsSeeded) { if (!RAND_load_file("/dev/urandom", seedbytes)) { return -1; } opensslIsSeeded = 1; } if (!RAND_bytes((unsigned char *)cKeyBuffer, KEYSIZE )) { } 


Now we can use the generated key (cKeyBuffer) to encrypt the file. Initialize EVP with your key and iv. Now we submit blocks of bytes to the input of the EVP_EncryptUpdate function. The last portion of bytes from your file should be fed to the function EVP_EncryptFinal_ex.

 if (!(EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, cKeyBuffer, iv ))) { ret = -1; printf( "ERROR: EVP_ENCRYPTINIT_EXn"); } // go through file, and encrypt if ( orig_file != NULL ) { origData = new unsigned char[aes_blocksize]; encData = new unsigned char[aes_blocksize+EVP_CIPHER_CTX_block_size(e_ctx)]; // potential for encryption to be 16 bytes longer than original printf( "Encoding file: %sn", filename); bytesread = fread(origData, 1, aes_blocksize, orig_file); // read bytes from file, then send to cipher while ( bytesread ) { if (!(EVP_EncryptUpdate(e_ctx, encData, &len, origData, bytesread))) { ret = -1; printf( "ERROR: EVP_ENCRYPTUPDATEn"); } encData_len = len; fwrite(encData, 1, encData_len, enc_file ); // read more bytes bytesread = fread(origData, 1, aes_blocksize, orig_file); } // last step encryption if (!(EVP_EncryptFinal_ex(e_ctx, encData, &len))) { ret = -1; printf( "ERROR: EVP_ENCRYPTFINAL_EXn"); } encData_len = len; fwrite(encData, 1, encData_len, enc_file ); // free cipher EVP_CIPHER_CTX_free(e_ctx); 

Original article on Intel IDZ website
Test application sources

Random Number Generation

A random number generator (RNG) is a program or device for producing a random sequence of numbers on a certain interval. RNG is vital to the security of the application. In reality, a cryptographic protocol can be very reliable, but at the same time susceptible to various attacks due to the fact that it basically uses weak key generation methods. To enhance the key and increase the reliability of the entire system, hardware support for the RNG can be used.



There are as many as 4 ways to generate random numbers in Android:

However, if you use the RNG to generate a key that protects your data, it is not recommended to use the regular Random class, since it is easiest to crack. The remaining 3 methods provide more reliable protection.

java.util.random
Using the Java Random Number API is very simple. Calling Random.nextInt () will return a 4-byte random value (the total number of possible values ​​is 2 32 ). This API is quite suitable for cases where you do not need to rely on really random numbers.

 for (int i = 0; i < lastVal; i += 2) { dataRandomPoints[i] = (rand.nextInt() % widget_width); dataRandomPoints[i+1] = (rand.nextInt() % widget_height); } 


java.security.SecureRandom
SecureRandom is similar to java.util.Random in the sense that it also returns a 4-byte value. SecureRandom is cryptographically more reliable, however, developers should familiarize themselves with a recent recommendation to generate a seed using / dev / urandom for SecureRandom before generating random numbers. In the example below, / dev / urandom is not used.

 SecureRandom srand = new SecureRandom(); shouldDraw = (srand.nextInt() % randomMod ); 

/ dev / urandom
In all operating systems of the Linux family, including Android, there is a special file created by the kernel, with which you can provide random numbers to applications. Among all 4 methods this is the slowest, it generates cryptographically secure values ​​with high entropy by combining noise values ​​from different parts of the operating system (for example, device drivers) for the RNG. We can get a random number directly from the kernel by reading the file / dev / urandom. / dev / urandom has access to the hardware RNG, if one is available.

 unsigned int cKeyBuffer[keysize]; memset(cKeyBuffer, 0, sizeof(unsigned int) * keysize); FILE *fin; strcpy(filein, "/dev/urandom"); fin = fopen(filein, "rb"); if (fin != NULL) { fread(cKeyBuffer, sizeof(int), keysize, fin); fclose (fin); } 

OpenSSL API
We can also use the OpenSSL API to get random numbers in the native C code. In OpenSSL, it is possible to use the bare bytes from / dev / urandom to generate cryptographically secure random numbers. The OpenSSL API will access the hardware RNG, if one is available.

 int seedbytes = 1024; unsigned int cKeyBuffer[keysize]; memset(cKeyBuffer, 0, sizeof(unsigned int) * keysize); if (!opensslIsSeeded) { if (!RAND_load_file("/dev/urandom", seedbytes)) { __android_log_print(ANDROID_LOG_ERROR, TAG, "Failed to seed OpenSSL RNG"); return jKeyBuffer; } opensslIsSeeded = 1; } if (!RAND_bytes((unsigned char *)cKeyBuffer, keysize * sizeof(int))) { __android_log_print(ANDROID_LOG_ERROR, TAG, "Faled to create OpenSSSL random integers: %ul", ERR_get_error); } 

Original article on Intel IDZ website
Test application sources

Source: https://habr.com/ru/post/224285/


All Articles