17

I'm writing a program which takes as input from the console - the name of a zip file, name of a zip file to be made containing the (de/en)crypted files generated from the first zip and a file containing the public key. I get the exception when decrypting:

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) 

Can't figure out why I get this exception?

Public key:

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

Private key:

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 

The code for the program is bellow . Any help is wellcomed :)

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: Updated decrypt method. Still gives same error.

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(); } 
8
  • PS: previous question here: stackoverflow.com/questions/31941413/… Commented Aug 11, 2015 at 14:22
  • 1
    Possible duplicate of stackoverflow.com/questions/14085333/… Commented Aug 11, 2015 at 14:26
  • @JozefChocholacek I changed the size of the buffer for the decrypt method to 128, but it didn't help. A more detailed answer would be nice :) Commented Aug 11, 2015 at 14:41
  • @divanov What exactly do you mean by that ? Commented Aug 12, 2015 at 14:04
  • Was decryption error resolved after you used BufferedInputStream around ZipEntry's InputStream? Commented Aug 12, 2015 at 14:11

3 Answers 3

13

Jozef is right.

When you create cipher with default parameters, it defaults to "RSA/ECB/PKCS1Padding". You should specify padding explicitly, if you don't like nasty surprises. Because other security providers might have different default parameters. And you never know in advance which security settings each specific JRE has.

So PKCS1 padding adds 11 bytes to your original data increasing it from 117 bytes to 128 bytes. You should take into account that these numbers are specific to 1024 bit RSA keys (which are marginally secure) and will be different for longer keys. Since you are loading the key from a file consider checking its length.

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

This prints

117 becomes 128 

And finally, consider using AES instead of RSA for file encryption.

So to fix the problem you need to use buffer of size public key length - 11 (117) for encryption and public key size (128) for decryption.

Change

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

to

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

because buffer read is 117 bytes and size of doFinal result is 128 bytes.

Also you need to buffer input streams. When you are reading from file, it can be slow sometimes and then InputStream will read less data than buffer may contain. By using BufferedInputStream one ensures that there is enough data before read call returns. However, for decryption it's crucial to have the full block of data

InputStream inputEntry = new BufferedInputStream(originalZipFile.getInputStream(entry)); 
Sign up to request clarification or add additional context in comments.

5 Comments

The problem can be traced back to the line outputFile.write(cipher.doFinal(buffer), 0, read); during encryption, because the result of the doFinal() call is larger (padding) than read which means that a part of the ciphertext is missing which means that it cannot be decrypted.
@ArtjomB. How exactly should I fix this problem?
@divanov It contains the plaintext length.
Tried what you said , but still gives me the same error .
I solved this problem using : Cipher cipher1 = Cipher.getInstance("RSA/ECB/NOPADDING");
1
while((read = inputEntry.read(buffer)) != -1){ outputFile.write(cipher.doFinal(buffer), 0, read); } 

You have a problem here. read is the size of the plaintext that was read, not the ciphertext. You should remove the 2nd and 3rd parameters altogether.

It is also a waste of time and space to write the ciphertext to an intermediate file. Just write it straight to the zip stream.

1 Comment

just updated the method with the stuff you told me, but it still gives me the same error.
0

The decrypt method's byte array should be 256 bytes in length as it is the default output size of the algorithm (The extra bytes result in this length). Change byte[] buffer = new byte[128]; to byte[] buffer = new byte[256];.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.