Как безопасно хранить ключи шифрования в Android?

Я хочу знать, как безопасно хранить ключ шифрования в Android? Каков наилучший сценарий для защиты шифрования и секретных ключей?

4 ответа

Решение

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

Android Keystore предназначен для генерации и защиты ваших ключей. Но он недоступен для уровня API ниже 18 и имеет некоторые ограничения до уровня API 23.

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

  • Уровень API < 18: Android Keystore отсутствует. Запросить пароль пользователя, получить ключ шифрования из пароля. Недостатком является то, что вам нужно запросить пароль при запуске приложения. Ключ шифрования не хранится в устройстве. Он рассчитывается каждый раз, когда приложение запускается с использованием пароля

  • Уровень API>=18 <23: Android Keystore доступен без поддержки AES. Сгенерируйте случайный ключ AES, используя поставщик криптографии по умолчанию (не используя AndroidKeystore). Сгенерируйте пару ключей RSA в Android Keystore и зашифруйте ключ AES с помощью открытого ключа RSA. Сохраните зашифрованный ключ AES в Android SharedPreferences. При запуске приложения расшифруйте ключ AES с помощью закрытого ключа RSA

  • Уровень API>=23: Android Keystore доступен с поддержкой AES. Генерация случайного ключа AES с помощью Android Keystore. Вы можете использовать его напрямую.

Для шифрования можно использовать AES/CBC/PKCS7Padding алгоритм. Для шифрования ваших данных требуется также случайный вектор инициализации (IV), но он может быть общедоступным.

Альтернативы:

  • Уровень API>14: Брелок Android: KeyChain - это хранилище учетных данных для всей системы. Вы можете установить сертификаты с закрытыми ключами, которые могут использоваться приложениями. Используйте предварительно установленный ключ для шифрования / дешифрования вашего ключа AES, как показано во втором случае выше.

  • Внешний токен: Защищенные ключи не хранятся в устройстве. Вы можете использовать внешний токен, содержащий пару секретных / открытых ключей, которая позволяет шифровать ключ AES. Токен можно получить с помощью Bluetooth или NFC.

Похоже, вам нужен EncryptedSharedPreferences или EncryptedFile. Оба они используют AndroidKeyStore. Приведенные ниже фрагменты кода фактически отвечают на вопрос "Как использовать AndroidKeystore для шифрования файла или хранения криптографического ключа?"

Не забудьте включить implementation "androidx.security:security-crypto:1.0.0-rc02" в вашем приложении build.gradle файл.

из EncryptedSharedPreferences:

Реализация SharedPreferences, которая шифрует ключи и значения.

String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);

SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
  "secret_shared_prefs",
  masterKeyAlias,
  context,
  EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
  EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);

// use the shared preferences and editor as you normally would
SharedPreferences.Editor editor = sharedPreferences.edit();

Вы можете хранить такой ключ шифрования:

// generate random symmetric key
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey symkey = keyGen.generateKey();


String alias = "your encryption key";

// store symmetric key
byte[] encodedSymmetricKey = symkey.getEncoded();
SharedPreferences.Editor edit = sharedPreferences.edit();
String base64EncodedSymmetricKey = new String(Base64.getEncoder().encode(encodedSymmetricKey));
edit.putString(alias, base64EncodedSymmetricKey);
edit.commit();

// retrieve symmetric key
String raw = sharedPreferences.getString(alias, null);
byte[] symKey = Base64.getDecoder().decode(raw);
SecretKeySpec spec = new SecretKeySpec(symKey, "AES");

assert(spec.equals(symkey));

// use your encryption key

Хотя было бы намного лучше использовать EncryptedFile.


из EncryptedFile:

Класс, используемый для создания и чтения зашифрованных файлов.

String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);

File file = new File(context.getFilesDir(), "secret_data");
EncryptedFile encryptedFile = EncryptedFile.Builder(
  file,
  context,
  masterKeyAlias,
  EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();

// write to the encrypted file
FileOutputStream encryptedOutputStream = encryptedFile.openFileOutput();

// read the encrypted file
FileInputStream encryptedInputStream = encryptedFile.openFileInput();

Примечание:
главный ключ, однажды созданный, является постоянным. Таким образом, даже после перезагрузки телефона ваше приложение по-прежнему сможет зашифровать / расшифровать файл.

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

Невозможно безопасно сохранить ваши закрытые ключи API в коде. Но вы можете использовать NDK для безопасного сохранения закрытых ключей. Получить ключ от NDK нетривиально. Ключ Secue с примером NDK

Вы можете использовать систему Android Keystore для хранения и получения конфиденциальной информации. Прочтите эту 5-минутную статью, чтобы понять, как это работает. Использование системы Android Keystore для хранения и получения конфиденциальной информации

Другие вопросы по тегам