Cifrado de datos en Android con Jetpack Safety


publicado por Jon Markoff, defensor del personal desarrollador, seguridad de Android

Ilustración de Virginia Poltrack

¿Alguna vez ha tratado de cifrar datos en su aplicación? Como desarrollador, desea mantener los datos seguros y en manos de la parte destinada a usar. Pero si eres como la mayoría de los desarrolladores de Android, no tienes un equipo de seguridad dedicado para ayudar a cifrar los datos de tu aplicación correctamente. Al buscar en la web para aprender a cifrar datos, puede obtener respuestas que están desactualizadas varios años y proporcionar ejemplos incorrectos.

los Jetpack Stability (JetSec) la biblioteca de cifrado proporciona abstracciones para cifrar archivos y objetos SharedPreferences. La biblioteca promueve el uso de AndroidKeyStore mientras united states seguro y conocido primitivas criptográficas. El uso de EncryptedFile y EncryptedSharedPreferences le permite proteger localmente archivos que pueden contener datos confidenciales, claves API, tokens OAuth y otros tipos de secretos.

¿Por qué querrías encriptar datos en tu aplicación? No es Android, desde 5., cifrar el contenido de la partición de datos del usuario ¿por defecto? Ciertamente lo hace, pero hay algunos casos de uso en los que es posible que desee un nivel adicional de protección. Si tu aplicación usa almacenamiento compartido, debe cifrar los datos. En el directorio de inicio de la aplicación, su aplicación debe encriptar datos si su aplicación maneja información confidencial, que incluye, entre otros, información de identificación personal (PII), registros de salud, detalles financieros o datos empresariales. Cuando sea posible, le recomendamos que vincule esta información a la biometría para obtener un nivel adicional de protección.

Jetpack Security se basa en Tink, un proyecto de seguridad multiplataforma de código abierto de Google. Tink podría ser apropiado si necesita cifrado standard, cifrado híbrido o algo very similar. Las estructuras de datos de Jetpack Protection son totalmente compatibles con Tink.

Generación clave

Antes de comenzar a cifrar sus datos, es importante comprender cómo se mantendrán seguras sus claves de cifrado. Jetpack Safety utiliza un llave maestra, que cifra todas las subclaves que se utilizan para cada operación criptográfica. JetSec proporciona una clave maestra predeterminada recomendada en la clase MasterKeys. Esta clase utiliza una clave básica AES256-GCM que se genera y almacena en AndroidKeyStore. AndroidKeyStore es un contenedor que almacena claves criptográficas en el TEE o StrongBox, lo que dificulta su extracción. Las subclaves se almacenan en un objeto Configurable SharedPreferences.

Principalmente, utilizamos la especificación AES256_GCM_SPEC en Jetpack Safety, que se recomienda para casos de uso standard. AES256-GCM es simétrico y generalmente rápido en dispositivos modernos.

val keyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)

Para las aplicaciones que requieren más configuración o manejan datos muy confidenciales, se recomienda crear su KeyGenParameterSpec, eligiendo opciones que tengan sentido para su uso. Teclas con límite de tiempo con BiometricPrompt puede proporcionar un nivel adicional de protección contra dispositivos enraizados o comprometidos.

Opciones importantes:

  • userAuthenticationRequired() y userAuthenticationValiditySeconds() se puede usar para crear una clave con límite de tiempo. Las claves con límite de tiempo requieren autorización usando BiometricPrompt tanto para el cifrado como para el descifrado de claves simétricas.
  • unlockedDeviceRequired() establece una marca que ayuda a garantizar que no se pueda acceder a la clave si el dispositivo no está desbloqueado. Esta bandera está disponible en Android Pie y excellent.
  • Utilizar setIsStrongBoxBacked(), para ejecutar operaciones de cifrado en un chip separado más fuerte. Esto tiene un ligero impacto en el rendimiento, pero es más seguro. Está disponible en algunos dispositivos que ejecutan Android Pie o excellent.

Nota: Si su aplicación necesita encriptar datos en segundo plano, no debe usar claves con límite de tiempo ni requerir que el dispositivo esté desbloqueado, ya que no podrá lograr esto sin la presencia de un usuario.

// Custom made Advanced Grasp Key
val advancedSpec = KeyGenParameterSpec.Builder(
    "learn_vital",
    KeyProperties.Purpose_ENCRYPT or KeyProperties.Function_DECRYPT
).apply 
    setBlockModes(KeyProperties.BLOCK_Mode_GCM)
    setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
    setKeySize(256)
    setUserAuthenticationRequired(accurate)
    setUserAuthenticationValidityDurationSeconds(15) // ought to be greater than 
    if (Build.Edition.SDK_INT >= Create.Version_CODES.P) 
        setUnlockedDeviceRequired(correct)
        setIsStrongBoxBacked(real)
    
.make()

val advancedKeyAlias = MasterKeys.getOrCreate(advancedSpec)

Desbloqueo de claves con límite de tiempo

Debe usar BiometricPrompt para autorizar el dispositivo si su clave se creó con las siguientes opciones:

  • userAuthenticationRequired es verdad
  • userAuthenticationValiditySeconds >

Después de que el usuario se autentica, las claves se desbloquean durante el tiempo establecido en el campo de segundos de validez. AndroidKeystore no tiene una API para consultar configuraciones clave, por lo que su aplicación debe realizar un seguimiento de estas configuraciones. Debe compilar su instancia de BiometricPrompt en el onCreate() método de la actividad donde presenta el diálogo al usuario.

Código BiometricPrompt para desbloquear claves con límite de tiempo

// Exercise.onCreate

val promptInfo = PromptInfo.Builder()
    .setTitle("Unlock?")
    .setDescription("Would you like to unlock this essential?")
    .setDeviceCredentialAllowed(legitimate)
    .establish()

val biometricPrompt = BiometricPrompt(
    this, // Action
    ContextCompat.getMainExecutor(this),
    authenticationCallback
)

private val authenticationCallback = object : AuthenticationCallback() 
        override fun onAuthenticationSucceeded(
            consequence: AuthenticationResult
        ) 
            super.onAuthenticationSucceeded(result)
            // Unlocked -- do get the job done here.
        
        override enjoyable onAuthenticationError(
            errorCode: Int, errString: CharSequence
        ) 
            tremendous.onAuthenticationError(errorCode, errString)
            // Tackle mistake.
        
    

To use:
biometricPrompt.authenticate(promptInfo)

Cifrar archivos

Jetpack Security incluye una clase EncryptedFile, que elimina los desafíos de cifrar datos de archivos. Equivalent a File, EncryptedFile proporciona un objeto FileInputStream para leer y un objeto FileOutputStream para escribir. Los archivos se cifran usando Streaming AEAD, que sigue la definición OAE2. Los datos se dividen en fragmentos y se cifran con AES256-GCM de tal manera que no es posible reordenarlos.

val secretFile = File(filesDir, "super_magic formula")
val encryptedFile = EncryptedFile.Builder(
    secretFile,
    applicationContext,
    advancedKeyAlias,
    FileEncryptionScheme.AES256_GCM_HKDF_4KB)
    .setKeysetAlias("file_critical") // optional
    .setKeysetPrefName("secret_shared_prefs") // optional
    .build()

encryptedFile.openFileOutput().use  outputStream ->
    // Write knowledge to your encrypted file


encryptedFile.openFileInput().use  inputStream ->
    // Study knowledge from your encrypted file

Cifrar preferencias compartidas

Si su aplicación necesita guardar pares clave-valor, como las claves API, JetSec proporciona la clase EncryptedSharedPreferences, que utiliza la misma interfaz SharedPreferences a la que está acostumbrado.

Tanto las claves como los valores están encriptados. Las claves se encriptan usando AES256-SIV-CMAC, que proporciona un texto de cifrado determinista los valores se cifran con AES256-GCM y están vinculados a la clave cifrada. Este esquema permite que los datos clave se cifren de forma segura, al tiempo que permite búsquedas.

EncryptedSharedPreferences.build(
    "my_key_prefs",
    advancedKeyAlias,
    applicationContext,
    PrefKeyEncryptionScheme.AES256_SIV,
    PrefValueEncryptionScheme.AES256_GCM
).edit 
    // Update secret values

Más recursos

FileLocker es una aplicación de muestra en la página de muestras de Android Security GitHub. Es un gran ejemplo de cómo usar el cifrado de archivos con Jetpack Protection.

¡Feliz cifrado!



Enlace a la noticia authentic