2014-04-14 5 views
5

Ho un file di chiave privata codificato con DES/ECB/PKCS5Padding (chiave DES a 56 bit generata da una frase segreta) e voglio decrittografarlo. Non so perché, ma ogni volta che provo a decript, il metodo doFinal della mia classe di cifratura sta gettando questo errore:BadPaddingException: Dato blocco finale non adeguatamente riempito

javax.crypto.BadPaddingException: Given final block not properly padded at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.DESCipher.engineDoFinal(DashoA13*..) at javax.crypto.Cipher.doFinal(DashoA13*..) at...

Ecco il mio codice:

public static PrivateKey readPrivateKeyFromFile(File file, String chaveSecreta) { 
    try { 
     SecureRandom r = new SecureRandom(chaveSecreta.getBytes()); 
     KeyGenerator keyGen = KeyGenerator.getInstance("DES"); 
     keyGen.init(56, r); 
     Key key = keyGen.generateKey(); 

     byte[] privateKeyBytes = decryptPKFile(file, key); 

     KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
     EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); 
     PrivateKey privateKey = null; 
     try { 
      privateKey = keyFactory.generatePrivate(privateKeySpec); 
     } catch (InvalidKeySpecException e) { 
      JOptionPane.showMessageDialog(null, "Erro 01, tente mais tarde"); 
     } 
     return privateKey; 
    } catch (NoSuchAlgorithmException e) { 
     JOptionPane.showMessageDialog(null, "Erro 02, tente mais tarde"); 
    } 
    return null; 
} 

public static byte[] decryptPKFile(File file, Key key){ 
    try{ 
     Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); 
     byte[] cipherText = readBytes(file); 
     cipher.init(Cipher.DECRYPT_MODE, key); 
     System.out.println(cipher); 
     System.out.println(cipherText); 
     byte[] text = cipher.doFinal(cipherText); 
     return text; 
    }catch(Exception e){ 
     e.printStackTrace(); 
     return null; 
    } 
} 

public static byte[] readBytes(File file) { 
    try { 
     FileInputStream fs = new FileInputStream(file); 
     byte content[] = new byte[(int) file.length()]; 
     fs.read(content); 
     return content; 
    } catch (FileNotFoundException e) { 
     System.out.println("Arquivo não encontrado!"); 
     e.printStackTrace(); 
    } catch (IOException ioe) { 
     System.out.println("Erro ao ler arquivo!"); 
     ioe.printStackTrace(); 
    } 
    return null; 
} 

Qualsiasi syggestions?

+0

Sto supponendo che l'input letto dal file non sia un testo crittografato valido. Essendo l'algoritmo di blocco DES, dovresti controllare se la lunghezza del file è la moltiplicazione di 64. In caso contrario, significherebbe che quel file è corrotto. – markubik

+2

Vuoi dire più di 8? È, il file non è danneggiato, ho controllato. –

+0

@markubik È una chiave casuale: P –

risposta

8

Si sta tentando di decodificare il testo cifrato con un generatore di numeri casuali creato utilizzando un seme specifico. Tuttavia, non si specifica l'algoritmo e l'algoritmo potrebbe cambiare anche internamente. È noto che Android genera un valore completamente casuale invece per alcune versioni.

È necessario utilizzare un SecretKeyFactory non uno KeyGenerator. E ovviamente avrai bisogno dei dati chiave a 8 byte. L'unico modo per recuperare questo nel tuo caso è trovare l'algoritmo/implementazione SecureRandom prima e ricalcolare la chiave.

Ora qualsiasi testo cifrato decodifica con qualsiasi chiave. DES ECB fornisce solo (una sorta di) riservatezza, non integrità. Il problema è che decodificherà in spazzatura. Ora se provi a rimuovere il padding dalla spazzatura, probabilmente otterrai un errore di riempimento.

Se sei "fortunato" - una volta in circa 256 volte - otterrai un risultato. Ciò si verifica quando il blocco decrittografato termina con 01 o 0202, il riempimento è valido. Ovviamente il risultato sarà immondizia, ma non terminerà con lo BadPaddingException. Nel tuo caso l'istanza SecureRandom è probabilmente per restituire lo stesso valore errato all'infinito, quindi questo potrebbe non succedere mai.

In futuro, utilizzare PBKDF2 e alimentare la password codificata. Si noti chiaramente la codifica dei caratteri utilizzata, Java SE utilizza gli 8 bit più bassi dell'array char. Non utilizzare mai mai String.getBytes() poiché la codifica predefinita potrebbe differire da un sistema all'altro.

+1

Phew, scusa per le numerose modifiche, si sta facendo tardi. –

+2

Immagino sia per via del mio sistema. Tutto funziona quando si utilizza Windows, ma non funzionerà sul mio Mac. Indovina che è la cosa String.getBytes() che hai detto .. –

+1

http://stackoverflow.com/questions/9312816/java-platforms-default-charset-on-different-platforms –