Hallo
ich habe mich ein wenig mit dem Thema Verschlüsselung beschäftigt und fand den Gedanken interessant, dass eine XOR - Verschlüsselung mit einer Schlüssellänge >= Input nicht zurück zu rechnen ist. Dabei dacht mir, ich könnt doch auch mal Dokumente gegen mp3s als Schlüssel ver - und entschlüsseln. Es ist folgendes kleines Projekt entstanden, was haltet ihr von dieser Umsetzung?
Vorteil:
sichere Verschlüssung
Nachteil:
hoher Zeitaufwand bei größeren Dateien
public class XORCrypter {
public enum CrypterMode {
ENCRYPT,
DECRYPT;
}
private File inputFile;
private File outputFile;
private File keyFile;
private CrypterMode mode;
private List<CrypterListener> listener = new ArrayList<CrypterListener>();
private boolean running = false;
private XORCrypter(File inputFile, File outputFile, File keyFile, CrypterMode mode) throws IllegalArgumentException {
this.inputFile = inputFile;
this.outputFile = outputFile;
this.keyFile = keyFile;
this.mode = mode;
if(inputFile.length() > keyFile.length()) {
//throw exception
//for save xor encryption key may not repeat
throw new IllegalArgumentException("key file may not be smaller than input file");
}
}
/**
* Creates a crypter object to encrypt
*
* @param inputFile
* @param outputFile
* @param keyFile
* @throws Exception
*/
public XORCrypter(File inputFile, File outputFile, File keyFile) throws IllegalArgumentException {
this(inputFile, outputFile, keyFile, CrypterMode.ENCRYPT);
}
/**
* Creates a crypter object to decrypt
*
* @param inputFile
* @param keyFile
* @throws Exception
*/
public XORCrypter(File inputFile, File keyFile) throws IllegalArgumentException {
this(inputFile, null, keyFile, CrypterMode.DECRYPT);
}
public void doWork() {
running = true;
FileInputStream inputFin = null;
FileInputStream keyFin = null;
FileOutputStream outputFout = null;
try {
inputFin = new FileInputStream(inputFile);
keyFin = new FileInputStream(keyFile);
if(mode == CrypterMode.DECRYPT) {
//read prefix
//get length
byte[] prefixData = new byte[Integer.SIZE / 8];
inputFin.read(prefixData);
byte[] keyData = new byte[prefixData.length];
keyFin.read(keyData);
prefixData = crypt(prefixData, keyData);
int prefixLength = byteArrayToInt(prefixData);
if(prefixLength > 64) {
//invalid key
//and now?
}
//get prefix data
prefixData = new byte[prefixLength];
inputFin.read(prefixData);
keyData = new byte[prefixData.length];
keyFin.read(keyData);
prefixData = crypt(prefixData, keyData);
String outputFileName = getNextPossibleFileName(new String(prefixData));
outputFile = new File(outputFileName);
}
outputFout = new FileOutputStream(outputFile);
if(mode == CrypterMode.ENCRYPT) {
//write prefix
byte[] prefixData = generatePrefix();
byte[] keyData = new byte[prefixData.length];
keyFin.read(keyData);
prefixData = crypt(prefixData, keyData);
outputFout.write(prefixData);
}
//write data
int dataByte;
int keyByte;
while(running && (dataByte = inputFin.read()) != -1) {
keyByte = keyFin.read();
dataByte ^= keyByte;
outputFout.write(dataByte);
}
if(running) {
for(CrypterListener l : listener) {
l.finished();
}
running = false;
}
else {
//aborted
for(CrypterListener l : listener) {
l.failed("process stopped");
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
for(CrypterListener l : listener) {
l.failed(e.getMessage());
}
}
finally {
try {
if(inputFin != null)
inputFin.close();
if(keyFin != null)
keyFin.close();
if(outputFout != null)
outputFout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void addListener(CrypterListener l) {
listener.add(l);
}
public void removeListener(CrypterListener l) {
listener.remove(l);
}
private byte[] crypt(byte[] data, byte[] key) {
byte[] cryptedData = new byte[data.length];
for(int i = 0; i < cryptedData.length; i++) {
cryptedData** = (byte) (data**^key**);
}
return cryptedData;
}
public boolean isRunning() {
return running;
}
public void stop() {
running = false;
}
private byte[] generatePrefix() {
String fileName = inputFile.getName();
ByteBuffer b = ByteBuffer.allocate(Integer.SIZE / 8 + fileName.getBytes().length);
b.putInt(fileName.getBytes().length);
b.put(fileName.getBytes());
return b.array();
}
private int byteArrayToInt(byte[] b) {
return b[3] & 0xFF |
(b[2] & 0xFF) << 8 |
(b[1] & 0xFF) << 16 |
(b[0] & 0xFF) << 24;
}
private String getNextPossibleFileName(String name) {
int counter = 0;
String nameToTest = name;
while(new File(nameToTest).exists()) {
counter++;
nameToTest = counter + "_" + name;
}
return nameToTest;
}
}
dazu ein kleiner Listener
public interface CrypterListener {
void finished();
void failed(String msg);
}
und eine mögliche Anwendung
File input = new File("file");
File key = new File("key.mp3");
File output = new File("file.enc");
XORCrypter enc;
enc = new XORCrypter(input, output, key);
enc.doWork();
XORCrypter dec;
dec = new XORCrypter(output, key);
dec.doWork();