Nesta resposta, optei por abordar o tema principal "Exemplo de criptografia / descriptografia simples de Java AES" e não a questão de depuração específica, porque acho que isso irá beneficiar a maioria dos leitores.
Este é um resumo simples da postagem do meu blog sobre criptografia AES em Java portanto, recomendo a leitura antes de implementar qualquer coisa. No entanto, ainda fornecerei um exemplo simples para usar e darei algumas dicas sobre o que observar.
Neste exemplo, vou escolher usar criptografia autenticada com modo Galois / Contador ou modo GCM . A razão é que na maioria dos casos você deseja integridade e autenticidade combinadas com confidencialidade (leia mais no blog ).
Tutorial de criptografia / descriptografia AES-GCM
Aqui estão as etapas necessárias para criptografar / descriptografar com AES-GCM com a Java Cryptography Architecture (JCA) . Não misture com outros exemplos , pois diferenças sutis podem tornar seu código totalmente inseguro.
1. Criar chave
Como depende do seu caso de uso, assumirei o caso mais simples: uma chave secreta aleatória.
SecureRandom secureRandom = new SecureRandom();
byte[] key = new byte[16];
secureRandom.nextBytes(key);
SecretKey secretKey = SecretKeySpec(key, "AES");
Importante:
2. Crie o vetor de inicialização
Um vetor de inicialização (IV) é usado para que a mesma chave secreta crie diferentes textos cifrados .
byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
secureRandom.nextBytes(iv);
Importante:
3. Criptografar com IV e Chave
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); //128 bit auth tag length
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] cipherText = cipher.doFinal(plainText);
Importante:
- usar etiqueta de autenticação de 16 bytes / 128 bits (usada para verificar integridade / autenticidade)
- a tag de autenticação será automaticamente anexada ao texto cifrado (na implementação JCA)
- uma vez que o GCM se comporta como uma cifra de fluxo, nenhum preenchimento é necessário
- usar
CipherInputStream
ao criptografar grandes blocos de dados
- deseja que dados adicionais (não secretos) sejam verificados caso tenham sido alterados? Você pode querer usar dados associados com
cipher.updateAAD(associatedData);
Mais aqui.
3. Serializar para mensagem única
Basta anexar IV e o texto cifrado. Como afirmado acima, o IV não precisa ser segredo.
ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + cipherText.length);
byteBuffer.put(iv);
byteBuffer.put(cipherText);
byte[] cipherMessage = byteBuffer.array();
Opcionalmente, codifique com Base64 se precisar de uma representação de string. Use a implementação integrada do Android ou do Java 8 (não use o Apache Commons Codec - é uma implementação horrível). A codificação é usada para "converter" matrizes de bytes em representação de string para torná-las ASCII seguras, por exemplo:
String base64CipherMessage = Base64.getEncoder().encodeToString(cipherMessage);
4. Prepare a descriptografia: desserialize
Se você codificou a mensagem, primeiro decodifique-a para a matriz de bytes:
byte[] cipherMessage = Base64.getDecoder().decode(base64CipherMessage)
Importante:
5. Descriptografar
Inicialize a cifra e defina os mesmos parâmetros da criptografia:
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
//use first 12 bytes for iv
AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, cipherMessage, 0, 12);
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmIv);
//use everything from 12 bytes on as ciphertext
byte[] plainText = cipher.doFinal(cipherMessage, 12, cipherMessage.length - 12);
Importante:
- não se esqueça de adicionar dados associados com
cipher.updateAAD(associatedData);
se você os adicionou durante a criptografia.
Um trecho de código funcional pode ser encontrado nesta essência.
Observe que as implementações mais recentes do Android (SDK 21+) e Java (7 +) devem ter AES-GCM. Versões mais antigas podem não ter. Eu ainda escolho este modo, pois é mais fácil de implementar além de ser mais eficiente em comparação com o modo semelhante de Encrypt-then-Mac (com por exemplo AES-CBC + HMAC ). Veja este artigo sobre como implementar AES-CBC com HMAC .