2013-01-02 11 views
5

Dlaczego miałoby to Init uda:Dlaczego mój AES Cipher rzucić InvalidKeyException na init DECRYPT_MODE

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

podczas gdy to się nie powiedzie:

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

rzuca Wyjątek w wątku "głównym" Java. security.InvalidKeyException: Brak parametrów

Klucz tajny jest generowany przez KeyGenerator, a SecureRandom według SecureRandom.getInstance ("SHA1PRNG") z losowym st zestaw nasion atic.

Dzięki

+1

Dlaczego przekazujesz RNG do operacji deszyfrowania? Przypuszczam, że RNG jest używany do generowania IV, więc do odszyfrowania prawdopodobnie musisz przejść w IV, a nie RNG. – CodesInChaos

+0

Dzięki. Dlaczego więc init dostaje secRandom w pierwszej kolejności? Czy to właściwy sposób, aby najpierw pobrać trochę bajtów z secRandom, zapisać je jako IV, a następnie użyć ich jako nowego parametru IvParameterSpec? Później przekazywanie IV do deszyfrowania w ten sam sposób? – user54000

+2

To prawdopodobnie wymaga RNG, aby mógł sam utworzyć IV, zamiast zawracać sobie tym głowę. Ale nie jestem zaznajomiony z API Java Crypto. – CodesInChaos

Odpowiedz

5

Jak prawidłowo przypuszczać przez CodeInChaos instancja SecureRandom jest stosowany w celu uzyskania losowego IV, jeśli przykład AESCipher jest tworzony Cipher.ENCRYPT_MODE. Jednak podajesz go jako parametr podczas tworzenia instancji Cipher w trybie deszyfrowania. Ten mały, bezsensowny fragment kodu pokazuje przykład.

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); 
} 

Również Twoje twierdzenie, że inicjujesz instancję SecureRandom ze statycznym nasieniem, sugeruje nieporozumienie tej klasy. SecureRandom nie gwarantuje, że otrzymasz te same dane wyjściowe, gdy dostarczysz ten sam materiał siewny. Jeśli przyjrzysz się uważnie Javadocs, zobaczysz, że próbuje dostarczyć prawdziwej entropii z innych źródeł, jeśli to w ogóle możliwe.

EDIT 1:

Dzięki owlstead na swoim zwykłym sumienności w przeglądzie odpowiedzi. Zobacz jego answer na pokrewne pytanie w celu dodatkowej dyskusji. Kod źródłowy SHA1PRNG jest dostępny online pod numerem here. Trochę to trudne, ale jeśli dostarczysz ziarno , zanim zapyta instancję o dowolne losowe bajty, wynik będzie całkowicie deterministyczny. Moje wcześniejsze stwierdzenie jest nieprawidłowe.

+0

Em, to chyba Oops, implementacja Java "SHA1PRNG" gwarantuje to samo wyjście, gdy jest karmione tym samym nasieniem, * jeśli nasiono jest ustawione przed wywołaniem dowolnej metody, która pobiera losowe dane *, zobacz może odpowiedzieć [tutaj] (http://stackoverflow.com/questions/13923247/does-the-sha1prng-algorithm-for-securerandom-use-dev-random-for-entropy) i JavaDoc w ['SecureRandom'] (http: // docs .oracle.com/javase/7/docs/api/java/security/SecureRandom.html) class –

+0

Należy pamiętać, że używanie tej metody do generowania klucza jest niezwykle nierozsądne. Dane wyjściowe nie są wystarczająco dobrze określone, aby można je było wykorzystać do generowania kluczy lub IV z materiału statycznego klucza. W tym sensie uwaga jest prawidłowa; ** nie używaj 'SecureRandom' do generowania kluczy lub liter IV z materiału klucza statycznego **. –

2

Wystarczy przeczytać JavaDoc z init method with SecureRandom które się ubiegamy:

Jeśli ten szyfr wymaga żadnych parametrów algorytmu, który nie może być pochodzące z danego klawisza, podstawowe szyfr realizacja jest powinien generować wymagane same parametry (przy użyciu domyślnych lub losowych wartości specyficznych dla dostawcy) o wartości , jeśli jest inicjowana w celu szyfrowania lub zawijania klucza i podniesienia , jeśli jest inicjowana w celu odszyfrowania lub rozpakowania kluczy. Wygenerowane parametry można odzyskać, używając parametru getParameters lub (jeśli parametr to IV).

Będziesz musiał przenieść zaszyfrowany kod IV do metody deszyfrowania, np. poprzez dodanie go do tekstu zaszyfrowanego. IV może być przeniesiony w czysty. Użyj IvParameterSpec zamiast SecureRandom, aby ustawić IV do odszyfrowania.

+1

Osobiście uważam, że cała koncepcja generowania wartości domyślnych lub specyficznych dla dostawcy jest głupią funkcją Java crypto API, więc zawsze używam 'IvParameterSpec' i samemu wpisuję ją w przypadkowe wartości podczas szyfrowania. Znacznie łatwiej jest debugować, a połączenia szyfrowane i odszyfrowywane są również symetryczne. –

+0

Uzgodnione. Nie twierdzę, że domyślnie zawsze musi być katastrofa, ale nigdy nie widziałem implementacji, która nie spowodowała więcej problemów niż rozwiązali. Nie używaj wartości domyślnych w Java Crypto API, nie używaj domyślnych zestawów znaków ... po prostu unikaj wartości domyślnych. –

Powiązane problemy