Condividi i caratteri password
(a char[]
) e salt
(a byte[]
—8 byte selezionati da a SecureRandom
rende un buon sale — che non ha bisogno di essere tenuto segreto) con il destinatario fuori banda. Quindi per ottenere una buona chiave da queste informazioni:
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
I numeri magici (che potrebbero essere definiti come costanti da qualche parte) 65536 e 256 sono rispettivamente il conteggio dell'iterazione di derivazione della chiave e la dimensione della chiave.
La funzione di derivazione chiave viene ripetuta per richiedere un notevole sforzo computazionale e ciò impedisce agli aggressori di provare rapidamente molte password diverse. Il conteggio delle iterazioni può essere modificato in base alle risorse di elaborazione disponibili.
La dimensione della chiave può essere ridotta a 128 bit, che è ancora considerata una crittografia "forte", ma non dà molto margine di sicurezza se vengono scoperti attacchi che indeboliscono AES.
Utilizzata con una modalità di concatenamento di blocchi appropriata, la stessa chiave derivata può essere utilizzata per crittografare molti messaggi. In Cipher Block Chaining (CBC) , viene generato un vettore di inizializzazione casuale (IV) per ciascun messaggio, producendo un testo di cifratura diverso anche se il testo normale è identico. CBC potrebbe non essere la modalità più sicura disponibile (vedere AEAD di seguito); ci sono molte altre modalità con proprietà di sicurezza diverse, ma tutte usano un input casuale simile. In ogni caso, gli output di ciascuna operazione di crittografia sono il testo della cifra e il vettore di inizializzazione:
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));
Conservare il ciphertext
e il iv
. Al momento della decodifica, SecretKey
viene rigenerato esattamente allo stesso modo, usando la password con gli stessi parametri salt e iterazione. Inizializza la cifra con questa chiave e il vettore di inizializzazione memorizzato con il messaggio:
/* Decrypt the message, given derived key and initialization vector. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(ciphertext), "UTF-8");
System.out.println(plaintext);
Java 7 includeva il supporto API per le modalità di cifratura AEAD e il provider "SunJCE" incluso nelle distribuzioni OpenJDK e Oracle implementa queste a partire da Java 8. Una di queste modalità è fortemente consigliata al posto di CBC; proteggerà l'integrità dei dati e la loro privacy.
A java.security.InvalidKeyException
con il messaggio "Dimensione chiave illegale o parametri predefiniti" significa che la forza della crittografia è limitata; i file delle politiche sulla giurisdizione illimitata non si trovano nella posizione corretta. In un JDK, dovrebbero essere posizionati sotto${jdk}/jre/lib/security
In base alla descrizione del problema, sembra che i file delle politiche non siano installati correttamente. I sistemi possono facilmente avere più runtime Java; ricontrollare per assicurarsi che venga utilizzata la posizione corretta.