200 lines
7.7 KiB
Java
200 lines
7.7 KiB
Java
/*
|
|
Copyright 2019-2023 Dmitry Isaenko
|
|
|
|
This file is part of libKonogonka.
|
|
|
|
libKonogonka is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
libKonogonka is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with libKonogonka. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
package libKonogonka.aesctr;
|
|
|
|
import java.io.BufferedInputStream;
|
|
import java.io.File;
|
|
import java.io.InputStream;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
|
|
public class InFileStreamClassicProducer implements IProducer {
|
|
private boolean encrypted;
|
|
|
|
private Path filePath;
|
|
private InFileStreamProducer parentProducer;
|
|
private long offset;
|
|
private long encryptedStartOffset;
|
|
private long encryptedEndOffset;
|
|
private AesCtrDecryptClassic decryptor;
|
|
private final long fileSize;
|
|
|
|
/** Reference AES-CTR stream producer.
|
|
* @param filePath Path to file-container
|
|
* @param offset Offset to skip (since file beginning).
|
|
* @param encryptedStartOffset Offset since file beginning where encrypted section starts
|
|
* @param encryptedEndOffset Offset since file beginning where encrypted section ends
|
|
* @param key AES-CTR Key
|
|
* @param iv CTR / IV (counter)
|
|
*/
|
|
public InFileStreamClassicProducer(Path filePath,
|
|
long offset,
|
|
long encryptedStartOffset,
|
|
long encryptedEndOffset, //Files.size(filePath)
|
|
String key,
|
|
byte[] iv) throws Exception{
|
|
this.encrypted = true;
|
|
this.filePath = filePath;
|
|
this.offset = offset;
|
|
this.encryptedStartOffset = encryptedStartOffset;
|
|
this.encryptedEndOffset = encryptedEndOffset;
|
|
this.decryptor = new AesCtrDecryptClassic(key, iv);
|
|
this.fileSize = Files.size(filePath);
|
|
}
|
|
private InFileStreamClassicProducer(Path filePath,
|
|
long offset,
|
|
long encryptedStartOffset,
|
|
long encryptedEndOffset, //Files.size(filePath)
|
|
AesCtrDecryptClassic decryptor) throws Exception{
|
|
this.encrypted = true;
|
|
this.filePath = filePath;
|
|
this.offset = offset;
|
|
this.encryptedStartOffset = encryptedStartOffset;
|
|
this.encryptedEndOffset = encryptedEndOffset;
|
|
this.decryptor = decryptor;
|
|
this.fileSize = Files.size(filePath);
|
|
}
|
|
/** Stream producer for non-encrypted files.
|
|
* @param filePath Path to file-container
|
|
* */
|
|
public InFileStreamClassicProducer(Path filePath) throws Exception{
|
|
this.filePath = filePath;
|
|
this.fileSize = Files.size(filePath);
|
|
}
|
|
/** Stream producer for non-encrypted files.
|
|
* @param filePath Path to file-container
|
|
* @param offset Offset to skip (since file beginning).
|
|
* */
|
|
public InFileStreamClassicProducer(Path filePath, long offset) throws Exception{
|
|
this.filePath = filePath;
|
|
this.offset = offset;
|
|
this.fileSize = Files.size(filePath);
|
|
}
|
|
/** Reference AES-CTR stream producer that utilizes InFileStreamProducer instead of file.
|
|
* @param parentProducer Producer of the stream
|
|
* @param offset Offset to skip at parent stream
|
|
* @param encryptedStartOffset Offset since parent stream start at stream where encrypted section starts
|
|
* @param encryptedEndOffset Offset since parent stream start at stream where encrypted section ends
|
|
* @param key AES-CTR Key
|
|
* @param iv CTR / IV (counter)
|
|
* @param fileSize File Size
|
|
*/
|
|
public InFileStreamClassicProducer(InFileStreamProducer parentProducer,
|
|
long offset,
|
|
long encryptedStartOffset,
|
|
long encryptedEndOffset,
|
|
String key,
|
|
byte[] iv,
|
|
long fileSize) throws Exception{
|
|
this.parentProducer = parentProducer;
|
|
this.encrypted = true;
|
|
this.offset = offset;
|
|
this.encryptedStartOffset = encryptedStartOffset;
|
|
this.encryptedEndOffset = encryptedEndOffset;
|
|
this.decryptor = new AesCtrDecryptClassic(key, iv);
|
|
this.fileSize = fileSize;
|
|
}
|
|
private InFileStreamClassicProducer(InFileStreamProducer parentProducer,
|
|
long offset,
|
|
long encryptedStartOffset,
|
|
long encryptedEndOffset,
|
|
AesCtrDecryptClassic decryptor,
|
|
long fileSize){
|
|
this.parentProducer = parentProducer;
|
|
this.encrypted = true;
|
|
this.offset = offset;
|
|
this.encryptedStartOffset = encryptedStartOffset;
|
|
this.encryptedEndOffset = encryptedEndOffset;
|
|
this.decryptor = decryptor;
|
|
this.fileSize = fileSize;
|
|
}
|
|
|
|
@Override
|
|
public BufferedInputStream produce() throws Exception{
|
|
if (encrypted)
|
|
return produceAesCtr();
|
|
return produceNotEncrypted();
|
|
}
|
|
|
|
private BufferedInputStream produceAesCtr() throws Exception{
|
|
decryptor.reset();
|
|
|
|
InputStream is;
|
|
|
|
if (filePath == null)
|
|
is = parentProducer.produce();
|
|
else
|
|
is = Files.newInputStream(filePath);
|
|
|
|
AesCtrBufferedInputStream stream = new AesCtrBufferedInputStream(
|
|
decryptor, encryptedStartOffset, encryptedEndOffset, is, fileSize);
|
|
|
|
if (offset != stream.skip(offset))
|
|
throw new Exception("Unable to skip offset: "+offset);
|
|
|
|
return stream;
|
|
}
|
|
|
|
private BufferedInputStream produceNotEncrypted() throws Exception{
|
|
BufferedInputStream stream;
|
|
|
|
if (filePath == null)
|
|
stream = new BufferedInputStream(parentProducer.produce());
|
|
else
|
|
stream = new BufferedInputStream(Files.newInputStream(filePath));
|
|
|
|
if (offset != stream.skip(offset))
|
|
throw new Exception("Unable to skip offset: "+offset);
|
|
|
|
return stream;
|
|
}
|
|
@Override
|
|
public InFileStreamClassicProducer getSuccessor(long offset) throws Exception{
|
|
if (! encrypted)
|
|
return new InFileStreamClassicProducer(filePath, offset);
|
|
|
|
if (filePath == null)
|
|
return new InFileStreamClassicProducer(parentProducer, offset, encryptedStartOffset, encryptedEndOffset, decryptor, fileSize);
|
|
return new InFileStreamClassicProducer(filePath, offset, encryptedStartOffset, encryptedEndOffset, decryptor);
|
|
}
|
|
|
|
public InFileStreamClassicProducer getSuccessor(long offset, boolean incrementExisting) throws Exception{
|
|
if (incrementExisting)
|
|
return getSuccessor(this.offset + offset);
|
|
return getSuccessor(offset);
|
|
}
|
|
|
|
@Override
|
|
public boolean isEncrypted() {
|
|
return encrypted;
|
|
}
|
|
@Override
|
|
public File getFile(){
|
|
if (filePath == null)
|
|
return parentProducer.getFile();
|
|
return filePath.toFile();
|
|
}
|
|
@Override
|
|
public String toString(){
|
|
if (filePath == null)
|
|
return parentProducer.getFile().getAbsolutePath();
|
|
return filePath.toString();
|
|
}
|
|
}
|