使用私钥进行Java RSA解密会产生BadPaddingException

时间:2016-01-08 17:38:33

标签: java cryptography

今天,我写了一些代码用AES加密String并用RSA加密密钥。当我尝试解密所有内容时,Java会给我一个BadPaddingException。 这是我的代码:

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

1 个答案:

答案 0 :(得分:1)

在你的Decrypter中,你将Base64编码的String解码为字节,但是你再次解码它。在您的Encrypter中,您将加密的字节,并将其编码到Base64一次。这可能是你的问题所在。

奇怪的是,您似乎执行了超过必要的Base64操作。例如,在Encrypter中,您将获得要加密的字符串的字节数。为什么Base64再次编码这些字节?