В этой статье мы приведем тестовые фрагменты кода, реализующего две основополагающие с точки зрения безопасности функции в Android приложениях: генерацию случайных чисел и шифрование данных. Рекомендуем попробовать все приведенные варианты, а по прочтении текста – скомпилировать тестовое приложение, скачав его по ссылке.
Существует два варианта шифрования данных под Android: с использованием Java Crypto API и OpenSSL API (нативный код). Мы рассмотрим оба.
Теперь вы можете использовать сгенерированный ключ для шифрования файлов с данными. Для этого зашифруем блоки байтов по алгоритму AES с помощью javax.crypto.
Для начала сгенерируем ключ и iv.
Теперь мы можем использовать сгенерированный ключ (cKeyBuffer) для шифрования файла. Инициализируем EVP с помощью вашего ключа и iv. Теперь подаем блоки байтов на вход функции EVP_EncryptUpdate. Последняя порция байтов из вашего файла должна быть скормлена функции EVP_EncryptFinal_ex.
Оригинал статьи на сайте Intel IDZ
Исходники тестового приложения
Существует целых 4 способа сгенерировать случайные числа в Android:
Однако, если вы используете RNG для генерации ключа, защищающего ваши данные, использовать обычный класс Random не рекомендуется, так его легче всего взломать. Остальные 3 метода обеспечивают более надежную защиту.
Оригинал статьи на сайте Intel IDZ
Исходники тестового приложения
Шифрование данных
Шифрование имеет важное значение, поскольку позволяет скрыть от посторонних глаз то, что им не следует видеть. Мобильные устройства хранят все больше и больше значимой информации, и защитить ее – прямая обязанность каждого разработчика.Существует два варианта шифрования данных под Android: с использованием Java Crypto API и OpenSSL API (нативный код). Мы рассмотрим оба.
Java Crypto API
Использовать Java Crypto API под Android очень просто. Сначала вам необходимо сгенерировать ключ шифрования. За это отвечает класс KeyGenerator в пэкедже javax.crypto.mKey = null;
try {
kgen = KeyGenerator.getInstance("AES");
mKey = kgen.generateKey();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
Теперь вы можете использовать сгенерированный ключ для шифрования файлов с данными. Для этого зашифруем блоки байтов по алгоритму AES с помощью 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
Шифрование данных через OpenSSL под Android требует написания нативного кода С, который доступен в Java через вызовы JNI. Это отнимает больше времени, зато быстродействие в результате будет выше.Для начала сгенерируем ключ и 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 )) {
}
Теперь мы можем использовать сгенерированный ключ (cKeyBuffer) для шифрования файла. Инициализируем EVP с помощью вашего ключа и iv. Теперь подаем блоки байтов на вход функции EVP_EncryptUpdate. Последняя порция байтов из вашего файла должна быть скормлена функции 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);
Оригинал статьи на сайте Intel IDZ
Исходники тестового приложения
Генерация случайных чисел
Генератор случайных чисел (RNG) – это программа или устройство для производства случайной последовательности чисел на определенном промежутке. RNG является жизненно важным для безопасности приложения. В реальности криптографический протокол может быть очень надежным, но при этом подверженным разнообразным атакам из-за того, что в своей основе использует слабые методы генерации ключа. Для усиления ключа и повышения надежности всей системы в целом может использоваться аппаратная поддержка RNG.Существует целых 4 способа сгенерировать случайные числа в Android:
- java.util.random
- java.security.SecureRandom
- /dev/urandom
- OpenSSL API
Однако, если вы используете RNG для генерации ключа, защищающего ваши данные, использовать обычный класс Random не рекомендуется, так его легче всего взломать. Остальные 3 метода обеспечивают более надежную защиту.
java.util.random
Использовать Java Random Number API очень просто. Вызов Random.nextInt() возвратит 4-байтное случайное значение (общее количество возможных значений – 232). Это API вполне годится для случаев, когда не требуется полагаться на действительно случайные числа.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 похож на java.util.Random в том смысле, что также возвращает 4-байтовое значение. SecureRandom криптографически более надежен, однако разработчики должны ознакомиться с недавней рекомендацией генерировать затравочную величину с помощью /dev/urandom для SecureRandom перед генерацией случайных чисел. В примере ниже /dev/urandom не используется.SecureRandom srand = new SecureRandom();
shouldDraw = (srand.nextInt() % randomMod );
/dev/urandom
Во всех операционных системах семейства Linux, включая Android, имеется специальный файл, созданный ядром, с помощью которого можно предоставить случайные числа приложениям. Среди всех 4 способов этот самый медленный, он генерирует криптографически безопасные значения с высокой энтропией путем объединения шумовых величин из различных частей операционной системы (например, драйверов устройств) для RNG. Мы можем получить случайное число непосредственно из ядра, прочитав файл /dev/urandom. /dev/urandom имеет доступ к аппаратному RNG, если таковой имеется.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
Мы также можем использовать OpenSSL API для получения случайных чисел в нативном коде С. В OpenSSL возможно использование затравочных байт из /dev/urandom для генерации криптографически безопасных случайных чисел. OpenSSL API обратится к аппаратному RNG, если таковой имеется.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);
}
Оригинал статьи на сайте Intel IDZ
Исходники тестового приложения