2015-08-11 14 views
6

Sto scrivendo un programma che prende come input dalla console - il nome di un file zip, il nome di un file zip da creare contenente i file criptati (de/en) generati dal primo zip e un file contenente la chiave pubblica. Ottengo l'eccezione durante la decifrazione:BadPaddingException: Errore di decrittografia

exception Exception in thread "main" javax.crypto.BadPaddingException:  Decryption error 
at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:380) 
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:291) 
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:363) 
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389) 
at javax.crypto.Cipher.doFinal(Cipher.java:2165) 
at com.Main.decrypt(Main.java:67) 
at com.Main.main(Main.java:201) 

Non riesco a capire perché ottengo questa eccezione?

chiave pubblica:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCE3pA746UfpC8sFk8ZJp0yupyJqj5jy6cjdxUYoP7mCm7c0mqQDeCcDNBYW2eSozCioPrH/9L+CDQEPLYakoem+jFnUKDH5+pru/0PJTJJF8Xh/ZT9eJlvsYBr1/qSfICf6RTs7kzwq9IuSZBw7/tfNEF9i0A8FVox6HOopXod1QIDAQAB 

chiave privata:

MIICXQIBAAKBgQCE3pA746UfpC8sFk8ZJp0yupyJqj5jy6cjdxUYoP7mCm7c0mqQDeCcDNBYW2eSozCioPrH/9L+CDQEPLYakoem+jFnUKDH5+pru/0PJTJJF8Xh/ZT9eJlvsYBr1/qSfICf6RTs7kzwq9IuSZBw7/tfNEF9i0A8FVox6HOopXod1QIDAQABAoGANOFrYBqK5lvu1koOswDWQZFZqcSSzh8IZyoGwGWa7S0r0EECXlDXmuPSq8e9IfRG8ALHrH+ZlrbnFOSgyVSWHfpj3aH+qknoSX5TW2rMQHih8865xuqheMQ+RTZ7+BRDqNsYkzxB/Z8mqzpoJQSYf+H7nWxdDCgAJVYZzxl3DmUCQQD32iEjnwiwUjii8slcmvCEZl+z84DWNdvJOg6Z38sI4AvrfpKc1WAcDg1rNZCKrRgokh54wpLt08cpFcrD04c3AkEAiTzDmc0bdgfg5wj6xHFZpYlBwiGm/bjOR2PS57P0GNU5PsDllRbFqIuzArITutO5lvZZImzuYz7Lf+cQ73pxUwJBAOdEwmdaneDo17A0m2+to3/nhqWDMVSwLMU3RyiNigZeCMFU+bkd4PBMrHi9IoJDwacZsRU9eZwxYEUV8H2Jg0ECQEEkOqRSm2pXKwX/WSjNtQPCNxhy6NUeV6vDUmTxIjh3XYjP/ynZeVEbnoj1BjB0N2/U11Jj6nPpZqb7gyppMEkCQQCoGdVYDipU+hMMnvxa0zOIyQc/a+HE0lESqn+2ZPafYi9Z1RldRMvUXhP8U7s+OuhRwprdw2ivvOFrnWyz9lL2 

Il codice per il programma è sotto. Ogni aiuto è wellcomed :)

package com; 

import java.io.BufferedReader; 
import java.io.FileOutputStream; 
import java.io.FileReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.security.GeneralSecurityException; 
import java.security.KeyFactory; 
import java.security.PrivateKey; 
import java.security.PublicKey; 
import java.security.spec.PKCS8EncodedKeySpec; 
import java.security.spec.X509EncodedKeySpec; 
import java.util.Base64; 
import java.util.Enumeration; 
import java.util.Scanner; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipFile; 
import java.util.zip.ZipOutputStream; 

import javax.crypto.Cipher; 
import org.bouncycastle.asn1.ASN1EncodableVector; 
import org.bouncycastle.asn1.ASN1Integer; 
import org.bouncycastle.asn1.ASN1ObjectIdentifier; 
import org.bouncycastle.asn1.ASN1Sequence; 
import org.bouncycastle.asn1.DERNull; 
import org.bouncycastle.asn1.DEROctetString; 
import org.bouncycastle.asn1.DERSequence; 
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 

public class Main { 

    public final static int BUFFER_SIZE = 117; 

    public static void decrypt(String originalZipFileName, String newZipFileName, String privateKeyFileName) throws Exception { 
     byte[] buffer = new byte[128]; 

     ZipFile originalZipFile = new ZipFile(originalZipFileName); 
     ZipOutputStream newZipFile = new ZipOutputStream(new FileOutputStream(newZipFileName)); 

     Enumeration<? extends ZipEntry> zipEntries = originalZipFile.entries(); 

     String privateKey = getKeyString(privateKeyFileName); 
     PrivateKey key = makePrivateKey(privateKey); 

     Cipher cipher = Cipher.getInstance("RSA"); 

     cipher.init(Cipher.DECRYPT_MODE, key); 


     while(zipEntries.hasMoreElements()){ 

      ZipEntry entry = zipEntries.nextElement();   

      ZipEntry copy = new ZipEntry(entry.getName());  
      newZipFile.putNextEntry(copy);   

      InputStream inputEntry = originalZipFile.getInputStream(entry);   

      while(inputEntry.read(buffer) != -1){ 
       newZipFile.write(cipher.doFinal(buffer)); 
      } 

      newZipFile.closeEntry(); 
      inputEntry.close(); 
     } 
     newZipFile.close(); 
     originalZipFile.close(); 
    } 

    public static void encrypt(String originalZipFileName, String newZipFileName, String publicKeyFileName) throws Exception{ 

     byte[] buffer = new byte[BUFFER_SIZE]; 

     ZipFile originalZipFile = new ZipFile(originalZipFileName); 
     ZipOutputStream newZipFile = new ZipOutputStream(new FileOutputStream(newZipFileName)); 

     Enumeration<? extends ZipEntry> zipEntries = originalZipFile.entries(); 

     String publicKey = getKeyString(publicKeyFileName); 
     PublicKey key = makePublicKey(publicKey); 

     Cipher cipher = Cipher.getInstance("RSA"); 

     cipher.init(Cipher.ENCRYPT_MODE, key); 


     while(zipEntries.hasMoreElements()){ 

      ZipEntry entry = zipEntries.nextElement();   

      ZipEntry copy = new ZipEntry(entry.getName());  
      newZipFile.putNextEntry(copy);   

      InputStream inputEntry = originalZipFile.getInputStream(entry);   

      while(inputEntry.read(buffer) != -1){    
       newZipFile.write(cipher.doFinal(buffer)); 
      } 

      newZipFile.closeEntry(); 
      inputEntry.close(); 
     } 
     newZipFile.close(); 
     originalZipFile.close(); 
    } 

    public static String getKeyString(String fileName){ 

     String key = new String(); 
     try { 
      BufferedReader buf = new BufferedReader(new FileReader(fileName)); 
      key = buf.readLine();  
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     return key.trim(); 
    } 

    public static PublicKey makePublicKey(String stored) throws GeneralSecurityException { 
     byte[] data = Base64.getDecoder().decode(stored); 
     X509EncodedKeySpec spec = new X509EncodedKeySpec(data); 
     KeyFactory fact = KeyFactory.getInstance("RSA"); 
     return fact.generatePublic(spec); 
    } 

    public static PrivateKey makePrivateKey(String stored) throws GeneralSecurityException, Exception { 
     /*byte[] data = Base64.getDecoder().decode(stored); 
     PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(data); 
     KeyFactory fact = KeyFactory.getInstance("RSA"); 
     return fact.generatePrivate(spec);*/ 

     byte[] data = Base64.getDecoder().decode(stored); 

     ASN1EncodableVector v = new ASN1EncodableVector(); 
     v.add(new ASN1Integer(0)); 
     ASN1EncodableVector v2 = new ASN1EncodableVector(); 
     v2.add(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId())); 
     v2.add(DERNull.INSTANCE); 
     v.add(new DERSequence(v2)); 
     v.add(new DEROctetString(data)); 
     ASN1Sequence seq = new DERSequence(v); 
     byte[] privKey = seq.getEncoded("DER"); 

     PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privKey); 
     KeyFactory fact = KeyFactory.getInstance("RSA"); 
     PrivateKey key = fact.generatePrivate(spec); 

     return key; 

    } 

    public static void main(String[] args) throws Exception { 

     Scanner scan = new Scanner(System.in); 

     System.out.println("Enter type of operation:"); 
     String line = scan.nextLine(); 

     if(line.equals("encrypt")){ 
      System.out.println("Enter name of original ZIP file:"); 
      String originalZipFileName = scan.nextLine(); 

      System.out.println("Enter name of new ZIP file:"); 
      String newZipFileName = scan.nextLine(); 

      System.out.println("Enter name of file containg public key:"); 
      String publicKeyFileName = scan.nextLine(); 

      encrypt(originalZipFileName, newZipFileName, publicKeyFileName);   
     } 

     if(line.equals("decrypt")){ 
      System.out.println("Enter name of original ZIP file:"); 
      String originalZipFileName = scan.nextLine(); 

      System.out.println("Enter name of new ZIP file:"); 
      String newZipFileName = scan.nextLine(); 

      System.out.println("Enter name of file containg private key:"); 
      String privateKeyFileName = scan.nextLine(); 

      decrypt(originalZipFileName, newZipFileName, privateKeyFileName);  
     }  

    } 

} 

PS: Aggiornato decrypt metodo. Ancora dà lo stesso errore.

public static void decrypt(String originalZipFileName, String newZipFileName, String privateKeyFileName) throws Exception { 
    byte[] buffer = new byte[128]; 

    ZipFile originalZipFile = new ZipFile(originalZipFileName); 
    ZipOutputStream newZipFile = new ZipOutputStream(new FileOutputStream(newZipFileName)); 

    Enumeration<? extends ZipEntry> zipEntries = originalZipFile.entries(); 

    String privateKey = getKeyString(privateKeyFileName); 
    PrivateKey key = makePrivateKey(privateKey); 

    Cipher cipher = Cipher.getInstance("RSA"); 

    cipher.init(Cipher.DECRYPT_MODE, key); 


    while(zipEntries.hasMoreElements()){ 

     ZipEntry entry = zipEntries.nextElement();   

     ZipEntry copy = new ZipEntry(entry.getName());  
     newZipFile.putNextEntry(copy); 


     InputStream inputEntry = originalZipFile.getInputStream(entry); 


     while(inputEntry.read(buffer) != -1){ 
      newZipFile.write(cipher.doFinal(buffer)); 
     } 

     newZipFile.closeEntry(); 
     inputEntry.close(); 
    } 
    newZipFile.close(); 
    originalZipFile.close(); 
} 
+0

PS: domanda precedente qui: http://stackoverflow.com/questions/31941413/invalidkeyspecexception-algid-parse-error-not-a-sequence – user3719857

+1

Eventuale duplicato di http://stackoverflow.com/questions/14085333/ rsa-encryption-decryption-badpaddingexception-data-must-start-with-zero –

+0

@JozefChocholacek Ho cambiato la dimensione del buffer per il metodo decrypt in 128, ma non è stato d'aiuto. Una risposta più dettagliata sarebbe carina :) – user3719857

risposta

4

Jozef ha ragione.

Quando si crea la cifra con i parametri predefiniti, per impostazione predefinita "RSA/ECB/PKCS1Padding". Dovresti specificare esplicitamente il padding, se non ti piacciono le brutte sorprese. Perché altri fornitori di sicurezza potrebbero avere parametri predefiniti diversi. E non sai mai in anticipo quali impostazioni di sicurezza hanno ogni specifico JRE.

Quindi il padding PKCS1 aggiunge 11 byte ai dati originali aumentandolo da 117 byte a 128 byte. È necessario tenere conto del fatto che questi numeri sono specifici per le chiavi RSA a 1024 bit (che sono marginalmente sicure) e saranno diverse per le chiavi più lunghe. Dal momento che stai caricando la chiave da un file, controlla la sua lunghezza.

@Test 
public void testPadding() throws Exception { 
    SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); 

    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 
    keyGen.initialize(1024, random); 
    KeyPair keyPair = keyGen.generateKeyPair(); 

    /* constant 117 is a public key size - 11 */ 
    byte[] plaintext = new byte[117]; 
    random.nextBytes(plaintext); 

    Cipher cipher = Cipher.getInstance("RSA"); 
    cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); 
    byte[] ciphertext = cipher.doFinal(plaintext); 
    System.out.println(plaintext.length + " becomes " + ciphertext.length); 
} 

Questo stampa

117 becomes 128 

E, infine, è possibile utilizzare AES al posto di RSA per la crittografia dei file.

Quindi per risolvere il problema è necessario utilizzare il buffer della lunghezza della chiave pubblica delle dimensioni - 11 (117) per la crittografia e la dimensione della chiave pubblica (128) per la decrittografia.

Change

outputFile.write(cipher.doFinal(buffer), 0, read); 

a

outputFile.write(cipher.doFinal(buffer)); 

perché buffer di lettura è di 117 byte e la dimensione del risultato doFinal è di 128 byte.

Inoltre è necessario bufferizzare i flussi di input. Quando si legge dal file, a volte può essere lento e quindi InputStream leggerà meno dati di quanto possa contenere il buffer. Usando BufferedInputStream si assicura che ci siano abbastanza dati prima che i ritorni di chiamata di lettura. Tuttavia, per la decrittazione è fondamentale per avere la piena blocco dei dati

InputStream inputEntry = new BufferedInputStream(originalZipFile.getInputStream(entry)); 
+1

Il problema può essere ricondotto alla riga 'outputFile.write (cipher.doFinal (buffer), 0, read);' durante la crittografia, perché il risultato della chiamata 'doFinal()' è maggiore (padding) di 'read "che significa che manca una parte del testo cifrato, il che significa che non può essere decodificato. –

+0

@ArtjomB. Come esattamente dovrei risolvere questo problema? – user3719857

+1

@divanov Contiene la lunghezza * plaintext *. – EJP

1
while((read = inputEntry.read(buffer)) != -1){    
     outputFile.write(cipher.doFinal(buffer), 0, read); 
    } 

Hai un problema qui. read è la dimensione del testo in chiaro che è stato letto, non il testo cifrato. Dovresti rimuovere del tutto il 2 ° e il 3 ° parametro.

È anche uno spreco di tempo e spazio per scrivere il testo cifrato in un file intermedio. Basta scriverlo direttamente nello stream zip.

+0

ho appena aggiornato il metodo con le cose che mi hai detto, ma mi dà comunque lo stesso errore. – user3719857