2015-08-11 47 views
6

Piszę program, który bierze jako dane wejściowe z konsoli - nazwę pliku zip, nazwę pliku zip, który ma zostać utworzony zawierający (de/en) zaszyfrowane pliki wygenerowane z pierwszego zipa i plik zawierający klucz publiczny. Dostaję wyjątek podczas odszyfrowywania:BadPaddingException: Błąd deszyfrowania

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) 

Nie mogę zrozumieć, dlaczego dostaję ten wyjątek?

klucz publiczny:

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

Klucz prywatny:

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 

Kod programu jest poniżej. Każda pomoc jest 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: Aktualizacja decrypt metody. Nadal daje ten sam błąd.

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: poprzednie pytanie tutaj: http://stackoverflow.com/questions/31941413/invalidkeyspecexception-algid-parse-error-not-a-sequency – user3719857

+1

Możliwe duplikaty http://stackoverflow.com/questions/14085333/ rsa-encryption-deszyfrowanie-badpaddingexception-data-musi-start-z-zero –

+0

@JozefChocholacek Zmieniłem rozmiar bufora dla metody odszyfrowywania na 128, ale to nie pomogło. Bardziej szczegółowa odpowiedź byłaby miła :) – user3719857

Odpowiedz

4

Jozef ma rację.

Podczas tworzenia szyfru z domyślnymi parametrami domyślnie jest to "RSA/ECB/PKCS1Padding". Powinieneś wyraźnie określić dopełnienie, jeśli nie lubisz nieprzyjemnych niespodzianek. Ponieważ inni dostawcy zabezpieczeń mogą mieć różne domyślne parametry. I nigdy nie wiesz z góry, które ustawienia zabezpieczeń mają poszczególne JRE.

Wypełnienie PKCS1 dodaje 11 bajtów do oryginalnych danych, zwiększając je z 117 bajtów do 128 bajtów. Powinieneś wziąć pod uwagę, że te liczby są specyficzne dla 1024-bitowych kluczy RSA (które są marginalnie bezpieczne) i będą się różnić dla dłuższych kluczy. Ponieważ ładujesz klucz z pliku, rozważ rozważenie jego długości.

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

Drukuje

117 becomes 128 

I wreszcie, należy rozważyć użycie AES zamiast RSA do szyfrowania plików.

Aby naprawić problem, należy użyć bufora o rozmiarze klucza publicznego wielkości - 11 (117) do szyfrowania i rozmiaru klucza publicznego (128) do odszyfrowania.

Zmień

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

do

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

bo bufor odczytu wynosi 117 bajtów i wielkość wyniku doFinal wynosi 128 bajtów.

Należy również buforować strumienie wejściowe. Podczas odczytu z pliku czasami może być spowolniony, a następnie InputStream odczyta mniej danych niż może zawierać bufor. Za pomocą BufferedInputStream zapewnia się wystarczającą ilość danych przed powrotem do odczytu. Jednak dla deszyfrowania to zasadnicze znaczenie, aby mieć pełny blok danych

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

Problem można prześledzić do linii 'outputFile.write (cipher.doFinal (buffer), 0, read);' podczas szyfrowania, ponieważ wynik wywołania 'doFinal()' jest większy (wypełnienie) niż 'odczyt "co oznacza, że ​​brakuje części zaszyfrowanego tekstu, co oznacza, że ​​nie można jej odszyfrować. –

+0

@ArtjomB. Jak dokładnie powinienem rozwiązać ten problem? – user3719857

+1

@divanov Zawiera długość * zwykłego tekstu *. – EJP

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

Masz problem tutaj. read to rozmiar tekstu zwykłego, który został odczytany, a nie tekst zaszyfrowany. Powinieneś całkowicie usunąć drugi i trzeci parametr.

Jest to również strata czasu i miejsca na zapisanie zaszyfrowanego tekstu do pliku pośredniego. Po prostu napisz to bezpośrednio do strumienia zip.

+0

właśnie zaktualizował metodę z rzeczami, które mi powiedziałeś, ale nadal daje mi ten sam błąd. – user3719857