简体   繁体   中英

Java RSA decryption with private key gives BadPaddingException

today, I wrote some code to encrypt a String with AES and encrypt the key with RSA. When I try to decrypt the everything, Java gives me a BadPaddingException. Here is my code:

Test.java:

import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
import java.security.Key;
import java.security.SecureRandom;
import java.util.Scanner;

public class Test {

private static String publicName = null;
private static String privateName = null;

public static void main(String[] args) throws Exception {
    Scanner scanner = new Scanner(System.in);
    System.out.println("Choose an option: \n(1) Decrypt \n(2) Encrypt \n(3) Generate Keypair");
    int choice = scanner.nextInt();
    if(choice == 1) decrypt();
    else if(choice == 2) encrypt();
    else if(choice == 3) makeKeypair();
}

private static void makeKeypair() throws Exception {
    Scanner scanner = new Scanner(System.in);
    System.out.println("Enter the name of your public key: ");
    publicName = scanner.nextLine() + ".key";
    System.out.println("Enter the name of your private key: ");
    privateName = scanner.nextLine() + ".key";
    KeyMaker keyMaker = new KeyMaker(publicName, privateName);
    keyMaker.generateKeys();
}

public static void encrypt() throws Exception {
    Scanner scanner = new Scanner(System.in);
    System.out.println("Enter the text you want to encrypt: ");
    String toEncrypt = scanner.nextLine();
    System.out.println("Enter the name of the public key you want to use: ");
    publicName = scanner.nextLine() + ".key";
    Encrypter encrypter = new Encrypter(publicName);

    Key key = generateKey();
    String encryptedWithAES = encryptAES(toEncrypt, key);

    String encodedKey = java.util.Base64.getEncoder().encodeToString(key.getEncoded());
    String encryptedKey = encrypter.rsaEncrypt(encodedKey);
    String finalOutput = encryptedKey + encryptedWithAES;

    System.out.println("Enter the name of the file encrypted file which will be created: ");
    String fileName = scanner.nextLine();
    PrintWriter out = new PrintWriter(fileName + ".txt");
    out.println(finalOutput);
    out.close();

    System.out.println("DONE - saved as: " + fileName + ".txt");
    scanner.close();
}

public static void decrypt() throws Exception {
    Scanner scanner = new Scanner(System.in);
    System.out.println("Enter the name of your encrypted file: ");
    String fileName = scanner.nextLine() + ".txt";

    String givenInput = null;
    try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
        String line;
        while ((line = br.readLine()) != null) {
            givenInput = givenInput + line;
        }
    }
    assert givenInput != null;
    String encryptedKey = givenInput.substring(0,172);
    String encryptedWithAES = givenInput.replace(encryptedKey, "");

    System.out.println("Enter the name of your private key: ");
    privateName = scanner.nextLine() + ".key";
    Decrypter decrypter = new Decrypter(privateName);
    String decryptedKey = decrypter.rsaDecrypt(encryptedKey);

    byte[] decodedKey = java.util.Base64.getDecoder().decode(decryptedKey);
    Key originalKey = new SecretKeySpec(decodedKey, "AES");

    String decryptedWithAES = decryptAES(encryptedWithAES, originalKey);
    System.out.println(decryptedWithAES);
    scanner.close();
}

public static Key generateKey() throws Exception {
    KeyGenerator kg = KeyGenerator.getInstance("AES");
    SecureRandom random = new SecureRandom();
    kg.init(random);
    return kg.generateKey();
}

private static String encryptAES(String message, Key key) throws Exception {
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE,key);

    byte[] stringBytes = message.getBytes();
    byte[] raw = cipher.doFinal(stringBytes);
    return Base64.encodeBase64String(raw);
}

public static String decryptAES(String encrypted, Key key) throws Exception       {
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, key);

    byte[] raw = Base64.decodeBase64(encrypted);
    byte[] stringBytes = cipher.doFinal(raw);
    return new String(stringBytes, "UTF8");
}
}

KeyMaker.java:

import java.io.FileOutputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class KeyMaker {
String publicName;
String privateName;

public KeyMaker(String publicName, String privateName) {
    this.publicName = publicName;
    this.privateName = privateName;
}

public void generateKeys() throws Exception{
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(1024);
    KeyPair kp = kpg.genKeyPair();

    PrivateKey privateKey = kp.getPrivate();
    PublicKey publicKey = kp.getPublic();

    X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
            publicKey.getEncoded());
    FileOutputStream fos = new FileOutputStream(publicName);
    fos.write(x509EncodedKeySpec.getEncoded());
    fos.close();

    PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
            privateKey.getEncoded());
    fos = new FileOutputStream(privateName);
    fos.write(pkcs8EncodedKeySpec.getEncoded());
    fos.close();
}
}

Encrypter.java:

import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.io.*;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

public class Encrypter {
String keyFileName;

public Encrypter(String keyFileName) {
    this.keyFileName = keyFileName;
}

public String rsaEncrypt(String data) throws Exception {
    PublicKey pubKey = readPublicKeyFromFile(keyFileName);
            byte[] utf8 = data.getBytes("UTF-8");
    Cipher cipher = Cipher.getInstance("RSA");

    cipher.init(Cipher.ENCRYPT_MODE, pubKey);
    byte[] enc = cipher.doFinal(Base64.encodeBase64(utf8));
    return Base64.encodeBase64String(enc);
}

private PublicKey readPublicKeyFromFile(String keyFileName) throws Exception {
    File filePublicKey = new File(keyFileName);
    FileInputStream fis = new FileInputStream(keyFileName);
    byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
    fis.read(encodedPublicKey);
    fis.close();

    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
            encodedPublicKey);
    PublicKey pubKey = keyFactory.generatePublic(publicKeySpec);
    return pubKey;
}
}

Decrypter.java:

import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.io.*;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;

public class Decrypter {
String keyFileName;

public Decrypter(String keyFileName) {
    this.keyFileName = keyFileName;
}

public String rsaDecrypt(String str) throws Exception {
    PrivateKey privateKey = readPrivateKeyFromFile(keyFileName);
    Cipher cipher = Cipher.getInstance("RSA");

    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    byte[] dec = Base64.decodeBase64(str);
    byte[] utf8 = cipher.doFinal(Base64.decodeBase64(dec));
    return Base64.encodeBase64String(utf8);

}

private PrivateKey readPrivateKeyFromFile(String keyFileName) throws Exception {
    File filePrivateKey = new File(keyFileName);
    FileInputStream fis = new FileInputStream(keyFileName);
    byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
    fis.read(encodedPrivateKey);
    fis.close();

    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
            encodedPrivateKey);
    PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
    return privateKey;
}
}

In your Decrypter, you decode the Base64-encoded String into bytes, but then you decode that again. In your Encrypter, you take the bytes encrypted, and encode that into Base64 once. This is likely where your problem lies.

Strangely enough, you seem to perform more Base64 operations than necessary. For example, in Encrypter, you get the bytes of the string to encrypt. Why do you Base64-encode those bytes again?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM