web-dev-qa-db-fra.com

BadPaddingException: erreur de déchiffrement

J'écris un programme qui prend en entrée de la console - le nom d'un fichier Zip, le nom d'un fichier Zip à créer contenant les fichiers (de/en) cryptés générés à partir du premier Zip et un fichier contenant la clé publique. . Je reçois une exception lors du décryptage:

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)

Vous ne pouvez pas comprendre pourquoi je reçois cette exception?

Clé publique:

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

Clé privée:

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

Le code du programme est ci-dessous. Toute aide est la bienvenue :)

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: Mise à jour de la méthode decrypt. Donne toujours la même erreur.

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 a raison.

Lorsque vous créez un chiffrement avec des paramètres par défaut, "RSA/ECB/PKCS1Padding" est utilisé par défaut. Vous devez spécifier explicitement le rembourrage si vous n'aimez pas les mauvaises surprises. Parce que d'autres fournisseurs de sécurité peuvent avoir des paramètres par défaut différents. Et vous ne savez jamais à l'avance quels paramètres de sécurité chaque JRE spécifique a.

Ainsi, le remplissage PKCS1 ajoute 11 octets à vos données d'origine, ce qui passe de 117 octets à 128 octets. Vous devez tenir compte du fait que ces numéros sont spécifiques aux clés RSA 1024 bits (qui sont légèrement sécurisées) et seront différents pour les clés plus longues. Puisque vous chargez la clé à partir d’un fichier, envisagez de vérifier sa longueur.

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

Cette imprime

117 becomes 128

Enfin, envisagez d'utiliser AES au lieu de RSA pour le chiffrement de fichier.

Donc, pour résoudre le problème, vous devez utiliser un tampon de taille longueur de clé publique - 11 (117) pour le chiffrement et taille de clé publique (128) pour le déchiffrement.

Changement

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

à

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

parce que la lecture du tampon est de 117 octets et que la taille du résultat de doFinal est de 128 octets.

Aussi, vous devez mettre en mémoire tampon les flux d’entrée. Lorsque vous lisez un fichier, cela peut parfois être lent, puis InputStream lit moins de données que la mémoire tampon ne peut en contenir. En utilisant BufferedInputStream, on s'assure qu'il y a suffisamment de données avant le retour de l'appel en lecture. Cependant, pour le déchiffrement, il est essentiel de disposer du bloc complet de données.

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

Vous avez un problème ici. read est la taille du texte en clair qui a été lu, pas le texte chiffré. Vous devez supprimer les 2ème et 3ème paramètres.

Écrire le texte crypté dans un fichier intermédiaire est également une perte de temps et d'espace. Il suffit de l'écrire directement dans le flux Zip.

1
user207421

Le tableau d'octets de la méthode de déchiffrement doit avoir une longueur de 256 octets, car il s'agit de la taille de sortie par défaut de l'algorithme (les octets supplémentaires donnent cette longueur). Remplacez byte[] buffer = new byte[128]; par byte[] buffer = new byte[256];.

0
Georgios Anifantis