RSA加密 – 解密:BadPaddingException:数据必须从零开始

我很遗憾地问你关于这么多问题的技巧。 我有一个关于RSA crypthography的问题。 我已经检查了有关此问题的其他主题,但我没有找到任何有用的答案。 我希望你能帮助我。

我想读取一个文件,将其包含,然后解密并将这些解密的字节放在一个新文件中。

我实际上可以: – 获取文件的字节 – 加密它

我有一个例外:javax.crypto.BadPaddingException:数据必须从零开始。

这是我的代码:

package com.bodom.ghosty; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.io.*; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.*; import java.security.spec.InvalidKeySpecException; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; import java.util.Scanner; public class EncryptionUtil { private final PrivateKey privateKey; private final PublicKey publicKey; /** * Build an EncryptionUtil object * * @param keyPair The KeyPair used for Ghosty */ public EncryptionUtil (KeyPair keyPair) { this.privateKey = keyPair.getPrivate(); this.publicKey = keyPair.getPublic(); } /** * Generate a pair of RSA keys * * @return A keypair of RSA keys * @throws NoSuchAlgorithmException */ private static KeyPair keyGenerate() throws NoSuchAlgorithmException { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); keyGen.initialize(2048); return keyGen.genKeyPair(); } /** * Crypt data * * @param data Data to encrypt * @return The crypted data * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws IllegalBlockSizeException * @throws BadPaddingException */ private static byte[] rsaEncryption(byte[] data, EncryptionUtil encryptionUtil) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, encryptionUtil.publicKey); return cipher.doFinal(data); } /** * Read the bytes of a file * * @param file is the file to read * @return the bytes of the file * @throws IOException */ private static byte[] readBytesInFile (Path file) throws IOException { byte[] result = new byte[(int)Files.size(file)]; try { try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file.getFileName().toString()))) { int bytesRead = 0; while (bytesRead  0) { bytesRead += bytesGet; } } } } catch (IOException e) { System.out.println(e); } return result; } /** * Encrypt a file * * @param file Path of the file to crypt * @return A byte array which contains the crypted lines of the file * @throws java.io.IOException * @throws javax.crypto.IllegalBlockSizeException * @throws java.security.InvalidKeyException * @throws javax.crypto.BadPaddingException * @throws java.security.NoSuchAlgorithmException * @throws javax.crypto.NoSuchPaddingException */ public static byte[] encryption (Path file, EncryptionUtil encryptionUtil) throws IOException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException { byte[] datatocrypt = readBytesInFile(file); int offset = 0; byte[] cryptedfile = null; while (offset < datatocrypt.length) { byte[] outputBytes; byte[] tmp; if(datatocrypt.length - offset < 200 ) { outputBytes = new byte[datatocrypt.length - offset]; System.arraycopy(datatocrypt, offset, outputBytes, 0, datatocrypt.length - offset); byte[] crypt = rsaEncryption(outputBytes, encryptionUtil); tmp = cryptedfile; if (tmp != null) { cryptedfile = new byte[tmp.length + crypt.length]; } else cryptedfile = new byte[crypt.length]; if (tmp != null) { System.arraycopy(tmp, 0, cryptedfile, 0, tmp.length); System.arraycopy(crypt, 0, cryptedfile, tmp.length, crypt.length); } else { System.arraycopy(crypt, 0, cryptedfile, 0, crypt.length); } break; } outputBytes = new byte[200]; System.arraycopy(datatocrypt, offset, outputBytes, 0, 200); byte[] crypt = rsaEncryption(outputBytes, encryptionUtil); tmp = cryptedfile; if (tmp != null) { cryptedfile = new byte[tmp.length + crypt.length]; } else cryptedfile = new byte[crypt.length]; if (tmp != null) { System.arraycopy(tmp, 0, cryptedfile, 0, tmp.length); System.arraycopy(crypt, 0, cryptedfile, tmp.length, crypt.length); } else { System.arraycopy(crypt, 0, cryptedfile, 0, crypt.length); } offset += 200 ; } return cryptedfile; } /** * Decrypt data * * @param crypteddata Crypted data to decrypt * @return The decrypted data * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws IllegalBlockSizeException * @throws BadPaddingException */ private static byte[] rsaDecryption(byte[] crypteddata, EncryptionUtil encryptionUtil) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, encryptionUtil.privateKey); return cipher.doFinal(crypteddata); } /** * Decrypt a file * * @param file Path of the file to decrypt * @return A byte array which contains the decrypted lines of the file * @throws IOException * @throws IllegalBlockSizeException * @throws InvalidKeyException * @throws BadPaddingException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException */ public static byte[] decryption(Path file, EncryptionUtil encryptionUtil) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException { byte[] crypteddata = readBytesInFile(file); int offset = 0; byte[] decryptedfile = null; while (offset < crypteddata.length) { byte[] outputBytes; byte[] tmp; if(crypteddata.length - offset < 200 ) { outputBytes = new byte[crypteddata.length - offset]; System.arraycopy(crypteddata, offset, outputBytes, 0, crypteddata.length - offset); byte[] decrypt = rsaDecryption(outputBytes, encryptionUtil); tmp = decryptedfile; if (tmp != null) { decryptedfile = new byte[tmp.length + decrypt.length]; } else decryptedfile = new byte[decrypt.length]; if (tmp != null) { System.arraycopy(tmp, 0, decryptedfile, 0, tmp.length); System.arraycopy(decrypt, 0, decryptedfile, tmp.length, decrypt.length); } else { System.arraycopy(decrypt, 0, decryptedfile, 0, decrypt.length); } break; } outputBytes = new byte[200]; System.arraycopy(crypteddata, offset, outputBytes, 0, 200); byte[] decrypt = rsaDecryption(outputBytes, encryptionUtil); tmp = decryptedfile; if (tmp != null) { decryptedfile = new byte[decrypt.length + tmp.length]; } else decryptedfile = new byte[decrypt.length]; if (tmp != null) { System.arraycopy(tmp, 0, decryptedfile, 0, tmp.length); System.arraycopy(decrypt, 0, decryptedfile, tmp.length, decrypt.length); } else { System.arraycopy(decrypt, 0, decryptedfile, 0, decrypt.length); } offset +=200 ; } return decryptedfile; } /** * Save a key in a file * * @param modulus Modulus of the key to save * @param exponent Exponent of the key to save * @param filename File used to save the keys * @throws IOException * @throws NoSuchAlgorithmException */ private static void saveKeyToFile (BigInteger modulus, BigInteger exponent, String filename) throws IOException, NoSuchAlgorithmException { Path path = Paths.get(filename); if(!Files.exists(path)) { Files.createFile(path); } try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filename))) { objectOutputStream.writeObject(modulus); objectOutputStream.writeObject(exponent); } } /** * Save a KeyPair in two files * * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws FileNotFoundException * @throws IOException */ public static void saveKeyPair(EncryptionUtil encryptionUtil, String directorypath) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPublicKeySpec rsaPublicKeySpec = keyFactory.getKeySpec(encryptionUtil.publicKey, RSAPublicKeySpec.class); saveKeyToFile(rsaPublicKeySpec.getModulus(), rsaPublicKeySpec.getPublicExponent(), directorypath + "/public.key"); RSAPrivateKeySpec rsaPrivateKeySpec = keyFactory.getKeySpec(encryptionUtil.privateKey, RSAPrivateKeySpec.class); saveKeyToFile(rsaPrivateKeySpec.getModulus(), rsaPrivateKeySpec.getPrivateExponent(), directorypath + "/private.key"); } /** * Get a PublicKey from a file * * @param filename File where the PublicKey is saved * @return The PublicKey get in the file * @throws IOException * @throws ClassNotFoundException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ private static PublicKey getPublicKeyFromFile (String filename) throws IOException, ClassNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException { try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename))) { BigInteger modulus = (BigInteger) objectInputStream.readObject(); BigInteger exponent = (BigInteger) objectInputStream.readObject(); RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulus, exponent); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePublic(rsaPublicKeySpec); } } /** * Get a PrivateKey from a file * * @param filename File where the PrivateKey is saved * @return The PrivateKey get in the file * @throws IOException * @throws ClassNotFoundException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ private static PrivateKey getPrivateKeyFromFile (String filename) throws IOException, ClassNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException { try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename))) { BigInteger modulus = (BigInteger) objectInputStream.readObject(); BigInteger exponent = (BigInteger) objectInputStream.readObject(); RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus, exponent); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePrivate(rsaPrivateKeySpec); } } /** * Get the RSA keypair from the files * * @return The Keypair which contains the public and the private key * @throws IOException * @throws ClassNotFoundException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ public static KeyPair getKeysFromFiles (String directorypath) throws IOException, ClassNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException{ PublicKey publicKey = getPublicKeyFromFile(directorypath + "/public.key"); PrivateKey privateKey = getPrivateKeyFromFile(directorypath + "/private.key"); return new KeyPair(publicKey, privateKey); } public static void main(String[] args) { EncryptionUtil encryptionUtil = null; Scanner scanner = new Scanner(System.in); System.out.println("Path of the keys :"); String path = scanner.nextLine(); try { encryptionUtil = new EncryptionUtil(EncryptionUtil.keyGenerate()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } Path directorypath = Paths.get(path); try { Files.createDirectories(directorypath); } catch (IOException e) { e.printStackTrace(); } try { saveKeyPair(encryptionUtil, path); } catch (NoSuchAlgorithmException | InvalidKeySpecException| IOException e) { System.out.println("Error during the storage of the keys : " + e); } // Crypt part byte[] uncrypt; try { if (encryptionUtil != null) { if (encryptionUtil.publicKey != null && encryptionUtil.privateKey != null) { //Cryptage byte[] crypt = encryption(Paths.get("filetocrypt"), encryptionUtil); FileOutputStream fileOutputStream = new FileOutputStream("cryptedfile"); FileChannel channel = fileOutputStream.getChannel(); ByteBuffer byteBuffer = ByteBuffer.allocate(crypt.length * 2); byteBuffer.put(crypt); byteBuffer.flip(); channel.write(byteBuffer); channel.close(); //Decryptage uncrypt = decryption(Paths.get("cryptedfile"), encryptionUtil); String v = new String(uncrypt); System.out.println("END " + v); } } } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | IOException e) { e.printStackTrace(); } } } 

我读到这个问题经常出现在使用错误的私钥解密或Cypher被滥用时。 但我认为这不是这种情况,或者我没有看到它……我不清楚我的代码有什么问题。 要运行此代码,您需要一个名为“filetocrypt”的文件。 我使用bytes []并将它们拆分为crypt并解密文件,以避开RSA的字节大小问题。 这种拆分工作正常(我尝试使用字符串的文件而不使用RSA算法)

谢谢你的帮助!

您的解密代码需要与您的加密代码不同。 存在许多问题,但导致错误的问题如下。 由于RSA填充,输入块为200字节,输出块为256字节。 因此,在解密时,您需要一次读取256个字节,并期望得到200个字节。 相反,您一次只能读取200个字节。

 import java.security.*; import java.security.interfaces.*; import javax.crypto.Cipher; public class RsaToy { public static void main(String[] args) throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(1024); KeyPair kp = kpg.generateKeyPair(); RSAPublicKey pub = (RSAPublicKey) kp.getPublic(); RSAPrivateKey priv = (RSAPrivateKey) kp.getPrivate(); Cipher c = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); c.init(Cipher.ENCRYPT_MODE, pub); byte [] plain = new byte[100]; // initialize to all zero bytes // First encrypt: length of input (plain) is 100 byte [] cipher = c.doFinal(plain); System.out.println("length of cipher is " + cipher.length); // Now decrypt: length of input(cipher) is 128; c.init(Cipher.DECRYPT_MODE, priv); byte [] decrypted_cipher = c.doFinal(cipher); System.out.println("length of decrypted cipher is " + decrypted_cipher.length); } } 

那么,在你的解密方法中,改变3中出现的200? 到256的位置。你真的不应该硬编码这些常量。