Android security key app

Securing Secret Key In Android Using Keystore

At some point in time, we all wanted to keep our data secure from being hacked/reverse engineered. The basic security mechanisms like,

a. ProGuard, ShrinkResources & minifyEnabled
b. Hiding in Manifest
c. Hiding in Build.Gradle
d. Storing in MySQL DB/Room DB/SharedPreference
e. Hiding in Strings.xml.

All these methods fail to provide maximum security. The most common and known logic of securing the key can be bypassed either by reversing and taking it from dex->jar file or by rooting the device and accessing the device storage.

But, there is one more method that beats them all. The mechanism which is generally used by applications for storing very sensitive data like Credit Card details, Bank Account and such.

Keystore is bound to hardware security which is generally used to store cryptographic keys. It becomes incredibly difficult for hackers to get access to it since a Keystore is very specific to every application. More of introduction done let us jump to the code now —

Declare few variables in Cryptor.java

private static final String TRANSFORMATION = “AES/GCM/NoPadding”;
private static final String ANDROID_KEY_STORE = “AndroidKeyStore”;
private byte[] iv;
private KeyStore keyStore;
private static final String SAMPLE_ALIAS = “MYALIAS”;

a. TRANSFORMATION is used for setting the algorithm which will be used for encoding.

b. iv is known as Initialization Vector which is an arbitrary number used along with a secret key for encryption. (It can be stored in public storage like SharedPreference, Room DB or MySQL DB).

c. SAMPLE_ALIAS is used to access the entity stored inside the Keystore.

ENCRYPTING DATA

For encrypting a value with the Keystore, we can do it by,

a. Create an object of the Cryptor class.

b. Use a setIv method to init the cipher using a secret key in Cryptor class.

c. Encrypt the text using an encryption function defined in Cryptor class.

d. Store the Iv and encrypted text (The Iv can be made public and it does not cause any issue) in SharedPreference or Room Database.

In Cryptor.java, we define the following functions

2. getSecretKey_en() method :

3. encryptText(String string_to_encrypt) :

4. encryptData(String text_to_encrypt) :

Explanation: We generate a secret key using the keyStore with specific algorithms and the ALIAS. the secret key which is generated is used to init the cipher and get the IV. The encrypt text function uses the text and the iv to encrypt the text in the Keystore and gives the encrypted text which can be stored in any general storage medium.

DECRYPTING DATA

For decrypting a value with the Keystore, we can do it by,

a. Create an object of the Cryptor class.

b. Initialize the KeyStore instance.

c. Use the decrypt function by passing the encrypted text and the iv (stored in SharedPreference or Room Database).

In HomeScreen.java

In Cryptor.java, add the following functions

2. decryptText(String encrypted_string, String iv) :

3. decryptData(String encrypted_string, byte[] Iv) :

Explanation: While decrypting, we get the stored Iv and encrypted text stored in our one of the storage medium. We initialize the Keystore using the ANDROID_KEY_STORE and decrypt the text using the Iv and by the init and doFinal method of the Cipher.

CONCLUSION:

So, with the above implementation, secrets are now safe in the KeyStore. Why it is probably the best method is because KeyStore is very specific to the application. It cannot be retrieved and hence the text cannot be decrypted without it. Many applications which stores the Credit Card and other sensitive data of the users use this encryption method to keep it safe.

For the entire code, you can look into my GitHub repository.

Источник

Android Security, Keystore and Fingerprint API. Creating Lock Screen for your app.

How to protect sensitive data in your Android application. In this article, I’ll tell about AndroidKeystore, Fingerprints and how to use it to protects some of your data such as passwords, tokens, etc.

Читайте также:  Airplay сервер для android

This article is based on PFLockScreen library I created. You can use it in your application. If you have some issues or ideas fill free to create an issue on GitHub or write me a message.

About Android Keystore.

The Android Keystore system lets you store cryptographic keys in a container to make it more difficult to extract from the device. Once keys are in the keystore, they can be used for cryptographic operations with the key material remaining non-exportable.

You can use Android Keystore to encrypt some sensitive data like passwords. For example, your application required a password to make a purchase and you want the application to remember user’s password for some short amount of time (15 min — 30 min) so a user doesn’t need to input it again. The similar logic you can find, for instance, in Apple AppStore. Within this time input password again is not required. For this situation, you can use keystore to encrypt and save the password.

First, you need to load a keystore.

Next step is to generate an encryption key.

What is going on here? You initialize KeyGenerator, with your alias name and purposes (Encryption and Decryption).

Set encryption algorithm and parameters. You can use different algorithms to create a symmetric or asymmetric key, etc (Use KeyPairGenerator or KeyGenerator).

If you want you can protect this key with device pin code (The one you use to lock your device) or fingerprint with the setUserAuthenticationRequired method.

It’s mean that to get access to the encryption keys from keystore and decrypt your data you will need to use a device authorization.

But don’t worry. Only your application can get its keystore data. But in this case, there is additional security level required user participation.

After you load keystore and generate key next set is creating a Cipher object.

This class provides the functionality of a cryptographic cipher for encryption and decryption.

“RSA/ECB/OAEPWithSHA-256AndMGF1Padding” — “algorithm/mode/padding” or can be just “algorithm” depends on your key generator parameters.

Encrypt

To encrypt out data we need to initialize cipher object.

A known bug in Android 6.0 (API Level 23) causes user authentication-related authorizations to be enforced even for public keys. To work around this issue extract the public key material to use outside of Android Keystore.

After we did all the steps we finally do encoding. byte[] bytes = cipher.doFinal(input.getBytes()); String encoded = Base64.encodeToString(bytes, Base64.NO_WRAP);

This encoded string we got in result we can save somewhere in SharedPreferences or using Accounts API.

Decrypt

To decode string we got before, first, we need to preparing Cipher to decode.

If before we set the “user authentication required” parameter to false before, we can just decode.

Using fingerprint API to confirm user and decryption.

Google added Fingerprint API only in Android 6.0 and even new devices not always have a fingerprint scanner. So you have to check you if a device has fingerprint hardware.

To check if a device has a scanner: FingerprintManagerCompat.from(context).isHardwareDetected();

To check if a user added his fingerprint to the device: FingerprintManagerCompat.from(context).hasEnrolledFingerprints();

If we going to use Fingerprint API for decoding (KeyGenerator’s userAuthenticationRequired is true), then we need to check also if your screen is locked with pin or pattern.

If we are using Fingerprint for decryption we need to pass CryptoObject. Otherwise, CryptoObject can be null.

Next step is letting the system know that we are ready to try to authenticate with fingerprint:

If we want a system to stop listening for fingerprint we can cancel.

To get an event about successful or unsuccessful attempts use

You can find code example in my PFLockScreen library.

If you like the article please press 👏 button.

Источник

Ключи, учетные данные и хранилище на Android

Russian (Pусский) translation by Ellen Nelson (you can also view the original English article)

В предыдущем материале о безопасности пользовательских данных Android мы рассмотрели шифрование данных с помощью предоставленного пользователем кода. В этом уроке перейдём к хранению учётных данных и ключей. Я начну с ознакомления с учётными данными и закончу примером защиты данных с помощью хранилища ключей KeyStore.

Читайте также:  Нет драйверов под android

Часто, при работе со сторонней службой, требуется какая-то форма авторизации. Она может быть настолько простой, как /login на стороне пользователя, которая принимает имя пользователя и пароль.

Сначала может показаться, что простое решение — это собрать UI, который будет предлагать пользователю войти в систему, а затем записать и сохранить их данные для входа. Однако, это не лучший метод, так как нашему приложению не нужно знать данные для входа в сторонний аккаунт. Вместо этого, мы можем использовать Диспетчер учётных записей (Account Manager), который уполномочен отрабатывать эту конфиденциальную информацию для нас.

Диспетчер учётных записей

Диспетчер учётных записей (Account Manager) — это централизованный помощник для работы с учётными данными пользователя, поэтому вашему приложению, иметь дело с паролями напрямую не нужно. Часто он предоставляет токен вместо реального имени пользователя и пароля, который можно использовать для выполнения аутентифицированных запросов к службе. Например, при запросе токена OAuth2.

Иногда, вся необходимая информация уже хранится на устройстве, а иногда Account Manager придётся обращаться к серверу за новым токеном. Вы, наверное, видели раздел Учётные записи в Настройках вашего устройства для разных приложений. И вот как, мы можем получить список доступных учётных записей:

Этому коду потребуется разрешение android.permission.GET_ACCOUNTS . Если вы ищете определённую учётную запись, вы можете найти её вот так:

Как только найдёте учётную запись, её токен можно получить вызвав метод getAuthToken(Account, String, Bundle, Activity, AccountManagerCallback, Handler) . Затем, таки можно использовать как для авторизированных запросов API к сервису. Это может быть RESTful API, в котором вы передаёте параметр токена во время HTTPS-запроса без необходимости знать детали личной учётной записи пользователя.

Так как, у каждой службы будет свой способ проверки подлинности и хранения личных учётных данных, Диспетчер учётных записей предоставляет модули проверки подлинности для реализации сторонней службой. Хотя Android может выполнять вход на многие популярные сервисы, для вашего приложения, вы можете написать свой собственный обработчик авторизации учётной записи и хранилища учётных данных. Это позволит убедиться, что учётные данные зашифрованы. Имейте также в виду, что учётные данные в Диспетчере учётных записей, которые используются другими службами, могут храниться в виде открытого текста, что делает их видимыми для любого, кто имеет рут-права на своё устройство.

Временами вам нужно будет иметь дело с ключами или сертификатами для отдельного лица или сущности, вместо просто данных для входа. Например, когда стороннее приложение отправляет вам файл сертификата, который вам нужно сохранить. Самый распространённый сценарий — это когда приложению нужно авторизироваться на сервере частной организации.

В следующем уроке, мы рассмотрим использование сертификатов для аутентификации и безопасной связи, ну а пока, я всё же хочу рассмотреть, как хранить эти элементы. Изначально Keychain API был создан для очень конкретного использования — установка закрытого ключа или пары сертификатов из файла PKCS#12.

Keychain — связка ключей

Представленный в Android 4.0 (API Level 14), Keychain API управлял ключами. В частности, это работает с объектами PrivateKey и X509Certificate и обеспечивает более безопасный контейнер, чем использование хранилища данных вашего приложения. Связано это с тем, что разрешения закрытых ключей открывают доступ к ключам только вашему приложению и только после авторизации пользователя. Это означает, что, прежде чем, вы сможете использовать хранилище учётных данных, на устройстве должен быть настроен экран блокировки. Кроме того, объекты в связке ключей можно объединить с защитой от оборудования, если доступно.

Код установки сертификата выглядит следующим образом:

Пользователю будет предложено ввести пароль для доступа к закрытому ключу и указать имя сертификата. Для получения ключа, в следующем коде представлен пользовательский интерфейс, который позволяет пользователю выбирать ключ из списка установленных ключей.

Как только выбор сделан, возвращается строка с названием псевдонима alias(final String alias) , где вы можете напрямую получить доступ к закрытому ключу или цепочке сертификатов.

Вооружившись этими знаниями, теперь давайте посмотрим, как мы можем использовать хранилище учётных данных для сохранения конфиденциальных данных.

KeyStore

В предыдущем уроке, мы рассмотрели защиту данных с помощью предоставляемого пользователем пароля. Такой вариант хорош, но требования к приложениям часто уводят от того, чтобы пользователи каждый раз входили в систему и запоминали дополнительный пароль.

Вот где можно использовать KeyStore API. Начиная с API 1, KeyStore используется системой для хранения учётных данных WiFi и VPN. Начиная с 4.3 (API 18), вы можете работать с асимметричными ключами конкретного приложения, а в Android M (API 23) можно хранить симметричный ключ AES. Таким образом, хотя API не позволяет хранить конфиденциальные строки напрямую, эти ключи можно сохранить, а затем использовать для шифрования строк.

Читайте также:  Хороший пасьянс для андроид

Преимущество хранения ключа в хранилище ключей заключается в том, что он позволяет работать с ключами без раскрытия секретного содержимого этого ключа; данным ключа не место в приложении. Помните, что ключи защищаются разрешениями, так что только ваше приложение может получить к ним доступ, и они могут быть дополнительно защищены аппаратным обеспечением, если устройство поддерживает это. Создаётся контейнер, который усложняет извлечение ключей с устройства.

Генерирование нового случайного ключа

В этом примере вместо генерации ключа AES из предоставленного пользователем пароля мы можем автоматически сгенерировать случайный ключ, который будет защищён в хранилище ключей KeyStore. Мы можем сделать это, создав экземпляр KeyGenerator , настроенного на поставщика «AndroidKeyStore» .

Здесь важно обратить внимание на спецификации .setUserAuthenticationRequired(true) и .setUserAuthenticationValidityDurationSeconds(120) . Для этого, обязательно должна быть включена блокировка экрана и ключ должен быть заблокирован, до тех пор, пока пользователь не аутентифицируется.

Изучив документацию .setUserAuthenticationValidityDurationSeconds() , вы увидите, что это означает, что ключ доступен только через определённое количество секунд после аутентификации по паролю, и что для передачи -1 требуется идентификация по отпечатку пальца каждый раз, когда вы хотите получить доступ к ключу. Включение требования для аутентификации также приводит к отзыву ключа, когда пользователь удаляет или изменяет экран блокировки.

Поскольку хранение незащищённого ключа вместе с зашифрованными данными, это как прятать ключ от дома под половик, эти параметры пытаются защитить ключ в состоянии покоя в случае взлома устройства. Примером может служить автономный дамп данных устройства. Если пароль устройства не известен, эти данные, по сути, бесполезны.

Опция .setRandomizedEncryptionRequired(true) включает требование о наличии достаточного количества случайных чисел (каждый раз новый случайный ВИ [вектор инициализации]), чтобы при повторном шифровании одних и тех же данных, зашифрованный результат всё равно не повторялся. Это не позволяет злоумышленнику получить информацию о зашифрованном тексте на основе передачи тех же данных.

Ещё стоит отметить — setUserAuthenticationValidWhileOnBody(boolean remainsValid) , что блокирует ключ, как только устройство обнаружит, что он больше не принадлежит человеку.

Шифрование данных

Теперь, когда ключ хранится в хранилище KeyStore, мы можем создать метод, который зашифрует данные с использованием объекта Cipher , учитывая SecretKey . Это вернёт HashMap , содержащий зашифрованные данные и случайный ВИ, который понадобится для расшифровки данных. Зашифрованные данные вместе с ВИ могут быть сохранены в файл или в открытых настройках.

Расшифровка в массив байтов

Для расшифровки применяется обратный ход. Объект Cipher инициализируется с использованием константы DECRYPT_MODE , и возвращается расшифрованный массив byte[] .

Смотрим на примере

Теперь мы можем посмотреть на пример!

Использование асимметричных ключей RSA для старых устройств

Это хорошее решение для хранения данных в версии M и выше, но что, если ваше приложение поддерживает более ранние версии? Хотя симметричные ключи AES не поддерживаются в M, поддерживаются асимметричные ключи RSA. Это означает, что для достижения того же результата, мы можем использовать RSA ключи и шифрование.

Основное отличие заключается в том, что асимметричная пара ключей содержит два ключа: закрытый и открытый ключ, где открытый ключ шифрует данные, а закрытый ключ расшифровывает их. KeyPairGeneratorSpec передаётся в KeyPairGenerator , который инициализируется с помощью KEY_ALGORITHM_RSA и поставщика AndroidKeyStore .

Для шифрования, из пары ключей мы получаем RSAPublicKey и используем его с объектом Cipher .

Расшифровка выполняется с использованием объекта RSAPrivateKey .

Кое-что об RSA — шифрование медленнее, чем в AES. Для небольших объёмов информации, например, когда вы защищаете строки общих настроек, это не страшно. Если вы обнаружите проблему с производительностью при шифровании больших объёмов данных, то вместо этого вы можете использовать данный пример для шифрования и хранения только ключа AES. И тогда, для остальной части ваших данных, используйте более быстрое шифрование AES, которое обсуждалось в предыдущем уроке. Вы можете сгенерировать новый AES ключ и преобразовать его в массив byte[] , который совместим с этим примером.

Чтобы получить ключ, сделайте вот так:

Довольно много кода! Для простоты примеров, я пропустил обработку исключений. Но помните, что для итогового кода не рекомендуется просто перехватывать все случаи Throwable в одном операторе catch.

Заключение

На этом урок по работе с учётными данными и ключами завершён. Большая часть неразберихи вокруг ключей и хранилища связана с эволюцией ОС Android, но вы можете выбрать, какое решение использовать, учитывая уровень API, поддерживаемый вашим приложением.

Теперь, когда мы рассмотрели лучшие примеры защиты данных в состоянии покоя, следующий урок будет сосредоточен на защите данных при передаче.

Источник

Оцените статью