In questa risposta scelgo di avvicinarmi al tema principale "Semplice esempio di crittografia / decrittografia AES Java" e non alla specifica domanda di debug perché penso che questo trarrà vantaggio dalla maggior parte dei lettori.
Questo è un semplice riassunto del mio post sul blog sulla crittografia AES in Java, quindi consiglio di leggerlo prima di implementare qualsiasi cosa. Tuttavia fornirò ancora un semplice esempio da utilizzare e fornirò alcuni suggerimenti a cosa fare attenzione.
In questo esempio, sceglierò di utilizzare la crittografia autenticata con la modalità Galois / Counter o GCM . Il motivo è che nella maggior parte dei casi desideri integrità e autenticità in combinazione con riservatezza (leggi di più nel blog ).
Tutorial sulla crittografia / decrittografia AES-GCM
Di seguito sono riportati i passaggi necessari per crittografare / decrittografare con AES-GCM con Java Cryptography Architecture (JCA) . Non mischiare con altri esempi , poiché sottili differenze potrebbero rendere il tuo codice completamente insicuro.
1. Crea chiave
Poiché dipende dal tuo caso d'uso, assumerò il caso più semplice: una chiave segreta casuale.
SecureRandom secureRandom = new SecureRandom();
byte[] key = new byte[16];
secureRandom.nextBytes(key);
SecretKey secretKey = SecretKeySpec(key, "AES");
Importante:
2. Creare il vettore di inizializzazione
Viene utilizzato un vettore di inizializzazione (IV) in modo che la stessa chiave segreta crei diversi testi cifrati .
byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
secureRandom.nextBytes(iv);
Importante:
3. Crittografa con IV e chiave
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:
- utilizzare tag di autenticazione a 16 byte / 128 bit (utilizzato per verificare integrità / autenticità)
- il tag di autenticazione verrà automaticamente aggiunto al testo cifrato (nell'implementazione JCA)
- poiché GCM si comporta come un cifrario a flusso, non è richiesto alcun riempimento
- utilizzare
CipherInputStream
quando si crittografano grandi blocchi di dati
- vuoi controllare dati aggiuntivi (non segreti) se sono stati modificati? Potresti voler utilizzare i dati associati con
cipher.updateAAD(associatedData);
Altro qui.
3. Serializza in un singolo messaggio
Basta aggiungere IV e testo cifrato. Come affermato sopra, la flebo non deve essere segreta.
ByteBuffer byteBuffer = ByteBuffer.allocate(iv.length + cipherText.length);
byteBuffer.put(iv);
byteBuffer.put(cipherText);
byte[] cipherMessage = byteBuffer.array();
Facoltativamente codifica con Base64 se hai bisogno di una rappresentazione di stringa. Utilizza l' implementazione integrata di Android o Java 8 (non utilizzare Apache Commons Codec: è un'implementazione orribile). La codifica viene utilizzata per "convertire" array di byte in rappresentazioni di stringa per renderlo ASCII sicuro, ad esempio:
String base64CipherMessage = Base64.getEncoder().encodeToString(cipherMessage);
4. Preparare la decrittografia: deserializza
Se hai codificato il messaggio, prima decodificalo in un array di byte:
byte[] cipherMessage = Base64.getDecoder().decode(base64CipherMessage)
Importante:
5. Decrittografa
Inizializza la crittografia e imposta gli stessi parametri della crittografia:
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:
- non dimenticare di aggiungere i dati associati con
cipher.updateAAD(associatedData);
se li hai aggiunti durante la crittografia.
Uno snippet di codice funzionante può essere trovato in questo gist.
Tieni presente che le implementazioni Android (SDK 21+) e Java (7+) più recenti dovrebbero avere AES-GCM. Le versioni precedenti potrebbero non esserlo. Scelgo ancora questa modalità, poiché è più facile da implementare oltre ad essere più efficiente rispetto alla modalità simile di Encrypt-then-Mac (con ad esempio AES-CBC + HMAC ). Consulta questo articolo su come implementare AES-CBC con HMAC .