Im trying to read my encrypted file and placing its decrypted contents into a list, but some lines towards the end split randomly or half way to a new line. Any ideas why it's doing this? (In the decrypt method). Btw the buffer is 1024 if that helps.
public Crypto() {
try {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(keySpec);
ecipher = Cipher.getInstance("PBEWithMD5AndDES");
dcipher = Cipher.getInstance("PBEWithMD5AndDES");
byte[] salt = new byte[8];
PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (Exception e) {
}
}
@SuppressWarnings("resource")
public static List<String> decrypt(String file) {
List<String> list = new LinkedList<String>();
try {
InputStream in = new CipherInputStream(new FileInputStream(file), dcipher);
int numRead = 0;
while ((numRead = in.read(buffer)) >= 0) {
list.add(new String(buffer, 0, numRead);
}
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
The read
method on a Stream
just reads a number of Byte
s into a buffer. So your code reads the file in chunks of size 1024 and saves each chunk read into a List
.
There are several ways to read a Stream
line by line, I would recommend the BufferedReader
final List<String> list = new LinkedList<String>();
try {
final BufferedReader reader = new BufferedReader(new InputStreamReader(new CipherInputStream(new FileInputStream(file), dcipher)));
String line;
while ((line = reader.readLine()) != null) {
list.add(line);
}
} catch (IOException e) {
e.printStackTrace();
}
One thing to note that has caught me out on numerous occasions is that the InputStreamReader
does an implicit conversion from Byte
to String
- this requires an encoding. By default the platform encoding will be used, this means that your code is platform dependent. The same goes for your original code as new String(byte[])
also uses the platform encoding be default.
I would recommend always specifying the encoding explicitly:
final BufferedReader reader = new BufferedReader(new InputStreamReader(new CipherInputStream(new FileInputStream(file), dcipher), "UTF-8"));
Or for the String
constructor
new String(bytes, "UTF-8")
The same goes for any code that writes a String
to a File
:
try {
try (final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new CipherOutputStream(new FileOutputStream(file), dcipher), "UTF-8"))) {
writer.append(data);
}
} catch (IOException ex) {
e.printStackTrace();
}
This way you avoid nasty surprises when running your application on a different OS as each family use a different default encoding (UTF-8
on Linux, ISO-8859-1
on Windows and MacRoman
on Mac).
Another note is that you do not close your Stream
(or Reader
now) - this is necessary, it can be done in a finally
in java 6 or using the new try-with-resources
construct of java 7.
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(new CipherInputStream(new FileInputStream(file), dcipher), "UTF-8"))) {
String line;
while ((line = reader.readLine()) != null) {
list.add(line);
}
}