web-dev-qa-db-de.com

BadPaddingException: Entschlüsselungsfehler

Ich schreibe ein Programm, das als Eingabe von der Konsole genommen wird - der Name einer Zip-Datei, der Name einer Zip-Datei, die die (de/en) verschlüsselten Dateien enthält, die aus der ersten Zip-Datei generiert wurden, und eine Datei, die den öffentlichen Schlüssel enthält . Ich bekomme die Ausnahme beim Entschlüsseln:

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)

Kann ich nicht herausfinden, warum ich diese Ausnahme bekomme?

Öffentlicher Schlüssel:

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

Privat Schlüssel:

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

Der Code für das Programm ist unten angegeben. Jede Hilfe ist gut :)

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: Aktualisierte decrypt-Methode. Gibt immer noch den gleichen fehler.

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

Jozef hat recht.

Wenn Sie eine Verschlüsselung mit Standardparametern erstellen, wird standardmäßig "RSA/ECB/PKCS1Padding" verwendet. Sie sollten das Auffüllen explizit angeben, wenn Sie keine bösen Überraschungen mögen. Möglicherweise haben andere Sicherheitsanbieter andere Standardparameter. Sie wissen nie im Voraus, welche Sicherheitseinstellungen die einzelnen JREs haben.

Das PKCS1-Padding fügt also 11 Byte zu Ihren ursprünglichen Daten hinzu und erhöht sie von 117 Byte auf 128 Byte. Sie sollten berücksichtigen, dass diese Zahlen spezifisch für 1024-Bit-RSA-Schlüssel sind (die geringfügig sicher sind) und sich bei längeren Schlüsseln unterscheiden. Da Sie den Schlüssel aus einer Datei laden, sollten Sie die Länge überprüfen.

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

Dies druckt

117 becomes 128

Erwägen Sie schließlich die Verwendung von AES anstelle von RSA für die Dateiverschlüsselung.

Um das Problem zu beheben, müssen Sie einen Puffer mit der Länge des öffentlichen Schlüssels - 11 (117) für die Verschlüsselung und die Größe des öffentlichen Schlüssels (128) für die Entschlüsselung verwenden.

Veränderung

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

zu

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

weil das Lesen des Puffers 117 Bytes und die Größe des doFinal-Ergebnisses 128 Bytes beträgt.

Sie müssen auch Eingabeströme puffern. Wenn Sie aus einer Datei lesen, kann es manchmal langsam sein, und InputStream liest dann weniger Daten, als der Puffer enthalten kann. Durch die Verwendung von BufferedInputStream wird sichergestellt, dass genügend Daten vorhanden sind, bevor der Leseaufruf zurückgegeben wird. Für die Entschlüsselung ist es jedoch wichtig, den gesamten Datenblock zu haben

InputStream inputEntry = new BufferedInputStream(originalZipFile.getInputStream(entry));
8
divanov
while((read = inputEntry.read(buffer)) != -1){              
        outputFile.write(cipher.doFinal(buffer), 0, read);
    }

Sie haben hier ein Problem. read ist die Größe des gelesenen Klartextes, nicht der Chiffretext. Sie sollten den 2. und 3. Parameter vollständig entfernen.

Es ist auch eine Verschwendung von Zeit und Raum, um den verschlüsselten Text in eine Zwischendatei zu schreiben. Schreiben Sie es einfach direkt in den Zip-Stream.

1
user207421

Das Byte-Array der Entschlüsselungsmethode sollte 256 Byte lang sein, da es sich um die Standardausgabegröße des Algorithmus handelt (Die zusätzlichen Byte ergeben diese Länge). Ändern Sie byte[] buffer = new byte[128]; in byte[] buffer = new byte[256];.

0