
Описание
Приложение хранит или использует при своей работе чувствительную информацию.
Во время своей работы приложение часто оперирует чувствительной информацией, такой как пароли, различные токены, ключи шифрования и т.д. Во время проведения анализа приложения Stingray определяем такую информацию согласно правилам поиска и дополнительно проверяет, что найденная чувствительная информация хранится в неизменном виде или используется приложением в других функциях или “зашита“ в исходном коде приложения.
Рекомендации
При необходимости использования чувствительной информации в приложении необходимо убедиться, что она правильно хранится и не попадает в общедоступные места, как, например, системные логи (logcat) или файлы приложения на sd-карте.
При необходимости хранения такой информации рекомендуется использовать шифрование. Для обеспечения конфиденциальности Android оснащена множеством криптографических функций и методов, с помощью которых приложения Android могут безопасно осуществлять шифрование и дешифрование (для обеспечения конфиденциальности), а также аутентификацию сообщений (MAC) и цифровые подписи (для проверки целостности).
Для того, чтобы выбрать подходящий в заданных условиях метод шифрования и тип ключа, можно воспользоваться следующей схемой:

Шифрование/дешифрование с использованием Android KeyStore.
Для примера рассмотрим шифрование/дешифрование с использованием Android KeyStore. Данный механизм позволяет генерировать и использовать ключи, сгенерированные в аппаратном хранилище ключей Android. Такой подход является наиболее защищенным с точки зрения хранения ключей, так как закрытый ключ никогда не появляется в памяти, что минимизирует риск его утечки или компрометации.
Создание новых ключей.
Прежде чем начать процесс шифрования, необходимо задать alias, который будет использован для шифрования / дешифрования данных. Это может быть любая строка. Alias — это имя записи, по которому можно будет обращаться к сгенерированному ключу в Android KeyStore.
Для начала, необходимо получить экземпляр Android KeyGenerator .
final KeyGenerator keyGenerator = KeyGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
В данном примере используется алгоритм AES, и ключи будут храниться в AndroidKeyStore.
Далее нужно создать KeyGenParameterSpec, используя KeyGenParameterSpec.Builder для передачи в метод инициализации KeyGenerators.
Что такое KeyGenParameterSpec?
KeyGenParameterSpec это некоторые свойства ключей, которые будут сгенерированы. Например, можно указать срок действия ключа, его назначение, и различные другие параметры.
final KeyGenerator keyGenerator = KeyGenerator .getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE); final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .build();
В приведенном примере первым аргументом передаётся alias, который будет использован в дальнейшем для обращения к этому ключу. Затем указывается цель этого ключа — зашифровать и расшифровать данные. В setBlockModes ,указывается режим в котором будет применяться данный ключ, поскольку мы используем алгоритм преобразования «AES / GCM / NoPadding», необходимо указать BLOCK_MODE_GCM и последним параметром указывается режим дополнения (ENCRYPTION_PADDING_NONE).
Шифрование данных
Предварительные настройки завершены. Для шифрования данных возможно использовать следующий пример:
final KeyGenerator keyGenerator = KeyGenerator .getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE); final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .build(); keyGenerator.init(keyGenParameterSpec); final SecretKey secretKey = keyGenerator.generateKey(); final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, secretKey);
final KeyGenerator keyGenerator = KeyGenerator .getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE); final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .build(); keyGenerator.init(keyGenParameterSpec); final SecretKey secretKey = keyGenerator.generateKey(); final Cipher cipher = Cipher.getInstance(TRANSFORMATION); cipher.init(Cipher.ENCRYPT_MODE, secretKey); iv = cipher.getIV(); encryption = cipher.doFinal(textToEncrypt.getBytes("UTF-8"));
Затем используется ссылка на вектор инициализации (IV) , который так же необходим для дешифрования, и с помощью doFinal (textToEncrypt) завершаем операцию шифрования. Метод doFinal возвращает массив байтов, который является зашифрованным текстом.
Расшифровка данных
Запуск KeyStore
Прежде чем начать расшифровывать данные, нам понадобится экземпляр KeyStore.
keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null);
KeyStore используется, чтобы получить закрытый ключ, используя alias, который ранее использовалcz при шифровании данных.
Необходим SecretKeyEntry из хранилища ключей, чтобы получить из него secretKey.
keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore .getEntry(alias, null); final SecretKey secretKey = secretKeyEntry.getSecretKey();
Используем GCMParameterSpec с Cipher для инициализации процесса дешифрования (параметр encryptionIv это вектор инициализации, который использовался при шифровании).
keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore .getEntry(alias, null); final SecretKey secretKey = secretKeyEntry.getSecretKey(); final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); final GCMParameterSpec spec = new GCMParameterSpec(128, encryptionIv); cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
И, как и раньше, для получения расшифрованных данных:
final byte[] decodedData = cipher.doFinal(encryptedData);
Чтобы получить незашифрованное строковое представление:
final String unencryptedString = new String(decodedData, "UTF-8");
Ссылки
3. https://developer.android.com/reference/javax/crypto/KeyGenerator.html
4. https://developer.android.com/reference/android/security/keystore/KeyGenParameterSpec.html
5. https://developer.android.com/reference/android/security/keystore/KeyGenParameterSpec.Builder.html
6.https://developer.android.com/reference/android/security/keystore/KeyProperties.html
7.https://developer.android.com/reference/javax/crypto/SecretKey.html
8.https://developer.android.com/reference/javax/crypto/Cipher.html
9.https://developer.android.com/reference/javax/crypto/spec/GCMParameterSpec.html