using CipherOutputStream in Java, encrypted file ends up corrupted - java

I am doing my bachelor thesis on the topic of cryptography and its costs.
A part of that is to compare different crypto Algorithms and Cipher Modes in terms of Runtime and Resource cost.
For that I wrote a small tool that should work in four steps:
Read Input File
Encrypt the Input File and write it to a new file.
Read and decrypt the just written encrypted file.
Write another copy of the decrypted file onto file system.
Compare initial input file and decrypted file to see if they are equal.
It works just fine with a small .txt input File. But for some reason it doesn’t work with any other kind of file. If I take an Image as input File, the first few pixels are good, the rest ends up corrupted.
So as far as I understand the problem should be somehow when I initialize the Cipher or when I use the Streams.
I also tried to out comment the lines encrypting and decrypting and it also works then in just making plain copies of the input file which are identical.
Any suggestions are welcome, I will try to test them out asap and report back what results showed up.
I do apologies for the “Hungarian notations”. The p is just use for public and the l for local. It is the way we do it in our company.
So here is my class:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Date;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
public class AES_Cipher_Test {
public String pLocalRef = "E:\\Test.txt";
public String pLocalRefOutput = "E:\\Test-crypted.txt";
public String pLocalCopyOutput = "E:\\Test-Neu.txt";
public Key pKeyAES = null;
public int pBitKey = 128;
public Cipher pCipher;
public FileOutputStream pFos;
public FileInputStream pFis;
public CipherOutputStream pCos;
public CipherInputStream pCis;
public File pInputFile = new File(this.pLocalRef);
public File pOutputFile = new File(this.pLocalRefOutput);
public File pGeneratedFile = new File(this.pLocalCopyOutput);
public AES_Cipher_Test() {
crypt_decrypt_write_File();
}
public void crypt_decrypt_write_File() {
byte[] lLoadedFile = null;
byte[] lGeneratedFileByte = null;
try {
// generate new random AES Key
KeyGenerator lKeygen = KeyGenerator.getInstance("AES");
lKeygen.init(this.pBitKey);
this.pKeyAES = lKeygen.generateKey();
// read input File
this.pFis = new FileInputStream(this.pInputFile);
FileInputStream tempStream = new FileInputStream(this.pInputFile);
int count = 0;
while (tempStream.read() != -1){
count ++;
}
lLoadedFile = new byte[count]; // new byte[this.pFis.available()]
this.pFis.read(lLoadedFile);
System.err.println("lLoadedFile.legth " + lLoadedFile.length);
this.pFis.close();
//init Cipher with AES Encrypt Mode CFB8 oder CTR
this.pCipher = Cipher.getInstance("AES/CTR/PKCS5Padding");
this.pCipher.init(Cipher.ENCRYPT_MODE, this.pKeyAES);
// build cipher stream from FileOutputStream
this.pFos = new FileOutputStream(this.pOutputFile);
this.pCos = new CipherOutputStream(this.pFos, this.pCipher);
//write encrypted Data to stream
this.pCos.write(lLoadedFile);
this.pCos.close();
this.pFos.close();
// init Cipher for decrypt Mode
this.pCipher.init(Cipher.DECRYPT_MODE, this.pKeyAES, new IvParameterSpec(this.pCipher.getIV()));
// read just written localFile and decrypt
this.pFis = new FileInputStream(this.pOutputFile);
tempStream = new FileInputStream(this.pOutputFile);
count = 0;
while (tempStream.read() != -1){
count ++;
}
byte[] lBytes = new byte[count];// new byte[this.pFis.available()]
this.pCis = new CipherInputStream(this.pFis, this.pCipher);
int lBytesRead = this.pCis.read(lBytes);
while (lBytesRead > -1) {
lBytesRead = this.pCis.read(lBytes);
}
this.pCis.close();
this.pFis.close();
System.err.println("lBytes.length " + lBytes.length);
// write new not crypted File to see if procedure works
this.pFos = new FileOutputStream(this.pLocalCopyOutput);
this.pFos.write(lBytes);
this.pFos.close();
//compare Input File and Output File
this.pFis = new FileInputStream(this.pGeneratedFile);
tempStream = new FileInputStream(this.pGeneratedFile);
count = 0;
while (tempStream.read() != -1){
count ++;
}
lGeneratedFileByte = new byte[count]; // new byte[this.pFis.available()]
int i = this.pFis.read(lGeneratedFileByte);
this.pFis.close();
System.err.println("lGeneratedFileByte.length " + i);
System.err.println("Test if initial File and new File are identical = " + Arrays.equals(lGeneratedFileByte, lLoadedFile));
} catch (FileNotFoundException e) {
throw new RuntimeException("FILE_DOES_NOT_EXIST", e);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String args[]) {
System.err.println("Start AES_Cipher_Test");
long start = new Date().getTime();
new AES_Cipher_Test();
long runningTime = new Date().getTime() - start;
System.err.println("End AES_Cipher_Test");
System.err.println("Runtime: " + runningTime);
}
}

Usual series of mistakes.
read() isn't specified to fill the buffer. It is only specified to transfer at least one byte, or else return -1 indicating end of stream. You have to loop:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Your existing loop while (!(lBytesRead < lBytes.length)) is basically nonsense.
available() explicitly is not the total number of bytes in the stream, and any usage of it to allocate a buffer of such a size is explicitly stated in the Javadoc to be incorrect. Again, you have to loop, see above. There are few if any uses of available(), and this isn't one of them.

Related

Java how to start reading file after Nth line with good performance

I have a file where data keeps appending. I am using java to read that file and process the data. To get the latest data, I am storing the offset till where I have read the file and continue reading from that offset when java process runs next.
RandomAccessFile f = new RandomAccessFile("file.txt","r");
f.seek(offset)
The problem here is performance. Its around 300 times slower than BufferedReader. Is it possible to resume reading from particular line using BufferedReader?
import java.io.RandomAccessFile;
import java.io.FileReader;
import java.io.IOException;
public class ReadFileExample {
public static void main(String[] args) {
RandomAccessFile objReader = null;
try {
String strCurrentLine;
long startTime = System.currentTimeMillis();
objReader = new RandomAccessFile("auditlog-2018-12-21.txt", "r");
while ((strCurrentLine = objReader.readLine()) != null) {
}
System.out.println(System.currentTimeMillis()-startTime);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (objReader != null)
objReader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
Reading 30M file having 100,000 lines takes 12 s while replacing RandomAccessFile with BufferReader takes less than 400ms.
you can try the below code
try {
BufferedReader reader = Files.newBufferedReader(Paths.get("file.txt"), StandardCharsets.UTF_8);
List<String> line = reader.lines().skip(31).limit(1).collect(Collectors.toList());
line.stream().forEach(System.out::println);
}catch(Exception e){
}

I wanted to add a way to store points earned between games (Java)

I had several attempts of using java.io in several ways, but I could never get it to work. My idea was to store points earned in a file named save_data.txt, then retrieve the 3 highest integers in that list and display them on a leaderboard.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class TextFind {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
File file = new File("save_data.txt");
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
String text = null;
while((text = reader.readLine()) != null) {
list.add(Integer.parseInt(text));
}
}catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(reader != null) {
reader.close();
}
}catch(IOException e) {
}
}
}
}
I took this and called it when the game stopped running. It seems to do nothing.
You are not that far off actually. Are there values in your save_date.txt file? Here is some example using Java 8:
public static void main(String[] args) {
List<Integer> highScore = Arrays.asList(1, 2); // Dummy values
Path filePath = Paths.get("save_data.txt"); // Your saved data
// Transform available high scores to a single String using the System line separator to separated the values and afterwards transform the String to bytes ...
byte[] bytes = highScore.stream().map(Object::toString).collect(Collectors.joining(System.lineSeparator())).getBytes();
try {
// Write those high score bytes to a file ...
Files.write(filePath, bytes, StandardOpenOption.CREATE);
} catch (IOException e) {
e.printStackTrace();
}
List<String> lines = Collections.emptyList();
try {
// Read all available high scores lines from the file ...
lines = Files.readAllLines(filePath);
} catch (IOException e) {
e.printStackTrace();
}
int skipLines = Math.max(lines.size() - 3, 0); // You only want the three highest values so we use the line count to determine the amount of values that may be skipped and we make sure that the value may not be negative...
// Stream through all available lines stored in the file, transform the String objects to Integer objects, sort them, skip all values except the last three and sort their order descending
highScore = lines.stream().map(Integer::valueOf).sorted().skip(skipLines).sorted(Comparator.reverseOrder()).collect(Collectors.toList());
// Print the result
highScore.forEach(System.out::println);
}

zip file is being create but without any files in it

i copied this code directly from oracle website. i have two .png file inside d:\barcode. while i run this code myfigs.zip is created in d: drive but it is corruped and 0kb size.
code:-
public class Zip {
static final int BUFFER = 2048;
public static void main (String argv[]) {
try {
BufferedInputStream origin = null;
FileOutputStream dest = new
FileOutputStream("D:\\myfigs.zip");
CheckedOutputStream checksum = new
CheckedOutputStream(dest, new Adler32());
ZipOutputStream out = new
ZipOutputStream(new
BufferedOutputStream(checksum));
//out.setMethod(ZipOutputStream.DEFLATED);
byte data[] = new byte[BUFFER];
// get a list of files from current directory
File f = new File("D:\\barcode");
String files[] = f.list();
for (int i=0; i<files.length; i++) {
System.out.println("Adding: "+files[i]);
FileInputStream fi = new FileInputStream(files[i]);
origin = new BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(files[i]);
out.putNextEntry(entry);
int count;
while((count = origin.read(data, 0,
BUFFER)) != -1) {
out.write(data, 0, count);
}
origin.close();
}
out.close();
System.out.println("checksum: "+checksum.getChecksum().getValue());
} catch(Exception e) {
e.printStackTrace();
}
}
}
to add more information whenever i run the code in debug mode code is successfully compiled to FileInputStream fi line then it is stopped there. the error thrown is
java.io.FileNotFoundException: barcode.png (The system cannot find the file specified)
Adding: barcode.png
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
The exception says "file not found". Your "adding" print statement gives you the answer:
Adding: barcode.png
The file "barcode.png" is not the same as the file "D:\barcode\barcode.png". You're just looking for a file named "barcode.png" in whatever your current working directory is set to, and it isn't there.
As per the docs for list() and the conclusion you should have made from your observations of your printed output and exception:
Names denoting the directory itself and the directory's parent directory are not included in the result. Each string is a file name rather than a complete path.
So you need to either:
Change your working directory to "D:\barcode" first, or
Add the parent directory name ("D:\barcode") back to the beginning of your filename ("barcode.png") before opening it, or
Look at some of the other functions File has to offer and see if there's one that helps you avoid this problem entirely.
Couple other minor notes:
It should be no surprise that the zip file was empty, given that your code threw an exception before you wrote anything to it.
"whenever i run the code in debug mode code is successfully compiled to FileInputStream fi line then it is stopped there" - This terminology is not correct. Your error was not a compiler error, it was a runtime error. The code compiled just fine.
The root cause of your problem was blind modification of the code copied from the Oracle site. Note the original comment, "get a list of files from current directory" -- This code assumed the files came from the current working directory. When you added your own directory in, that was no longer the case, and the program broke.
You can use as below code for zip one file:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* Create by Cuder
*
*/
public class SampleZipFile {
/**
* Create by Cuder
*/
public static void main(String[] args) {
ZipOutputStream zipOutputStream = null;
FileInputStream fileInputStream = null;
try {
File fileInput = new File(
"D:\\eclipse4.4\\workspace\\SampleJava\\resource\\sampleZipFile.txt");
File fileOutput = new File(
"D:\\eclipse4.4\\workspace\\SampleJava\\resource\\sampleZipFile.zip");
FileOutputStream fileOutputStream = new FileOutputStream(fileOutput);
zipOutputStream = new ZipOutputStream(fileOutputStream);
fileInputStream = new FileInputStream(fileInput);
ZipEntry entry = new ZipEntry(fileInput.getName());
zipOutputStream.putNextEntry(entry);
byte[] buf = new byte[1024];
int byteRead = 0;
while ((byteRead = fileInputStream.read(buf)) > 0) {
zipOutputStream.write(buf, 0, byteRead);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (null != fileInputStream) {
fileInputStream.close();
}
if (null != zipOutputStream) {
zipOutputStream.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

Android Studio - Java Method Call getBytesFromFile() Fails

I am using Android Studio and Oracle Java 8. I am trying to get all bytes from a file and pass them to a byte array. The code below acts like it does not see import java.io.File;
I get the error message:
cannot resolve method getBytesFromFile(java.io.File)
code
import java.io.File;
// ...
File path = new File(
Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/zTest-Records/");
path.mkdirs();
try {
recordingFile = File.createTempFile("recording", ".pcm", path);
} catch (IOException e) {
throw new RuntimeException("Couldn't create pcm file", e);
}
// NOTE: The code below gives error message: cannot resolve method 'getBytesFromFile(java.io.File)'
byte[] data = getBytesFromFile(recordingFile);
That function is not defined, perhaps you copy paste this code from somewhere.
A quick google search points to this link:
https://code.google.com/p/picturesque/source/browse/myClasses/GetBytesFromFile.java?r=1d9332c4c969b4d35847c10f7c83b04c1ccb834f
package myClasses;
import java.util.*;
import java.io.*;
public class GetBytesFromFile {
public static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
// You cannot create an array using a long type.
// It needs to be an int type.
// Before converting to an int type, check
// to ensure that file is not larger than Integer.MAX_VALUE.
if (length > Integer.MAX_VALUE) {
// File is too large
}
// Create the byte array to hold the data
byte[] bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead = is.read(bytes, offset, Math.min(bytes.length - offset, 512*1024))) >= 0) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}
// Close the input stream and return bytes
is.close();
return bytes;
}
}
You probably need to add this class to your project

Write int to file using DataOutputStream

I'm generating random ints and trying to write them down to a file. The problem is when I open the file I've created I don't find my ints but a set of symbols like squares etc... Is it a problem of encoding ?
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class GenerateBigList {
public static void main(String[] args) {
//generate in memory big list of numbers in [0, 100]
List list = new ArrayList<Integer>(1000);
for (int i = 0; i < 1000; i++) {
Double randDouble = Math.random() * 100;
int randInt = randDouble.intValue();
list.add(randInt);
}
//write it down to disk
File file = new File("tmpFileSort.txt");
try {
FileOutputStream fos = new FileOutputStream("C:/tmp/tmpFileSort.txt");
DataOutputStream dos = new DataOutputStream(fos);
writeListInteger(list, dos);
dos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void writeListInteger(List<Integer> list, DataOutputStream dos) throws IOException {
for (Integer elt : list) {
dos.writeInt(elt);
}
}
}
A partial copy paste from the created file:
/ O a C ? 6 N
From the doc:
public final void writeInt(int v) throws IOException
Writes an int to the underlying output stream as four bytes, high byte first. If no exception is thrown, the counter written is incremented by 4.
There is no encoding problem. That is what you see when you open a binary file with a text editor. Try to open with a hex editor.
Those "symbols" are your ints. That's what binary files look like if you open them in a text editor. Notice that the file is exactly 4000 bytes in size, and you wrote 1000 ints, at 4 bytes each.
If you read the file in with a DataInputStream you will get the original values back:
try (DataInputStream dis = new DataInputStream(
new BufferedInputStream(new FileInputStream("C:/tmp/tmpFileSort.txt")))) {
for (int i = 0; i < 1000; i++) {
System.out.println(dis.readInt());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
It writes binary, not text. Your expectations are misplaced. If you want text, use a Writer.

Categories

Resources