Опубліковано Середа в 03:202 дн Адміністратор Ви коли-небудь намагалися зашифрувати дані у своєму додатку? Як розробник, ви хочете, щоб дані були в безпеці, і в руках сторони, яка має право їх використання. Але якщо ви, як більшість розробників Android, і у вас немає спеціальної групи безпечників, яка б допомагала правильно шифрувати дані вашої програми. Пошукавши в Інтернеті, як зашифрувати дані, ви можете отримати відповіді, які застаріли на кілька років і зробити неправильні висновки. Бібліотека сприяє використанню AndroidKeyStore при використанні безпечних та відомих криптографічних примітивів. Використання EncryptedFile та EncryptedSharedPreferences дозволяє локально захистити файли, які можуть містити конфіденційні дані, ключі API, токени OAuth та інші типи секретів.Чому ви хочете зашифрувати дані у вашому додатку? Хіба Android, починаючи з 5.0, не шифрує вміст розділу даних користувача за умовчанням? Звичайно, це так, але є деякі випадки використання, коли вам може знадобитися додатковий рівень захисту. Якщо ваша програма використовує спільне сховище, ви повинні зашифрувати дані. У домашньому каталозі програми ваша програма повинна шифрувати дані, якщо ваша програма обробляє конфіденційну інформацію, включаючи, крім іншого, інформацію, що дозволяє встановити особистість (PII), медичні записи, фінансові дані або корпоративні дані. По можливості, ми рекомендуємо прив'язувати цю інформацію до біометрії для додаткового рівня захисту.Jetpack Security заснований на Tink, кросплатформному проекті безпеки з відкритим вихідним кодом від Google. Тинк може підійти, якщо вам потрібне загальне шифрування, гібридне шифрування або щось подібне. Структури даних Jetpack Security повністю сумісні із Tink.Генерація ключівПерш ніж ми почнемо шифрувати ваші дані, важливо зрозуміти, як ваші ключі шифрування зберігатимуться в безпеці. Jetpack Security використовує master key, який шифрує всі subkeys, що використовуються кожної криптографічної операції. JetSec надає рекомендований master key за промовчанням у класі MasterKeys. Цей клас використовує базовий ключ AES256-GCM, який генерується та зберігається в AndroidKeyStore. AndroidKeyStore - це контейнер, який зберігає криптографічні ключі в TEE або StrongBox, що ускладнює їхнє вилучення. Subkeys зберігаються в об'єкті SharedPreferences, що настроюється.Насамперед ми використовуємо специфікацію AES256_GCM_SPEC у Jetpack Security, яка рекомендується для загальних випадків використання. AES256-GCM є симетричним і загалом швидко працює на сучасних пристроях.Код:val keyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)Для додатків, які потребують більш ретельного налаштування або обробляють дуже конфіденційні дані, рекомендується створити KeyGenParameterSpec, вибираючи варіанти, які мають сенс для використання. Ключі з прив'язкою часу з BiometricPrompt можуть забезпечити додатковий рівень захисту від рутованих або скомпрометованих пристроїв.Важливі опції:userAuthenticationRequired() та userAuthenticationValiditySeconds() можуть використовуватися для створення ключа з прив'язкою до часу. Ключі з прив'язкою до часу вимагають авторизації за допомогою BiometricPrompt для шифрування та дешифрування симетричних ключів.unlockedDeviceRequired () встановлює прапор, який допомагає запобігти доступу до ключа, якщо пристрій не розблоковано. Цей прапор доступний на Android Pie та вище.Використовуйте setIsStrongBoxBacked (), щоб виконувати криптографічні операції на більш продуктивному окремому чіпі. Це мало впливає на продуктивність, але є більш безпечним. Він доступний на деяких пристроях з Android Pie або вище.ПриміткаЯкщо ваша програма шифрує дані у фоновому режимі, вам не слід використовувати ключі з прив'язкою до часу або вимагати, щоб пристрій був розблокований, оскільки ви не зможете виконати це без присутності користувача.Код:// Кастомний master key val advancedSpec = KeyGenParameterSpec.Builder( "master_key", KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT ).apply { setBlockModes(KeyProperties.BLOCK_MODE_GCM) setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) setKeySize(256) setUserAuthenticationRequired(true) setUserAuthenticationValidityDurationSeconds(15) // must be larger than 0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { setUnlockedDeviceRequired(true) setIsStrongBoxBacked(true) } }.build() val advancedKeyAlias = MasterKeys.getOrCreate(advancedSpec)Розблокування ключів, що прив'язані за часомВи повинні використовувати BiometricPrompt для авторизації пристрою, якщо ваш ключ був створений з наступними параметрами:userAuthenticationRequired trueuserAuthenticationValiditySeconds > 0Після аутентифікації користувача ключі розблокуються на час, встановлений у полі validity seconds . AndroidKeystore не має API для запиту налаштувань ключа, тому ваша програма повинна відстежувати ці налаштування. Ви повинні створити свій екземпляр BiometricPrompt у методі onCreate () в activity , в якому ви представляєте діалогове вікно користувачеві.Код BiometricPrompt для розблокування ключів із прив'язкою до часу:Код:// Activity.onCreate val promptInfo = PromptInfo.Builder() .setTitle("Розблокувати") .setDescription("Ви бажаєте розблокувати цей ключ?") .setDeviceCredentialAllowed(true) .build() val biometricPrompt = BiometricPrompt( this, // Activity ContextCompat.getMainExecutor(this), authenticationCallback ) private val authenticationCallback = object : AuthenticationCallback() { override fun onAuthenticationSucceeded( result: AuthenticationResult ) { super.onAuthenticationSucceeded(result) // Unlocked -- do work here. } override fun onAuthenticationError( errorCode: Int, errString: CharSequence ) { super.onAuthenticationError(errorCode, errString) // Handle error. } } To use: biometricPrompt.authenticate(promptInfo)Шифруємо файлиJetpack Security включає клас EncryptedFile, який усуває проблеми, пов'язані із шифруванням файлових даних. Подібно до File, EncryptedFile надає об'єкт FileInputStream для читання і об'єкт FileOutputStream для запису. Файли шифруються за допомогою потокової передачі AEAD, яка відповідає визначенню OAE2. Дані поділяються на шматки та шифруються за допомогою AES256-GCM таким чином, що неможливо змінити їх порядок.Код:val secretFile = File(filesDir, "super_secret") val encryptedFile = EncryptedFile.Builder( secretFile, applicationContext, advancedKeyAlias, FileEncryptionScheme.AES256_GCM_HKDF_4KB) .setKeysetAlias("file_key") // опціонально .setKeysetPrefName("secret_shared_prefs") // опціонально .build() encryptedFile.openFileOutput().use { outputStream -> // Записуємо дані до нашого зашифрованого файлу encryptedFile.openFileInput().use { inputStream -> // Зчитуємо дані із нашого зашифрованого файлу }Шифруємо SharedPreferencesЯкщо вашому додатку необхідно зберегти пари ключ-значення – наприклад, ключі API – JetSec надає клас EncryptedSharedPreferences, який використовує той самий інтерфейс SharedPreferences, до якого ви звикли.І ключі, і значення зашифровано. Ключі шифруються з використанням AES256-SIV-CMAC, який забезпечує детермінований шифротекст; значення зашифровані за допомогою AES256-GCM і прив'язані до зашифрованого ключа. Ця схема дозволяє безпечно шифрувати дані ключа, водночас дозволяючи пошук.Код:EncryptedSharedPreferences.create( "my_secret_prefs", advancedKeyAlias, applicationContext, PrefKeyEncryptionScheme.AES256_SIV, PrefValueEncryptionScheme.AES256_GCM ).edit { // Update secret values }
Для публікації повідомлень створіть обліковий запис або авторизуйтесь