2013-08-14 17 views
41

Qual è il modo consigliato di generare una chiave AES casuale e sicura in Java, utilizzando il JDK standard?Come creare una chiave AES casuale sicura in Java?

in altri post, ho trovato questo, ma utilizzando un SecretKeyFactory potrebbe essere un'idea migliore:

KeyGenerator keyGen = KeyGenerator.getInstance("AES"); 
SecureRandom random = new SecureRandom(); // cryptograph. secure random 
keyGen.init(random); 
SecretKey secretKey = keyGen.generateKey(); 

Sarebbe bello se la risposta comprendeva una spiegazione del motivo per cui è un buon modo di generare la chiave casuale. Grazie!

+0

Questo mighth aiuto http://stackoverflow.com/questions/10252449/is-aes-key-random – Tala

+0

@Tala Ecco dove ho trovato il [codice citato] (http://stackoverflow.com/a/10252662/1005481). Ma da quel post, non sono riuscito a determinare un consenso su come creare la chiave casuale, e perché era un modo sicuro. –

risposta

53

Vorrei utilizzare il codice suggerito, ma con una leggera semplificazione:

KeyGenerator keyGen = KeyGenerator.getInstance("AES"); 
keyGen.init(256); // for example 
SecretKey secretKey = keyGen.generateKey(); 

Lasciate che il fornitore di selezionare come intende ottenere casualità - non definire qualcosa che non può essere buono come quello che il fornitore ha già selezionato.

Questo esempio di codice presuppone (as Maarten points out below) di aver configurato il file java.security per includere il provider preferito in cima all'elenco. Se si desidera specificare manualmente il provider, è sufficiente chiamare lo KeyGenerator.getInstance("AES", "providerName");.

Per una chiave veramente sicura, è necessario utilizzare uno hardware security module (HSM) per generare e proteggere la chiave. I produttori di HSM in genere forniranno un fornitore JCE che eseguirà tutte le generazioni di chiavi per te, utilizzando il codice sopra riportato.

+1

Normalmente vorrei omettere anche il nome del fornitore. Configura la piattaforma (ad esempio usando il file 'java.security' o configurando' Provider' a livello di programmazione usando 'Security.addProvider()' e allo stesso modo). In caso contrario, il codice sarà meno portabile e non consentirebbe all'utente di passare ad es. un HSM senza modificare il codice dell'applicazione. –

+0

Perché dovrei specificare il fornitore? Il comportamento predefinito consiste nell'utilizzare il provider installato con la massima priorità che supporta l'algoritmo, che mi sembra sufficiente. –

+2

Non tutti i metodi di generazione delle chiavi sono creati uguali e potresti voler scegliere esplicitamente, ad es. il metodo di generazione della chiave di un fornitore. Questo è particolarmente utile per i provider di token di sicurezza. Tuttavia, per AES, il generatore di numeri casuali potrebbe essere più importante: si potrebbe ad esempio voler utilizzare un generatore di numeri casuali certificato FIPS più lento e più sicuro invece del valore predefinito. –

19

Utilizzare KeyGenerator come metodo preferito. Come indicato da Duncan, darei sicuramente le dimensioni della chiave durante l'inizializzazione. KeyFactory è un metodo che dovrebbe essere utilizzato per le chiavi preesistenti.

OK, quindi passiamo al nocciolo della questione. In linea di principio le chiavi AES possono avere qualsiasi valore. Non ci sono "chiavi deboli" come in (3) DES. Né ci sono bit che abbiano un significato specifico come in (3) bit di parità DES. Quindi generare una chiave può essere semplice come generare un array di byte con valori casuali e creare uno SecretKeySpec attorno ad esso.

Ma ci sono ancora vantaggi per il metodo che si sta utilizzando: lo KeyGenerator è stato creato appositamente per generare chiavi. Ciò significa che il codice potrebbe essere ottimizzato per questa generazione. Questo potrebbe avere vantaggi di efficienza e sicurezza. Potrebbe essere programmato per evitare attacchi di canale laterali temporali che potrebbero esporre la chiave, per esempio. Tieni presente che potrebbe essere già una buona idea svuotare qualsiasi byte[] che contiene le informazioni chiave in quanto potrebbero essere trapelate in un file di scambio (tuttavia, questo potrebbe comunque essere il caso).

Inoltre, come detto, non tutti gli algoritmi utilizzano chiavi completamente casuali. Quindi utilizzando KeyGenerator renderebbe più semplice passare ad altri algoritmi. Tuttavia, i codici più moderni accettano solo chiavi completamente casuali; questo è visto come un importante vantaggio rispetto ad es. DES.

Infine, e nel mio caso il motivo più importante, è che il metodo KeyGenerator è l'unico metodo valido per gestire le chiavi AES all'interno di un token sicuro (smart card, TPM, token USB o HSM). Se si creacon SecretKeySpec, la chiave deve essere provenire dalla memoria. Ciò significa che la chiave può essere inserita nel token sicuro, ma che la chiave è esposta in memoria a prescindere. Normalmente, i token sicuri funzionano solo con chiavi generate nel token sicuro o iniettate da es. una smart card o una cerimonia chiave. Un KeyGenerator può essere fornito con un provider in modo che la chiave venga generata direttamente nel token sicuro.

Come indicato in Duncan's answer: specificare sempre la dimensione della chiave (e qualsiasi altro parametro) in modo esplicito. Non fare affidamento sui valori predefiniti del provider in quanto questo corrisponderà a e renderà poco chiaro cosa sta facendo l'applicazione e ciascun provider potrebbe avere i suoi valori predefiniti.

+0

Grazie per questa eccellente informazione di base! –

+0

Più siamo, meglio è. Un'ottima risposta come al solito :-) –

2

Un sacco di buoni progressi negli altri post. Questo è quello che uso:

Key key; 
SecureRandom rand = new SecureRandom(); 
KeyGenerator generator = KeyGenerator.getInstance("AES"); 
generator.init(256, rand); 
key = generator.generateKey(); 

Se avete bisogno di un altro provider casualità, che io qualche volta faccio a scopo di test, basta sostituire rand con

MySecureRandom rand = new MySecureRandom(); 
+0

La prima volta che specificherò il generatore casuale, la seconda volta la lunghezza del tasto AES da usare (256). Sono metodi di init separati. – Andy

Problemi correlati