2013-01-02 17 views
5

Perché questo INIT successo:Perché il mio AES Cipher gettare un InvalidKeyException su init di DECRYPT_MODE

Cipher AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
AESCipher.init(Cipher.ENCRYPT_MODE, secretKey, secRandom); 

mentre questo non riesce:

Cipher AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
AESCipher.init(Cipher.DECRYPT_MODE, secretKey, secRandom); 

Lanciare un Exception in thread java "principale". security.InvalidKeyException: Parametri mancanti

Il secretKey è generato da un KeyGenerator e il secureRandom da SecureRandom.getInstance ("SHA1PRNG") con un valore casuale set di semi atici.

Grazie

+1

Perché si passa un RNG all'operazione di decrittografia? Immagino che l'RNG sia usato per generare l'IV, quindi per la decrittografia probabilmente devi passare nella IV e non in un RNG. – CodesInChaos

+0

Grazie. Quindi perché init ottiene un secRandom in primo luogo? È il modo corretto per ottenere alcuni byte dal secRandom, salvarli come IV e quindi usarli come se si usasse un nuovo IvParameterSpec? Successivamente passare la IV alla decrittografia nello stesso modo? – user54000

+2

Probabilmente prende l'RNG in modo che possa creare la IV stessa invece di infastidirla. Ma non ho familiarità con le API di java crypto. – CodesInChaos

risposta

5

Come ipotizzato correttamente CodeInChaos, l'istanza SecureRandom è usato per derivare una IV casuale quando l'istanza AESCipher viene creato con Cipher.ENCRYPT_MODE. Tuttavia, lo si fornisce come parametro durante la creazione di un'istanza Cipher in modalità decrittografia. Questo piccolo frammento di codice senza senso mostra un esempio.

public static void main(String[] args) throws Exception { 
    SecureRandom secRandom = SecureRandom.getInstance("SHA1PRNG"); 
    KeyGenerator kg = KeyGenerator.getInstance("AES"); 
    kg.init(128, secRandom); 
    Key secretKey = kg.generateKey(); 
    Cipher AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    AESCipher.init(Cipher.ENCRYPT_MODE, secretKey, secRandom); 
    IvParameterSpec iv = new IvParameterSpec(AESCipher.getIV()); 
    AESCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    AESCipher.init(Cipher.DECRYPT_MODE, secretKey,iv, secRandom); 
} 

Inoltre, la tua affermazione che si inizializza l'istanza SecureRandom con un seme statica suggeriscono un equivoco di quella classe. SecureRandom non garantisce che otterrai lo stesso risultato quando fornisci lo stesso seme. Se osservi attentamente lo Javadocs vedrai che tenta di fornire qualche vera entropia da altre fonti, se possibile.

EDIT 1:

Grazie a owlstead per la sua solita meticolosità nel rivedere le risposte. Vedere il suo answer a una domanda correlata per ulteriori discussioni. Il codice sorgente per SHA1PRNG è disponibile online here. È un po 'difficile da seguire, ma se fornisci un seme prima del chiedendo l'istanza per ogni byte casuale, l'output sarà completamente deterministico. Quindi la mia affermazione precedente non è corretta.

+0

Em, questa è una oops penso che l'implementazione di "SHA1PRNG" 'di Java garantisca lo stesso output quando viene alimentato lo stesso seme, * se il seed è impostato prima di chiamare qualsiasi metodo che recuperi i dati casuali *, vedere potrebbe rispondere [qui] (http://stackoverflow.com/questions/13923247/does-the-sha1prng-algorithm-for-securerandom-use-dev-random-for-entropy) e il JavaDoc del ['SecureRandom'] (http: // docs .oracle.com/javase/7/docs/api/java/security/SecureRandom.html) classe –

+0

Si noti che è estremamente imprudente usare questo metodo per generare una chiave. L'output non è specificato abbastanza bene da usarlo per generare chiavi o IV di materiale statico. Quindi in questo senso l'osservazione è corretta; ** non utilizzare 'SecureRandom' per generare chiavi o IV di materiale di chiavi statiche **. –

2

Basta leggere il JavaDoc del init method with SecureRandom che si sta applicando:

Se questa cifra richiede eventuali parametri dell'algoritmo che non può essere derivata dalla chiave data, l'implementazione cifra di fondo è dovrebbe generare la richiesta parametri stesso (utilizzando di default provider specifico o valori casuali) se è in fase di inizializzazione per la crittografia o la confezione chiave, e sollevare un InvalidKeyException se esso viene inizializzato per la decrittazione o Scartare chiave. I parametri generati da possono essere recuperati utilizzando getParameters o getIV (se il parametro è un IV).

È necessario trasferire l'IV crittografato al metodo di decrittografia, ad es. anteponendolo al testo cifrato. L'IV può essere trasferito in chiaro. Utilizzare IvParameterSpec anziché SecureRandom per impostare l'IV per la decrittografia.

+1

Personalmente, penso che l'intero concetto di generare valori predefiniti o specifici del provider sia una funzione stupida dell'API di crittografia Java, quindi uso sempre "IvParameterSpec' e lo inserisco con valori casuali durante la crittografia. Molto più facile da eseguire il debug e anche le chiamate di crittografia e decrittografia sono piacevolmente simmetriche. –

+0

concordato. Non dirò che le impostazioni predefinite devono teoricamente essere sempre un disastro, ma non ho mai visto un'implementazione in cui non abbiano causato più problemi che poi hanno risolto. Non utilizzare i valori predefiniti nell'API di crittografia Java, non utilizzare i set di caratteri predefiniti ... basta evitare i valori predefiniti. –