Skip to content

Commit

Permalink
Revert changes to ClientFactory to avoid BadPaddingException
Browse files Browse the repository at this point in the history
  • Loading branch information
buchen committed Oct 2, 2017
1 parent 3e66d06 commit 644963e
Showing 1 changed file with 77 additions and 82 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package name.abuchen.portfolio.model;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
Expand Down Expand Up @@ -29,7 +27,6 @@
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
Expand Down Expand Up @@ -151,29 +148,31 @@ private static class PlainWriterZIP implements ClientPersister
public Client load(InputStream input) throws IOException
{
// wrap with zip input stream
try (ZipInputStream zipin = new ZipInputStream(input))
{
ZipEntry entry = zipin.getNextEntry();

if (!ZIP_DATA_FILE.equals(entry.getName()))
throw new IOException(MessageFormat.format(Messages.MsgErrorUnexpectedZipEntry, ZIP_DATA_FILE,
entry.getName()));
ZipInputStream zipin = new ZipInputStream(input);
ZipEntry entry = zipin.getNextEntry();

if (!ZIP_DATA_FILE.equals(entry.getName()))
throw new IOException(MessageFormat.format(Messages.MsgErrorUnexpectedZipEntry, ZIP_DATA_FILE, entry.getName()));

return new XmlSerialization().load(new InputStreamReader(zipin, StandardCharsets.UTF_8));
}
return new XmlSerialization().load(new InputStreamReader(zipin, StandardCharsets.UTF_8));
}

@Override
public void save(Client client, OutputStream output) throws IOException
{
// wrap with zip output stream
try (ZipOutputStream zipout = new ZipOutputStream(output))
try (Writer writer = new OutputStreamWriter(output, StandardCharsets.UTF_8))
{
zipout.setLevel(Deflater.BEST_COMPRESSION);

// wrap with zip output stream
ZipOutputStream zipout = new ZipOutputStream(output);
zipout.putNextEntry(new ZipEntry(ZIP_DATA_FILE));
new XmlSerialization().save(client, zipout);
zipout.closeEntry();

new XmlSerialization().save(client, zipout);
zipout.closeEntry();

zipout.flush();
zipout.finish();
output.flush();
writer.flush();
}
}
}
Expand Down Expand Up @@ -202,25 +201,12 @@ public Decryptor(String method, char[] password)
this.password = password;
this.keyLength = "AES256".equals(method) ? AES256_KEYLENGTH : AES128_KEYLENGTH; //$NON-NLS-1$
}

/**
* Reads all data in the given {@link InputStream}.
*
* @param is
* {@link InputStream}
* @throws IOException
*/
private static void readStreamUntilEnd(InputStream is) throws IOException
{
// use an appropriate buffer (64 KB here)
byte[] data = new byte[65536];
while (is.read(data) != -1)
{}
}

@Override
public Client load(final InputStream input) throws IOException
{
InputStream decrypted = null;

try
{
// check signature
Expand All @@ -244,40 +230,29 @@ public Client load(final InputStream input) throws IOException
byte[] iv = new byte[IV_LENGTH];
input.read(iv);

Client client;
// build cipher and stream
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
try (InputStream decrypted = new CipherInputStream(input, cipher))
{
// read version information
byte[] bytes = new byte[4];
decrypted.read(bytes); // major version number
int majorVersion = ByteBuffer.wrap(bytes).getInt();
decrypted.read(bytes); // version number
int version = ByteBuffer.wrap(bytes).getInt();

// sanity check if the file was properly decrypted
if (majorVersion < 1 || majorVersion > 10 || version < 1 || version > 100)
throw new IOException(Messages.MsgIncorrectPassword);
if (majorVersion > Client.MAJOR_VERSION || version > Client.CURRENT_VERSION)
throw new IOException(MessageFormat.format(Messages.MsgUnsupportedVersionClientFiled, version));

// wrap with zip input stream
try (ZipInputStream zipin = new ZipInputStream(decrypted))
{
zipin.getNextEntry();
decrypted = new CipherInputStream(input, cipher);

client = new XmlSerialization().load(new InputStreamReader(zipin, StandardCharsets.UTF_8));
// read version information
byte[] bytes = new byte[4];
decrypted.read(bytes); // major version number
int majorVersion = ByteBuffer.wrap(bytes).getInt();
decrypted.read(bytes); // version number
int version = ByteBuffer.wrap(bytes).getInt();

// starting with a later jdk 1.8.0 (for example
// 1.8.0_25), a
// javax.crypto.BadPaddingException
// "Given final block not properly padded" is thrown if
// we do not read the complete stream
readStreamUntilEnd(decrypted);
}
}
// sanity check if the file was properly decrypted
if (majorVersion < 1 || majorVersion > 10 || version < 1 || version > 100)
throw new IOException(Messages.MsgIncorrectPassword);
if (majorVersion > Client.MAJOR_VERSION || version > Client.CURRENT_VERSION)
throw new IOException(MessageFormat.format(Messages.MsgUnsupportedVersionClientFiled, version));

// wrap with zip input stream
ZipInputStream zipin = new ZipInputStream(decrypted);
zipin.getNextEntry();

Client client = new XmlSerialization().load(new InputStreamReader(zipin, StandardCharsets.UTF_8));

// save secret key for next save
client.setSecret(secret);
Expand All @@ -288,6 +263,21 @@ public Client load(final InputStream input) throws IOException
{
throw new IOException(MessageFormat.format(Messages.MsgErrorDecrypting, e.getMessage()), e);
}
finally
{
try
{
if (decrypted != null)
decrypted.close();
}
catch (IOException ignore)
{
// starting with a later jdk 1.8.0 (for example 1.8.0_25), a
// javax.crypto.BadPaddingException
// "Given final block not properly padded" is thrown if the
// we do not read the complete stream
}
}
}

@Override
Expand Down Expand Up @@ -325,22 +315,22 @@ public void save(Client client, final OutputStream output) throws IOException
output.write(iv);

// encrypted stream
try (OutputStream encrypted = new CipherOutputStream(output, cipher))
{
// write version information
encrypted.write(ByteBuffer.allocate(4).putInt(Client.MAJOR_VERSION).array());
encrypted.write(ByteBuffer.allocate(4).putInt(client.getVersion()).array());
OutputStream encrpyted = new CipherOutputStream(output, cipher);

// wrap with zip output stream
try (ZipOutputStream zipout = new ZipOutputStream(encrypted))
{
zipout.setLevel(Deflater.BEST_COMPRESSION);
zipout.putNextEntry(new ZipEntry(ZIP_DATA_FILE));
// write version information
encrpyted.write(ByteBuffer.allocate(4).putInt(Client.MAJOR_VERSION).array());
encrpyted.write(ByteBuffer.allocate(4).putInt(client.getVersion()).array());

new XmlSerialization().save(client, zipout);
zipout.closeEntry();
}
}
// wrap with zip output stream
ZipOutputStream zipout = new ZipOutputStream(encrpyted);
zipout.putNextEntry(new ZipEntry(ZIP_DATA_FILE));

new XmlSerialization().save(client, zipout);

zipout.closeEntry();
zipout.flush();
zipout.finish();
output.flush();
}
catch (GeneralSecurityException e)
{
Expand Down Expand Up @@ -388,17 +378,17 @@ public static Client load(File file, char[] password, IProgressMonitor monitor)
if (isEncrypted(file) && password == null)
throw new IOException(Messages.MsgPasswordMissing);

InputStream input = null;

try
{
// progress monitor
long bytesTotal = file.length();
int increment = (int) Math.min(bytesTotal / 20L, Integer.MAX_VALUE);
monitor.beginTask(MessageFormat.format(Messages.MsgReadingFile, file.getName()), 20);
try (InputStream input = new ProgressMonitorInputStream(new BufferedInputStream(new FileInputStream(file)),
increment, monitor))
{
return buildPersister(file, null, password).load(input);
}
input = new ProgressMonitorInputStream(new FileInputStream(file), increment, monitor);

return buildPersister(file, null, password).load(input);
}
catch (FileNotFoundException e)
{
Expand All @@ -407,6 +397,11 @@ public static Client load(File file, char[] password, IProgressMonitor monitor)
fnf.initCause(e);
throw fnf;
}
finally
{
if (input != null)
input.close();
}
}

public static Client load(Reader input) throws IOException
Expand All @@ -432,7 +427,7 @@ public static void save(final Client client, final File file, String method, cha
if (isEncrypted(file) && password == null && client.getSecret() == null)
throw new IOException(Messages.MsgPasswordMissing);

try (OutputStream output = new BufferedOutputStream(new FileOutputStream(file)))
try (OutputStream output = new FileOutputStream(file))
{
buildPersister(file, method, password).save(client, output);
}
Expand Down

0 comments on commit 644963e

Please sign in to comment.