Android

8 dez, 2017

Biometria no Android

Publicidade

A Era da Biometria chegou! Grandes bancos do país já exigem o uso dela, e com o lançamento do Samsung Galaxy S8 e do iPhone X, novos métodos de autenticação usando biometria facial e de íris agora estão disponíveis nos dispositivos móveis. O Android, rodando atualmente em mais de 2 bilhões de devices ativos e apostando em IoT, se apresenta como uma opção para o crescimento e adoção da tecnologia em diversos segmentos.

Destes, um dos mais promissores é o mercado de pagamentos, no qual gigantes do mercado financeiro e empresas de tecnologia começam a competir através do uso de tecnologias, como Android e Apple Pay. Mas autenticar (dizer que algo é genuíno) uma pessoa é algo sensível e a segurança da informação é, mais do que nunca, essencial no uso desse tipo de tecnologia.

Neste artigo (1 de 2), conheceremos o sistema de segurança de chaves do Android, e no segundo veremos como usar ele em conjunto com as APIs de biometria e autenticação.

Relembrando a Segurança de informação

Antes de entrarmos nos detalhes do Android, vamos relembrar os elementos e o funcionamento de sistemas de criptografia de dados também utilizados em biometria e autenticação. São eles:

  • Mensagem –  Qualquer informação que queiramos transmitir (ou proteger) a alguém de forma que somente o destinatário seja capaz de compreender;
  • Chave  – Informação base usada pelo algoritmo de cifragem para codificação da mensagem;
  • Algoritmo de Cifragem  – Existem diversos, os mais comuns são DES e AES;

De modo simplificado, podemos dizer que o processo de proteção de informação se aplica às seguintes funções:

No remetente:

p = A(m,c)

O algoritmo ‘A’ é aplicado à mensagem ‘m’ e usa a chave ‘c’ para gerar a mensagem cifrada ‘p’ que vai ser transmitida ao destinatário.

No destinatário:

m = A(p,c)

Para que o destinatário consiga compreender a informação e decifrar a mensagem, vai receber a mensagem cifrada ‘p’, a chave ‘c’ e vai aplicar o algoritmo ‘A’.

Com isso, podemos observar então que o conhecedor do algoritmo ‘A’ e a chave ‘c’ vai conseguir decifrar qualquer mensagem e, sabemos que geralmente os algoritmos ‘A’ usados são algoritmos de conhecimento público, ficando então como segredo somente a chave.

Proteção no Android

Agora que relembramos como funciona a proteção de informações e que a chave é o elemento crucial nesse processo, é importante sabermos que quando colocamos qualquer mecanismo de proteção no Android (Fingerprint, Pin, Padrão, Irís, etc) essa informação é cifrada, uma chave é criada e guardada no seu aparelho. O que nos traz à mente algumas questões importantes, como:

  • Onde ficam guardadas as chaves?
  • É seguro?
  • E se alguém roubar essas chaves, pode se passar por mim?
  • Se eu habilitar root no aparelho tenho acesso a elas?

Vamos entender como funciona isso mais adiante.

KeyStore System

Para proteger as chaves, o Android disponibiliza o KeyStore System, e é a partir da API 18 (Jelly Bean), o “AndroidKeyStoreProvider”, que os apps podem usar para gerar chaves específicas para uso próprio, como por exemplo, no uso de autenticação.

No KeyStore System ficam armazenados os vários tipos de chave (Certificados digitais, chaves Sign/Verify e Crypto), logo ele disponibiliza alguns mecanismos que podemos utilizar para proteger e liberar/bloquear o acesso a elas.

No momento da criação de uma chave, definimos que o acesso a elas será:

  • Só quando usuário estiver autenticado;
  • Por um tempo determinado (por cinco minutos, por exemplo);
  • Enquanto não houver mudança no device (nova digital cadastrada, mudança de pin);
  • Ou sem proteção alguma (uso geral no device, por exemplo).

Modelo de Segurança

Para assegurar o acesso às chaves contra tampering (adulteração), extração (cópia) ou compromizing do app (update adulterando, hacking de intent), o acesso às chaves e à autenticação nunca é feito dentro do processo do app.

O Keystore System executa como um processo protegido a parte onde os apps se comunicam com ele através de IPC. Dessa forma, as chaves não são expostas a outros processos.

Além disso, alguns devices rodando Android Nougat (API 24) possuem um mecanismo de proteção conhecido como Trusted Execution Environment (TEE) ou Secure Element (SE), que são, na prática, um processador ou área do processador que executa operações de forma protegida (usando um Trusted OS) que impede a extração da chave para uso em outros devices ou ambientes, caso root esteja habilitado.

Hora das APIS

Agora que entendemos como as coisas funcionam, vamos aprender quais classes e APIs estão disponíveis para esse tipo de uso no Android. Primeiramente, precisamos saber que podemos gerar três tipos de chaves diferentes, cada uma com seu próprio uso e classe. Porém, antes de gerarmos a chave, temos que criar sua especificação com a classe KeyGenParameterSpec.

Agora veremos as peculiaridades na especificação de cada tipo de chave.

Chave para assinatura e verificação de informação

Geralmente usada em DRM (direitos autorais), pode ser usada também para adicionar assinatura digital em qualquer tipo de mensagem. Esse tipo de chave utiliza os seguintes parâmetros:

  • ALIAS = Nome usado na identificação da chave;
  • PURPOSE = Propósito de uso da chave (Sign/Verify);
  • DIGEST = Função hash utilizada na geração da chave;
  • BLOCK MODE = Algoritmo que usa blocos (de bytes) na geração da chave;
  • PADDING = Espécie de “preenchimento” em bytes da chave usado de acordo com o tipo de algoritmo usado;

Abaixo, vemos um exemplo de geração de chave de assinatura/verificação usando KeyGenParameterSpec e KeyPairGenerator:

KeyGenParameterSpec keyGenParameterSpec =
        new KeyGenParameterSpec.Builder(KEY_ALIAS, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
                .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
                .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
                .build();
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM_AES, ANDROID_KEYSTORE_PROVIDER);
kpg.initialize(keyGenParameterSpec);

KeyPair keyPair = kpg.generateKeyPair();

Um ponto importante de observarmos é o uso da classe KeyPairGenerator. Usamos ela, pois esse tipo de chave é usado no envio/recebimento de mensagens assinadas.

Quando usamos KeyPair, geramos um par de chaves, uma chave privada e uma chave pública geralmente enviada ao destinatário para verificação da assinatura.

Abaixo podemos ver um exemplo de como usamos esse tipo de chave para assinar e verificar uma mensagem “assinada digitalmente”.

Assinatura

KeyStore keyStore = getKeyStore();

KeyStore.Entry entry = keyStore.getEntry(KEY_ALIAS, null);

if(!(entry instanceof KeyStore.PrivateKeyEntry))
    return null;

Signature signature = Signature.getInstance(HASH_SHA256withECDSA_ALGORITHM);
signature.initSign(((KeyStore.PrivateKeyEntry) entry).getPrivateKey());
signature.update(data);

byte[] signatureBytes = signature.sign();

Verificação

KeyStore keyStore = getKeyStore();

KeyStore.Entry entry = keyStore.getEntry(KEY_ALIAS, null);

if(!(entry instanceof KeyStore.PrivateKeyEntry))
    return false;

Signature signature = Signature.getInstance(HASH_SHA256withECDSA_ALGORITHM);
signature.initVerify(((KeyStore.PrivateKeyEntry) entry).getCertificate());
signature.update(data);

return signature.verify(signatureBytes);

Chave Secreta

Usamos esse tipo de chave geralmente para proteção de identidade. Nesse caso, é o tipo de chave usada junto com mecanismos de Biometria como Fingerprint, Íris, Rosto, etc. Nesse tipo de chave, é altamente recomendável usarmos os mecanismos de proteção mencionados previamente.

No exemplo abaixo, vemos como gerar uma chave secreta, protegida por autenticação e mudanças na biometria cadastradas no device (novos dedos, padrões, pins, etc).

KeyGenParameterSpec keyGenParameterSpec =
        new KeyGenParameterSpec
                .Builder(KEY_ALIAS_NEW, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
                .setUserAuthenticationRequired(true)
                .setInvalidatedByBiometricEnrollment(true)
                .build();
KeyGenerator kpg = KeyGenerator.getInstance(KEY_ALGORITHM_AES, ANDROID_KEYSTORE_PROVIDER);
kpg.init(keyGenParameterSpec);

Key key = kpg.generateKey();

Nesse código podemos observar alguns pontos novos, por exemplo:

  • O uso da classe KeyGenerator no lugar do KeyPair usada então para geração de SecretKeys.
  • O purpose que neste caso é a cifragem/decifragem.
  • A chamada de .setUserAuthenticationRequired que bloqueia/libera o uso da chave baseado na recência da autenticação do usuário no dispositivo.
  • A chamada de .setInvalidatedByBiometricEnrollment que informa ao Android que, caso haja uma mudança na biometria registrada no device (um novo dedo, nova íris, etc) a chave deve ser invalidada.
  • Essa feature é muito útil para caso você esqueça o device desbloqueado por um curto período de tempo, mas tempo suficiente para alguém registrar uma nova biometria no seu device.

Além dessas proteções, existe mais uma, que é o bloqueio/desbloqueio da chave por um tempo determinado.

Muito útil para cenários de pagamento, por exemplo, imagine que você utilize uma carteira digital (Android Pay, Apple Pay, etc) onde basta você aproximar seu celular do dispositivo para autorizar um pagamento.

Colocando esse tipo de “trava” na chave, mesmo que alguém pegue o seu celular e tente usar, passado o tempo determinado, o Android obrigará você a autenticar-se novamente no device.

Para isso, basta adicionar o tempo de validade usando .setUserAuthenticationValidityDurationSeconds(), como no exemplo abaixo:

KeyGenParameterSpec keyGenParameterSpec =
        new KeyGenParameterSpec
                .Builder(KEY_ALIAS_NEW, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
                .setUserAuthenticationRequired(true)
                .setUserAuthenticationValidityDurationSeconds(120)
                .setInvalidatedByBiometricEnrollment(true)
                .build();

Para finalizar

Esta foi a primeira parte. Na segunda, veremos como as APIs de biometria e autenticação trabalham em conjunto com o KeyStore System para garantir a segurança dos seus dados.

Abraços e até a próxima!