Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Trabaja con datos de forma más segura Parte de Android Jetpack

La biblioteca de seguridad proporciona una implementación de las prácticas recomendadas de seguridad en relación con la lectura y escritura de datos en reposo, y la creación y verificación de claves.

La biblioteca utiliza el patrón de compilador a fin de proporcionar configuraciones predeterminadas seguras para los siguientes niveles de seguridad:

  • Seguridad sólida que equilibra una excelente encriptación y un buen rendimiento. Este nivel de seguridad es apropiado para aplicaciones para consumidores, como apps bancarias y de chat, y para apps empresariales que realizan comprobaciones de revocación de certificados.
  • Seguridad máxima. Este nivel de seguridad es adecuado para las apps que requieren un almacén de claves con copia de seguridad en hardware y la presencia del usuario para proporcionar acceso a las claves.

En esta guía, se muestra cómo trabajar con las configuraciones de seguridad recomendadas de la biblioteca de seguridad y se incluye información sobre cómo leer y escribir de manera fácil y segura datos encriptados que se almacenan en archivos y preferencias compartidas.

Administración de claves

La biblioteca de seguridad utiliza un sistema de 2 partes para la administración de claves:

  • Un conjunto de claves que contiene una o más claves para encriptar un archivo o datos de preferencias compartidas. Se almacena el conjunto de claves en SharedPreferences.

  • Una clave principal (master) que encripta todos los conjuntos de claves. Esta se almacena utilizando el sistema del almacén de claves de Android.

Clases incluidas en la biblioteca

La biblioteca de seguridad incluye las siguientes clases a fin de proporcionar datos más seguros en reposo:

EncryptedFile

Proporciona implementaciones personalizadas de FileInputStream y FileOutputStream, lo que otorga a tu app operaciones de transmisión de lectura y escritura más seguras.

Para proporcionar operaciones seguras de lectura y escritura desde transmisiones de archivos, la biblioteca de seguridad utiliza el tipo primitivo de encriptación autenticada con datos asociados (AEAD). Obtén más información sobre este tipo primitivo en la documentación de la biblioteca Tink, en GitHub.

EncryptedSharedPreferences

Envuelve la clase SharedPreferences y encripta automáticamente claves y valores utilizando un método de dos esquemas:

  • Se encriptan las claves mediante un algoritmo de encriptación determinista, de modo que sea posible encriptar la clave y buscarla correctamente.
  • Se encriptan los valores con AES-256 GCM de una manera no determinista.

En las siguientes secciones, se muestra cómo usar estas clases para realizar operaciones comunes con archivos y preferencias compartidas.

Cómo incluir la biblioteca en tu proyecto

A fin de usar la biblioteca de seguridad, agrega la siguiente dependencia al archivo build.gradle del módulo de tu app:

dependencies {
    implementation "androidx.security:security-crypto:1.0.0-rc03"

    // For Identity Credential APIs
    implementation "androidx.security:security-identity-credential:1.0.0-alpha01"
}

Cómo leer archivos

En el siguiente fragmento de código, se muestra cómo usar EncryptedFile para leer el contenido de un archivo de una manera más segura:

Kotlin

// Although you can define your own key generation parameter specification, it's
// recommended that you use the value specified here.
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

val context = applicationContext
val fileToRead = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(
    File(DIRECTORY, fileToRead),
    context,
    masterKeyAlias,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()

val inputStream = encryptedFile.openFileInput()
val byteArrayOutputStream = ByteArrayOutputStream()
var nextByte: Int = inputStream.read()
while (nextByte != -1) {
    byteArrayOutputStream.write(nextByte)
    nextByte = inputStream.read()
}

val plaintext: ByteArray = byteArrayOutputStream.toByteArray()

Java

// Although you can define your own key generation parameter specification, it's
// recommended that you use the value specified here.
KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC;
String masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);

Context context = getApplicationContext();
String fileToRead = "my_sensitive_data.txt";
EncryptedFile encryptedFile = new EncryptedFile.Builder(
        new File(DIRECTORY, fileToRead),
        context,
        masterKeyAlias,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();

InputStream inputStream = encryptedFile.openFileInput();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int nextByte = inputStream.read();
while (nextByte != -1) {
    byteArrayOutputStream.write(nextByte);
    nextByte = inputStream.read();
}

byte[] plaintext = byteArrayOutputStream.toByteArray();

Cómo escribir archivos

En el siguiente fragmento de código, se muestra cómo usar EncryptedFile para escribir el contenido de un archivo de una manera más segura:

Kotlin

// Although you can define your own key generation parameter specification, it's
// recommended that you use the value specified here.
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
val fileToWrite = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(
    File(DIRECTORY, fileToWrite),
    context,
    masterKeyAlias,
    EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()

val fileContent = "MY SUPER-SECRET INFORMATION"
        .toByteArray(StandardCharsets.UTF_8)
encryptedFile.openFileOutput().apply {
    write(fileContent)
    flush()
    close()
}

Java

// Although you can define your own key generation parameter specification, it's
// recommended that you use the value specified here.
KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC;
String masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);

// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
String fileToWrite = "my_sensitive_data.txt";
EncryptedFile encryptedFile = new EncryptedFile.Builder(
        new File(DIRECTORY, fileToWrite),
        context,
        masterKeyAlias,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build();

byte[] fileContent = "MY SUPER-SECRET INFORMATION"
        .getBytes(StandardCharsets.UTF_8);
OutputStream outputStream = encryptedFile.openFileOutput();
outputStream.write(fileContent);
outputStream.flush();
outputStream.close();

En los casos prácticos que requieran seguridad adicional, completa los siguientes pasos:

  1. Crea un objeto KeyGenParameterSpec.Builder y pasa true a setUserAuthenticationRequired() y un valor mayor que 0 a setUserAuthenticationValidityDurationSeconds().
  2. Solicita al usuario que ingrese las credenciales mediante createConfirmDeviceCredentialIntent(). Obtén más información sobre cómo solicitar la autenticación de usuarios para el uso de la clave.

  3. Anula onActivityResult() para obtener la devolución de llamada de la credencial confirmada.

Para obtener más información, consulta Cómo solicitar la autenticación de usuario para el uso de la clave.

Cómo editar preferencias compartidas

En el siguiente fragmento de código, se muestra cómo usar EncryptedSharedPreferences para editar el conjunto de preferencias compartidas de un usuario de una manera más segura:

Kotlin

val sharedPreferences = EncryptedSharedPreferences
    .create(
    FILE_NAME,
    masterKeyAlias,
    context,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

val sharedPrefsEditor = sharedPreferences.edit()

Java

EncryptedSharedPreferences sharedPreferences = EncryptedSharedPreferences
        .create(
                FILE_NAME,
                masterKeyAlias,
                context,
                EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        );

SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit();