mercredi 18 février 2015

How to effeciently read chunk of bytes of a given range from a large encrypted file in java?

I have a large encrypted file(10GB+) in server. I need to transfer the decrypted file to the client in small chunks. When a client make a request for a chunk of bytes (say 18 to 45) I have to random access the file, read the specific bytes, decrypt it and transfer it to the client using ServletResponseStream.


But since the file is encrypted I have to read the file as blocks of 16 bytes in order to decrypt correctly.


So if client requests to get from byte 18 to 45, in the server I have to read the file in multiples of 16 bytes block. So I have to random access the file from byte 16 to 48. Then decrypt it. After decryption I have to skip 2 bytes from the first and 3 bytes from the last to return the appropriate chunk of data client requested.


Here is what I am trying to do


Adjust start and end for encrypted files



long start = 15; // input from client
long end = 45; // input from client
long skipStart = 0; // need to skip for encrypted file
long skipEnd = 0;

// encrypted files, it must be access in blocks of 16 bytes
if(fileisEncrypted){
skipStart = start % 16; // skip 2 byte at start
skipEnd = 16 - end % 16; // skip 3 byte at end
start = start - skipStart; // start becomes 16
end = end + skipEnd; // end becomes 48
}


Access the encrypted file data from start to end



try(final FileChannel channel = FileChannel.open(services.getPhysicalFile(datafile).toPath())){
MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_ONLY, start, end-start);

// *** No idea how to convert MappedByteBuffer into input stream ***
// InputStream is = (How do I get inputstream for byte 16 to 48 here?)

// the medhod I used earlier to decrypt the all file atonce, now somehow I need the inputstream of specific range
is = new FileEncryptionUtil().getCipherInputStream(is,
EncodeUtil.decodeSeedValue(encryptionKeyRef), AESCipher.DECRYPT_MODE);

// transfering decrypted input stream to servlet response
OutputStream outputStream = response.getOutputStream();
// *** now for chunk transfer, here I also need to
// skip 2 bytes at the start and 3 bytes from the end.
// How to do it? ***/
org.apache.commons.io.IOUtils.copy(is, outputStream)
}


I am missing few steps in the code given above. I know I could try to read byte by byte and the ignore 2byte from first and 3 byte from last. But I am not sure if it will be efficient enough. Moreover, the client could request a large chunk say from byte 18 to 2048 which would require to read and decrypt almost two gigabytes of data. I am afraid creating a large byte array will consume too much memory.


How can I efficiently do it without putting too much pressure on server processing or memory? Any ideas?


Aucun commentaire:

Enregistrer un commentaire