1
Fork 0
mirror of https://github.com/Steffo99/unimore-oop-2020-cleaver.git synced 2024-11-22 08:04:19 +00:00

Do some things that I haven't finished yet

This commit is contained in:
Steffo 2020-01-07 21:18:49 +01:00
parent 823736aecc
commit b90693550a
40 changed files with 478 additions and 322 deletions

View file

@ -2,7 +2,7 @@ package eu.steffo.cleaver;
import javax.swing.*;
import eu.steffo.cleaver.gui.CleaverFrame;
import eu.steffo.cleaver.logic.Job;
import eu.steffo.cleaver.logic.job.Job;
import java.util.ArrayList;

View file

@ -1,8 +1,6 @@
package eu.steffo.cleaver;
import eu.steffo.cleaver.logic.ChopJob;
import eu.steffo.cleaver.logic.Job;
import eu.steffo.cleaver.logic.split.SplitFileOutputStream;
import eu.steffo.cleaver.logic.stream.output.CleaverSplitFileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@ -10,7 +8,7 @@ import java.io.OutputStream;
//TODO: delet this
public class Test {
public static void main(String[] args) {
OutputStream stream = new SplitFileOutputStream("test", 64);
OutputStream stream = new CleaverSplitFileOutputStream("test", 64);
for(int i = 0; i < 256; i++) {
try {
stream.write(i);

View file

@ -3,8 +3,7 @@ package eu.steffo.cleaver.gui;
import eu.steffo.cleaver.gui.panels.ChopAndStitchPanel;
import eu.steffo.cleaver.gui.panels.JobsButtonsPanel;
import eu.steffo.cleaver.gui.panels.JobsTablePanel;
import eu.steffo.cleaver.logic.Job;
import eu.steffo.cleaver.logic.progress.NotStartedProgress;
import eu.steffo.cleaver.logic.job.Job;
import java.awt.*;
import java.awt.event.ActionEvent;

View file

@ -1,6 +1,7 @@
package eu.steffo.cleaver.gui.panels;
import eu.steffo.cleaver.logic.Job;
import eu.steffo.cleaver.logic.job.Job;
import eu.steffo.cleaver.logic.job.ChopJob;
import javax.swing.*;
import java.awt.event.ActionListener;
@ -48,7 +49,7 @@ public class ChopAndStitchPanel extends JPanel {
* @param jobs The {@link ArrayList} of jobs that should be manipulated.
* @param onProgressChange The function that should be invoked when the {@link Job} {@link eu.steffo.cleaver.logic.progress.Progress Progress} changes.
* @see ChopPanel#createAndAddJobs(ArrayList, Runnable)
* @see eu.steffo.cleaver.logic.ChopJob
* @see ChopJob
* @see eu.steffo.cleaver.gui.CleaverFrame
*/
public void createAndAddChopJobs(ArrayList<Job> jobs, Runnable onProgressChange) {
@ -60,7 +61,7 @@ public class ChopAndStitchPanel extends JPanel {
* @param jobs The {@link ArrayList} of jobs that should be manipulated.
* @param onProgressChange The function that should be invoked when the {@link Job} {@link eu.steffo.cleaver.logic.progress.Progress Progress} changes.
* @see StitchPanel#createAndAddJobs(ArrayList, Runnable)
* @see eu.steffo.cleaver.logic.ChopJob
* @see ChopJob
* @see eu.steffo.cleaver.gui.CleaverFrame
*/
public void createAndAddStitchJobs(ArrayList<Job> jobs, Runnable onProgressChange) {

View file

@ -4,11 +4,11 @@ import eu.steffo.cleaver.gui.panels.rows.CreateJobButtonRow;
import eu.steffo.cleaver.gui.panels.rows.option.CompressRow;
import eu.steffo.cleaver.gui.panels.rows.option.CryptRow;
import eu.steffo.cleaver.gui.panels.rows.option.SplitRow;
import eu.steffo.cleaver.logic.ChopJob;
import eu.steffo.cleaver.logic.Job;
import eu.steffo.cleaver.logic.compress.CompressConfig;
import eu.steffo.cleaver.logic.crypt.CryptConfig;
import eu.steffo.cleaver.logic.split.SplitConfig;
import eu.steffo.cleaver.logic.job.ChopJob;
import eu.steffo.cleaver.logic.job.Job;
import eu.steffo.cleaver.logic.config.CompressConfig;
import eu.steffo.cleaver.logic.config.CryptConfig;
import eu.steffo.cleaver.logic.config.SplitConfig;
import javax.swing.*;
import java.awt.event.ActionListener;

View file

@ -1,9 +1,9 @@
package eu.steffo.cleaver.gui.panels;
import eu.steffo.cleaver.logic.Job;
import eu.steffo.cleaver.logic.compress.CompressConfig;
import eu.steffo.cleaver.logic.crypt.CryptConfig;
import eu.steffo.cleaver.logic.split.SplitConfig;
import eu.steffo.cleaver.logic.job.Job;
import eu.steffo.cleaver.logic.config.CompressConfig;
import eu.steffo.cleaver.logic.config.CryptConfig;
import eu.steffo.cleaver.logic.config.SplitConfig;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;

View file

@ -4,8 +4,8 @@ import eu.steffo.cleaver.errors.ChpFileError;
import eu.steffo.cleaver.errors.ProgrammingError;
import eu.steffo.cleaver.gui.panels.rows.CreateJobButtonRow;
import eu.steffo.cleaver.gui.panels.rows.option.KeyRow;
import eu.steffo.cleaver.logic.Job;
import eu.steffo.cleaver.logic.StitchJob;
import eu.steffo.cleaver.logic.job.Job;
import eu.steffo.cleaver.logic.job.StitchJob;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;

View file

@ -1,6 +1,6 @@
package eu.steffo.cleaver.gui.panels.rows.option;
import eu.steffo.cleaver.logic.compress.CompressConfig;
import eu.steffo.cleaver.logic.config.CompressConfig;
import javax.swing.*;

View file

@ -1,6 +1,6 @@
package eu.steffo.cleaver.gui.panels.rows.option;
import eu.steffo.cleaver.logic.crypt.CryptConfig;
import eu.steffo.cleaver.logic.config.CryptConfig;
import javax.swing.*;

View file

@ -1,9 +1,11 @@
package eu.steffo.cleaver.gui.panels.rows.option;
import eu.steffo.cleaver.logic.config.CryptConfig;
import javax.swing.*;
/**
* A {@link OptionRow} allowing the {@link eu.steffo.cleaver.logic.crypt.CryptConfig configuration of the crypt step} of the file stitch process.
* A {@link OptionRow} allowing the {@link CryptConfig configuration of the crypt step} of the file stitch process.
*
* This configuration is used only if the selected *.chp file specifies that the *.cXX are encrypted.
*

View file

@ -1,8 +1,8 @@
package eu.steffo.cleaver.gui.panels.rows.option;
import eu.steffo.cleaver.logic.split.SplitByPartsConfig;
import eu.steffo.cleaver.logic.split.SplitBySizeConfig;
import eu.steffo.cleaver.logic.split.SplitConfig;
import eu.steffo.cleaver.logic.config.SplitByPartsConfig;
import eu.steffo.cleaver.logic.config.SplitBySizeConfig;
import eu.steffo.cleaver.logic.config.SplitConfig;
import javax.swing.*;
import javax.swing.event.DocumentEvent;

View file

@ -1,25 +0,0 @@
package eu.steffo.cleaver.logic.compress;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* A class containing the configuration for the compression step of a {@link eu.steffo.cleaver.logic.Job Job}.
*/
public class CompressConfig {
@Override
public String toString() {
return "Yes (Deflate)";
}
/**
* Create a {@link Element} representing this CompressConfig (to be used in *.chp metadata files).
* @param doc The {@link Document} the {@link Element} should be created in.
* @return The created {@link Element}.
* @see eu.steffo.cleaver.logic.ChopJob
* @see eu.steffo.cleaver.logic.StitchJob
*/
public Element toElement(Document doc) {
return doc.createElement("Compress");
}
}

View file

@ -1,4 +0,0 @@
/**
* The package containing classes related to the (de)compression functionality.
*/
package eu.steffo.cleaver.logic.compress;

View file

@ -0,0 +1,13 @@
package eu.steffo.cleaver.logic.config;
import eu.steffo.cleaver.logic.job.Job;
/**
* A class containing the configuration for the compression step of a {@link Job Job}.
*/
public class CompressConfig {
@Override
public String toString() {
return "Yes (Deflate)";
}
}

View file

@ -0,0 +1,30 @@
package eu.steffo.cleaver.logic.config;
import eu.steffo.cleaver.logic.job.Job;
/**
* A class containing the configuration for the encryption/decryption step of a {@link Job Job}.
*/
public class CryptConfig {
protected final String key;
/**
* Construct a new CryptConfig with a specific encryption key.
* @param key The encryption key.
*/
public CryptConfig(String key) {
this.key = key;
}
/**
* @return The encryption key.
*/
public String getKey() {
return key;
}
@Override
public String toString() {
return "••••••••";
}
}

View file

@ -1,4 +1,4 @@
package eu.steffo.cleaver.logic.split;
package eu.steffo.cleaver.logic.config;
/**
* A {@link SplitConfig} created by reading a *.chp file, containing the number of parts and their size, but not the resulting file size.

View file

@ -1,4 +1,4 @@
package eu.steffo.cleaver.logic.split;
package eu.steffo.cleaver.logic.config;
public class SplitByPartsConfig extends SplitConfig {
/**

View file

@ -1,4 +1,4 @@
package eu.steffo.cleaver.logic.split;
package eu.steffo.cleaver.logic.config;
/**
* A {@link SplitConfig} for splitting a file in parts of a specific part size.

View file

@ -0,0 +1,29 @@
package eu.steffo.cleaver.logic.config;
import eu.steffo.cleaver.logic.job.Job;
/**
* A class containing the configuration for the split/merge step of a {@link Job Job}.
*/
public abstract class SplitConfig {
/**
* @return The size in bytes of a single part of the file.
*/
public abstract long getPartSize();
/**
* @return The number of parts the file should be split in.
*/
public abstract int getPartCount();
/**
* @return The total size of the original file.
*/
public abstract long getTotalSize();
/**
* @return The string representation of the {@link SplitConfig}, to be used in the jobs table.
* @see eu.steffo.cleaver.gui.panels.JobsTablePanel
*/
public abstract String toString();
}

View file

@ -1,42 +0,0 @@
package eu.steffo.cleaver.logic.crypt;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* A class containing the configuration for the encryption/decryption step of a {@link eu.steffo.cleaver.logic.Job Job}.
*/
public class CryptConfig {
protected final String key;
/**
* Construct a new CryptConfig with a specific encryption key.
* @param key The encryption key.
*/
public CryptConfig(String key) {
this.key = key;
}
/**
* @return The encryption key.
*/
public String getKey() {
return key;
}
@Override
public String toString() {
return "••••••••";
}
/**
* Create a {@link Element} representing this CryptConfig (to be used in *.chp metadata files).
* @param doc The {@link Document} the {@link Element} should be created in.
* @return The created {@link Element}.
* @see eu.steffo.cleaver.logic.ChopJob
* @see eu.steffo.cleaver.logic.StitchJob
*/
public Element toElement(Document doc) {
return doc.createElement("Crypt");
}
}

View file

@ -1,122 +0,0 @@
package eu.steffo.cleaver.logic.crypt;
import eu.steffo.cleaver.errors.ProgrammingError;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
public class CryptOutputStream extends FilterOutputStream {
private Cipher cipher;
/**
* @return The algorithm used for the encryption.
*/
public String getAlgorithm() {
return "AES";
}
/**
* @return The mode of operation used for the encryption.
*/
public String getModeOfOperation() {
return "CFB8";
}
/**
* @return The padding used for the encryption.
*/
public String getPadding() {
return "PKCS5Padding";
}
/**
* @return The secret key algorithm used in the generation of the final key.
*/
public String getKeyAlgorithm() {
return "PBKDF2WithHmacSHA1";
}
/**
* @return The full transformation string as required by {@link Cipher#getInstance(String)}.
*/
public String getTransformationString() {
return String.format("%s/%s/%s", getAlgorithm(), getModeOfOperation(), getPadding());
}
/**
* Create a new CryptOutputStream with default {@link Cipher} parameters.
* (AES algorithm in operation mode CFB8 with PKCS5 padding)
*
* Does not use this as {@literal try} and {@literal catch} are not supported.
*
* @param out The {@link OutputStream} to connect this {@link FilterOutputStream} to.
* @param key The desired encryption key.
*/
public CryptOutputStream(OutputStream out, String key) throws InvalidKeyException {
super(out);
//Setup the cipher object
try {
cipher = Cipher.getInstance(getTransformationString());
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
//Should never happen, as it's predefined
e.printStackTrace();
return;
}
//Create the salt
byte[] salt = new byte[8];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(salt);
//Create the KeySpec
//Using the recommended 65536 as iteration count
KeySpec spec = new PBEKeySpec(key.toCharArray(), salt, 65536, 256);
SecretKeyFactory factory;
try {
factory = SecretKeyFactory.getInstance(getKeyAlgorithm());
} catch (NoSuchAlgorithmException e) {
//Should never happen, as it's predefined
e.printStackTrace();
return;
}
//Create the pbkdf secret key
SecretKey pbkdf;
try {
pbkdf = factory.generateSecret(spec);
} catch (InvalidKeySpecException e) {
//Should never happen, as it's predefined
e.printStackTrace();
return;
}
//"Convert" the secret key to a AES secret key
SecretKey aes = new SecretKeySpec(pbkdf.getEncoded(), getAlgorithm());
//Init the cipher instance
cipher.init(Cipher.ENCRYPT_MODE, aes);
}
@Override
public void write(int decryptedInt) throws IOException {
byte[] decryptedByte = new byte[1];
decryptedByte[0] = (byte)decryptedInt;
byte[] encryptedByte = cipher.update(decryptedByte);
int encryptedInt = encryptedByte[0];
super.write(encryptedInt);
}
}

View file

@ -1,4 +0,0 @@
/**
* The package containing classes related to the encryption/decryption functionality.
*/
package eu.steffo.cleaver.logic.crypt;

View file

@ -1,15 +1,15 @@
package eu.steffo.cleaver.logic;
package eu.steffo.cleaver.logic.job;
import eu.steffo.cleaver.errors.ProgrammingError;
import eu.steffo.cleaver.logic.compress.CompressConfig;
import eu.steffo.cleaver.logic.crypt.CryptConfig;
import eu.steffo.cleaver.logic.crypt.CryptOutputStream;
import eu.steffo.cleaver.logic.config.CompressConfig;
import eu.steffo.cleaver.logic.config.CryptConfig;
import eu.steffo.cleaver.logic.stream.output.CleaverCryptOutputStream;
import eu.steffo.cleaver.logic.progress.ErrorProgress;
import eu.steffo.cleaver.logic.progress.FinishedProgress;
import eu.steffo.cleaver.logic.progress.Progress;
import eu.steffo.cleaver.logic.progress.WorkingProgress;
import eu.steffo.cleaver.logic.split.SplitConfig;
import eu.steffo.cleaver.logic.split.SplitFileOutputStream;
import eu.steffo.cleaver.logic.config.SplitConfig;
import eu.steffo.cleaver.logic.stream.output.CleaverSplitFileOutputStream;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -95,7 +95,7 @@ public class ChopJob extends Job {
OutputStream outputStream;
if(splitConfig != null) {
outputStream = new SplitFileOutputStream(file.getAbsolutePath(), splitConfig.getPartSize());
outputStream = new CleaverSplitFileOutputStream(file.getAbsolutePath(), splitConfig.getPartSize());
}
else {
outputStream = new FileOutputStream(String.format("%s.c0", file.getAbsolutePath()));
@ -106,7 +106,7 @@ public class ChopJob extends Job {
}
if(cryptConfig != null) {
outputStream = new CryptOutputStream(outputStream, cryptConfig.getKey());
outputStream = new CleaverCryptOutputStream(outputStream, cryptConfig.getKey());
}
//Create the .chp file

View file

@ -1,13 +1,13 @@
package eu.steffo.cleaver.logic;
package eu.steffo.cleaver.logic.job;
import java.io.File;
import javax.swing.SwingUtilities;
import eu.steffo.cleaver.logic.compress.CompressConfig;
import eu.steffo.cleaver.logic.crypt.CryptConfig;
import eu.steffo.cleaver.logic.config.CompressConfig;
import eu.steffo.cleaver.logic.config.CryptConfig;
import eu.steffo.cleaver.logic.progress.NotStartedProgress;
import eu.steffo.cleaver.logic.progress.Progress;
import eu.steffo.cleaver.logic.split.SplitConfig;
import eu.steffo.cleaver.logic.config.SplitConfig;
/**
* A {@link Thread} that allows access to the basic .

View file

@ -1,16 +1,18 @@
package eu.steffo.cleaver.logic;
package eu.steffo.cleaver.logic.job;
import eu.steffo.cleaver.errors.ChpFileError;
import eu.steffo.cleaver.errors.ProgrammingError;
import eu.steffo.cleaver.logic.compress.CompressConfig;
import eu.steffo.cleaver.logic.crypt.CryptConfig;
import eu.steffo.cleaver.logic.crypt.CryptInputStream;
import eu.steffo.cleaver.logic.config.CompressConfig;
import eu.steffo.cleaver.logic.config.CryptConfig;
import eu.steffo.cleaver.logic.config.MergeConfig;
import eu.steffo.cleaver.logic.config.SplitConfig;
import eu.steffo.cleaver.logic.stream.input.CryptInputStream;
import eu.steffo.cleaver.logic.progress.ErrorProgress;
import eu.steffo.cleaver.logic.progress.FinishedProgress;
import eu.steffo.cleaver.logic.progress.Progress;
import eu.steffo.cleaver.logic.progress.WorkingProgress;
import eu.steffo.cleaver.logic.split.*;
import eu.steffo.cleaver.logic.stream.input.CleaverSplitFileInputStream;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@ -21,7 +23,6 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.util.zip.DeflaterInputStream;
import java.util.zip.InflaterInputStream;
/**
@ -190,7 +191,7 @@ public class StitchJob extends Job {
OutputStream outputStream = new FileOutputStream(resultFile);
if (splitConfig != null) {
inputStream = new SplitFileInputStream(resultFile.getPath(), splitConfig.getPartSize());
inputStream = new CleaverSplitFileInputStream(resultFile.getPath(), splitConfig.getPartSize());
}
else {
inputStream = new FileInputStream(String.format("%s.c0", resultFile.getAbsolutePath()));

View file

@ -0,0 +1,4 @@
/**
* The package containing all possible {@link eu.steffo.cleaver.logic.job.Job Jobs}.
*/
package eu.steffo.cleaver.logic.job;

View file

@ -1,7 +1,9 @@
package eu.steffo.cleaver.logic.progress;
import eu.steffo.cleaver.logic.job.Job;
/**
* A {@link Progress} that specifies that a {@link eu.steffo.cleaver.logic.Job} stopped because an exception occoured.
* A {@link Progress} that specifies that a {@link Job} stopped because an exception occoured.
*/
public class ErrorProgress extends Progress {
private final Throwable error;
@ -15,7 +17,7 @@ public class ErrorProgress extends Progress {
}
/**
* @return The error encountered by the {@link eu.steffo.cleaver.logic.Job}.
* @return The error encountered by the {@link Job}.
*/
public Throwable getError() {
return error;

View file

@ -1,7 +1,9 @@
package eu.steffo.cleaver.logic.progress;
import eu.steffo.cleaver.logic.job.Job;
/**
* A {@link Progress} that specifies that a {@link eu.steffo.cleaver.logic.Job} has finished.
* A {@link Progress} that specifies that a {@link Job} has finished.
*/
public class FinishedProgress extends Progress {
@Override

View file

@ -1,7 +1,9 @@
package eu.steffo.cleaver.logic.progress;
import eu.steffo.cleaver.logic.job.Job;
/**
* A {@link Progress} that specifies that a {@link eu.steffo.cleaver.logic.Job} hasn't started yet.
* A {@link Progress} that specifies that a {@link Job} hasn't started yet.
*/
public class NotStartedProgress extends Progress {
@Override

View file

@ -1,7 +1,9 @@
package eu.steffo.cleaver.logic.progress;
import eu.steffo.cleaver.logic.job.Job;
/**
* A {@link Progress} that specifies that a {@link eu.steffo.cleaver.logic.Job} is currently running and has progressed to {@link #progress} %.
* A {@link Progress} that specifies that a {@link Job} is currently running and has progressed to {@link #progress} %.
*/
public class WorkingProgress extends Progress {
public final float progress;

View file

@ -1,59 +0,0 @@
package eu.steffo.cleaver.logic.split;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* A class containing the configuration for the split/merge step of a {@link eu.steffo.cleaver.logic.Job Job}.
*/
public abstract class SplitConfig {
//TODO REBUILD ERRORS
/**
* Create a {@link Element} representing this SplitConfig (to be used in *.chp metadata files).
*
* @param doc The {@link Document} the {@link Element} should be created in.
* @return The created {@link Element}.
*
* @see eu.steffo.cleaver.logic.ChopJob
* @see eu.steffo.cleaver.logic.StitchJob
*/
public Element toElement(Document doc) {
Element element = doc.createElement("Split");
Attr partSizeAttr = doc.createAttribute("part-size");
partSizeAttr.setValue(Long.toString(getPartSize()));
element.setAttributeNode(partSizeAttr);
Attr partCountAttr = doc.createAttribute("parts");
partCountAttr.setValue(Long.toString(getPartCount()));
element.setAttributeNode(partCountAttr);
Attr totalSizeAttr = doc.createAttribute("total-size");
totalSizeAttr.setValue(Long.toString(getPartCount()));
element.setAttributeNode(totalSizeAttr);
return element;
}
/**
* @return The size in bytes of a single part of the file.
*/
public abstract long getPartSize();
/**
* @return The number of parts the file should be split in.
*/
public abstract int getPartCount();
/**
* @return The total size of the original file.
*/
public abstract long getTotalSize();
/**
* @return The string representation of the {@link SplitConfig}, to be used in the jobs table.
* @see eu.steffo.cleaver.gui.panels.JobsTablePanel
*/
public abstract String toString();
}

View file

@ -1,4 +0,0 @@
/**
* The package containing classes related to the file splitting/merging functionality.
*/
package eu.steffo.cleaver.logic.split;

View file

@ -0,0 +1,4 @@
package eu.steffo.cleaver.logic.stream;
public interface ICleaverStream {
}

View file

@ -1,10 +1,10 @@
package eu.steffo.cleaver.logic.split;
package eu.steffo.cleaver.logic.stream.input;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class SplitFileInputStream extends InputStream {
public class CleaverSplitFileInputStream extends InputStream {
private final String fileBaseName;
private long currentByteCount;
private long maximumByteCount;
@ -20,7 +20,7 @@ public class SplitFileInputStream extends InputStream {
* @param fileBaseName The name of the files without the extension. If it is {@literal example}, the opened files will be {@literal example.c1}, {@literal example.c2}, and so on.
* @param maximumByteCount The number of bytes that should be read from a file before switching to the next one.
*/
public SplitFileInputStream(String fileBaseName, long maximumByteCount) {
public CleaverSplitFileInputStream(String fileBaseName, long maximumByteCount) {
this.fileBaseName = fileBaseName;
this.maximumByteCount = maximumByteCount;
this.currentByteCount = 0;

View file

@ -1,4 +1,4 @@
package eu.steffo.cleaver.logic.crypt;
package eu.steffo.cleaver.logic.stream.input;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;

View file

@ -0,0 +1,6 @@
package eu.steffo.cleaver.logic.stream.input;
import eu.steffo.cleaver.logic.stream.ICleaverStream;
public interface ICleaverInputStream extends ICleaverStream {
}

View file

@ -0,0 +1,98 @@
package eu.steffo.cleaver.logic.stream.output;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.OutputStream;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
public class CleaverCompressOutputStream extends DeflaterOutputStream implements ICleaverOutputStream {
/**
* Construct a new CleaverCompressOutputStream and ensure the passed {@link OutputStream} implements {@link ICleaverOutputStream}.
* @see DeflaterOutputStream#DeflaterOutputStream(OutputStream, Deflater, int, boolean)
*/
public CleaverCompressOutputStream(OutputStream out, Deflater def, int size, boolean syncFlush) {
super(out, def, size, syncFlush);
if(!(out instanceof ICleaverOutputStream)) {
throw new IllegalArgumentException("The OutputStream passed to the CleaverCompressOutputStream must implement ICleaverOutputStream.");
}
}
/**
* Construct a new CleaverCompressOutputStream and ensure the passed {@link OutputStream} implements {@link ICleaverOutputStream}.
* @see DeflaterOutputStream#DeflaterOutputStream(OutputStream, Deflater, int)
*/
public CleaverCompressOutputStream(OutputStream out, Deflater def, int size) {
super(out, def, size);
if(!(out instanceof ICleaverOutputStream)) {
throw new IllegalArgumentException("The OutputStream passed to the CleaverCompressOutputStream must implement ICleaverOutputStream.");
}
}
/**
* Construct a new CleaverCompressOutputStream and ensure the passed {@link OutputStream} implements {@link ICleaverOutputStream}.
* @see DeflaterOutputStream#DeflaterOutputStream(OutputStream, Deflater, boolean)
*/
public CleaverCompressOutputStream(OutputStream out, Deflater def, boolean syncFlush) {
super(out, def, syncFlush);
if(!(out instanceof ICleaverOutputStream)) {
throw new IllegalArgumentException("The OutputStream passed to the CleaverCompressOutputStream must implement ICleaverOutputStream.");
}
}
/**
* Construct a new CleaverCompressOutputStream and ensure the passed {@link OutputStream} implements {@link ICleaverOutputStream}.
* @see DeflaterOutputStream#DeflaterOutputStream(OutputStream, Deflater)
*/
public CleaverCompressOutputStream(OutputStream out, Deflater def) {
super(out, def);
if(!(out instanceof ICleaverOutputStream)) {
throw new IllegalArgumentException("The OutputStream passed to the CleaverCompressOutputStream must implement ICleaverOutputStream.");
}
}
/**
* Construct a new CleaverCompressOutputStream and ensure the passed {@link OutputStream} implements {@link ICleaverOutputStream}.
* @see DeflaterOutputStream#DeflaterOutputStream(OutputStream, boolean)
*/
public CleaverCompressOutputStream(OutputStream out, boolean syncFlush) {
super(out, syncFlush);
if(!(out instanceof ICleaverOutputStream)) {
throw new IllegalArgumentException("The OutputStream passed to the CleaverCompressOutputStream must implement ICleaverOutputStream.");
}
}
/**
* Construct a new CleaverCompressOutputStream and ensure the passed {@link OutputStream} implements {@link ICleaverOutputStream}.
* @see DeflaterOutputStream#DeflaterOutputStream(OutputStream)
*/
public CleaverCompressOutputStream(OutputStream out) {
super(out);
if(!(out instanceof ICleaverOutputStream)) {
throw new IllegalArgumentException("The OutputStream passed to the CleaverCompressOutputStream must implement ICleaverOutputStream.");
}
}
/**
* @return The name of the used compression algorithm (currently only {@literal Deflate}).
*/
public String getAlgorithm() {
return "Deflate";
}
@Override
public Element toElement(Document doc) {
Element element = doc.createElement("Compress");
Element child = ((ICleaverOutputStream)out).toElement(doc);
element.appendChild(child);
Attr algorithmAttr = doc.createAttribute("algorithm");
algorithmAttr.setValue(getAlgorithm());
element.setAttributeNode(algorithmAttr);
return element;
}
}

View file

@ -0,0 +1,174 @@
package eu.steffo.cleaver.logic.stream.output;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
public class CleaverCryptOutputStream extends FilterOutputStream implements ICleaverOutputStream {
private Cipher cipher;
/**
* The algorithm used for the encryption (<a href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard">Advanced Encryption Standard</a>).
*/
public static final String ENCRYPTION_ALGORITHM = "AES";
/**
* The mode of operation used for the encryption (<a href="https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Feedback_(CFB)">Cipher FeedBack</a> with 8-bit blocks).
*/
public static final String MODE_OF_OPERATION = "CFB8";
/**
* The padding standard used for the encryption (<a href="https://en.wikipedia.org/wiki/PKCS">PKCS#5</a>).
*/
public static final String PADDING = "PKCS5Padding";
/**
* The size in bytes of the <a href="https://en.wikipedia.org/wiki/Salt_(cryptography)">salt</a>.
*/
public static final int SALT_SIZE = 8;
/**
* The name of the key derivation algorithm to be used (<a href="https://en.wikipedia.org/wiki/PBKDF2">Password-Based Key Derivation Function 2</a> with <a href="https://en.wikipedia.org/wiki/HMAC">HMAC</a>-<a href="https://it.wikipedia.org/wiki/Secure_Hash_Algorithm>SHA512</a>).
*/
public static final String KEY_DERIVATION_ALGORITHM = "PBKDF2WithHmacSHA512";
/**
* The iteration count for the {@link #KEY_DERIVATION_ALGORITHM}.
*/
public static final int KEY_ITERATION_COUNT = 65535;
/**
* The length in bits of the key to be generated with the {@link #KEY_DERIVATION_ALGORITHM}.
*/
public static final int KEY_LENGTH = 512;
/**
* @return The full transformation string as required by {@link Cipher#getInstance(String)}.
*/
public String getTransformationString() {
return String.format("%s/%s/%s", ENCRYPTION_ALGORITHM, MODE_OF_OPERATION, PADDING);
}
/**
* Generate an array of secure random bytes.
* @param size The size of the array.
* @return The generated array of secure random bytes.
* @see SecureRandom
*/
protected byte[] generateSecure(int size) {
byte[] salt = new byte[8];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(salt);
return salt;
}
/**
* Generate a new <a href="https://en.wikipedia.org/wiki/Initialization_vector">Initialization Vector</a> with the specified size.
* @param size The size of the initialization vector.
* @return The generated IV.
*/
protected IvParameterSpec generateIV(int size) {
return new IvParameterSpec(generateSecure(size));
}
/**
* Generate a key starting from a character array.
* @throws NoSuchAlgorithmException If the {@link #KEY_DERIVATION_ALGORITHM} is invalid.
* @throws InvalidKeySpecException If the generated {@link KeySpec} is invalid.
*/
private SecretKey generatePasswordKey(char[] key) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeySpec spec = new PBEKeySpec(key, generateSecure(SALT_SIZE), KEY_ITERATION_COUNT, KEY_LENGTH);
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_DERIVATION_ALGORITHM);
return factory.generateSecret(spec);
}
/**
* Create and initialize the {@link Cipher} {@link #cipher} to be used by the CleaverCryptOutputStream.
* @param key The string to be used in the {@link Cipher} as encryption key.
* @throws NoSuchPaddingException If the {@link #PADDING} is invalid.
* @throws NoSuchAlgorithmException If the {@link #ENCRYPTION_ALGORITHM} is invalid.
* @throws InvalidKeySpecException If the generated {@link KeySpec} is invalid.
*/
private void createCipher(char[] key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidAlgorithmParameterException, InvalidKeyException {
//Setup the cipher object
cipher = Cipher.getInstance(getTransformationString());
//"Convert" the secret key to a AES secret key
SecretKey aes = new SecretKeySpec(generatePasswordKey(key).getEncoded(), ENCRYPTION_ALGORITHM);
//Init the cipher instance
cipher.init(Cipher.ENCRYPT_MODE, aes, generateIV(1));
}
/**
* Create a new CleaverCryptOutputStream with default {@link Cipher} parameters (AES algorithm in operation mode CFB8 with PKCS5 padding).
*
* @param out The {@link OutputStream} to connect this {@link FilterOutputStream} to.
* @param key The desired encryption key.
*/
public CleaverCryptOutputStream(OutputStream out, String key) {
super(out);
try {
createCipher(key.toCharArray());
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeySpecException | InvalidAlgorithmParameterException | InvalidKeyException e) {
e.printStackTrace();
}
}
@Override
public void write(int decryptedInt) throws IOException {
byte[] decryptedByte = new byte[1];
decryptedByte[0] = (byte)decryptedInt;
byte[] encryptedByte = cipher.update(decryptedByte);
int encryptedInt = encryptedByte[0];
super.write(encryptedInt);
}
@Override
public Element toElement(Document doc) {
Element element = doc.createElement("Crypt");
Element child = ((ICleaverOutputStream)out).toElement(doc);
element.appendChild(child);
Attr algorithmAttr = doc.createAttribute("algorithm");
algorithmAttr.setValue(ENCRYPTION_ALGORITHM);
element.setAttributeNode(algorithmAttr);
Attr modeOfOperationAttr = doc.createAttribute("mode-of-operation");
modeOfOperationAttr.setValue(MODE_OF_OPERATION);
element.setAttributeNode(modeOfOperationAttr);
Attr paddingAttr = doc.createAttribute("padding");
paddingAttr.setValue(PADDING);
element.setAttributeNode(paddingAttr);
Attr keyAlgorithmAttr = doc.createAttribute("key-algorithm");
keyAlgorithmAttr.setValue(KEY_DERIVATION_ALGORITHM);
element.setAttributeNode(keyAlgorithmAttr);
Attr iterationCountAttr = doc.createAttribute("iteration-count");
iterationCountAttr.setValue(Integer.toString(KEY_ITERATION_COUNT));
element.setAttributeNode(iterationCountAttr);
Attr keyLengthAttr = doc.createAttribute("key-length");
keyLengthAttr.setValue(Integer.toString(KEY_LENGTH));
element.setAttributeNode(keyLengthAttr);
return element;
}
}

View file

@ -1,4 +1,8 @@
package eu.steffo.cleaver.logic.split;
package eu.steffo.cleaver.logic.stream.output;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.FileOutputStream;
import java.io.IOException;
@ -9,10 +13,11 @@ import java.io.OutputStream;
*
* Bytes are written to a file until its length reaches {@link #maximumByteCount}, then the program switches to the following file (.c2 if .c1 is full, .c3 if .c2 is full, and so on).
*/
public class SplitFileOutputStream extends OutputStream {
public class CleaverSplitFileOutputStream extends OutputStream implements ICleaverOutputStream {
private final String fileBaseName;
private long currentByteCount;
private long maximumByteCount;
private long totalByteCount;
private int currentFileCount;
/**
@ -21,11 +26,11 @@ public class SplitFileOutputStream extends OutputStream {
protected FileOutputStream currentFileOutputStream;
/**
* Construct a SplitFileOutputStream.
* Construct a CleaverSplitFileOutputStream.
* @param fileBaseName The name of the files without the extension. If it is {@literal example}, the created files will be {@literal example.c1}, {@literal example.c2}, and so on.
* @param maximumByteCount The number of bytes that should be written to a file before switching to the next one.
*/
public SplitFileOutputStream(String fileBaseName, long maximumByteCount) {
public CleaverSplitFileOutputStream(String fileBaseName, long maximumByteCount) {
this.fileBaseName = fileBaseName;
this.maximumByteCount = maximumByteCount;
this.currentByteCount = 0;
@ -49,11 +54,13 @@ public class SplitFileOutputStream extends OutputStream {
@Override
public void write(int b) throws IOException {
// Can be optimized using the modulo operation, not doing it now for clarity
if(currentFileOutputStream == null || currentByteCount >= maximumByteCount) {
createNextFileOutputStream();
}
currentFileOutputStream.write(b);
currentByteCount += 1;
totalByteCount += 1;
}
@Override
@ -88,4 +95,31 @@ public class SplitFileOutputStream extends OutputStream {
public int getCurrentFileCount() {
return currentFileCount;
}
/**
* @return The number of bytes that have already been written.
*/
public long getTotalByteCount() {
return totalByteCount;
}
@Override
public Element toElement(Document doc) {
Element element = doc.createElement("Split");
element.setTextContent(fileBaseName);
Attr partSizeAttr = doc.createAttribute("part-size");
partSizeAttr.setValue(Long.toString(maximumByteCount));
element.setAttributeNode(partSizeAttr);
Attr partCountAttr = doc.createAttribute("parts");
partCountAttr.setValue(Long.toString(currentFileCount));
element.setAttributeNode(partCountAttr);
Attr totalSizeAttr = doc.createAttribute("total-size");
totalSizeAttr.setValue(Long.toString(totalByteCount));
element.setAttributeNode(totalSizeAttr);
return element;
}
}

View file

@ -0,0 +1,15 @@
package eu.steffo.cleaver.logic.stream.output;
import eu.steffo.cleaver.logic.stream.ICleaverStream;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public interface ICleaverOutputStream extends ICleaverStream {
/**
* Create a {@link Element} representing the stream (to be used in *.chp metadata files).
*
* @param doc The {@link Document} the {@link Element} should be created in.
* @return The created {@link Element}.
*/
public Element toElement(Document doc);
}