/** * Create a new EncFSInputStream for reading decrypted data off a file on an EncFS volume * * @param volume Volume hosting the file to read * @param in Input stream to access the raw (encrypted) file contents * @param volumePath Volume path of the file being decrypted (needed for externalIVChaining) * @throws EncFSCorruptDataException File data is corrupt * @throws EncFSUnsupportedException Unsupported EncFS configuration * @throws IOException File provider returned I/O error */ public EncFSInputStream(EncFSVolume volume, InputStream in, String volumePath) throws EncFSCorruptDataException, EncFSUnsupportedException { super(in); this.volume = volume; this.config = volume.getConfig(); this.blockSize = config.getBlockSize(); this.numMACBytes = config.getBlockMACBytes(); this.numRandBytes = config.getBlockMACRandBytes(); this.blockHeaderSize = this.numMACBytes + this.numRandBytes; this.blockBuf = null; this.bufCursor = 0; this.blockNum = 0; if (config.isUniqueIV()) { // Compute file IV byte[] fileHeader = new byte[EncFSFile.HEADER_SIZE]; try { in.read(fileHeader); } catch (IOException e) { throw new EncFSCorruptDataException("Could't read file IV"); } byte[] initIv; if (config.isExternalIVChaining()) { /* * When using external IV chaining we compute initIv based on * the file path. */ initIv = EncFSCrypto.computeChainIv(volume, volumePath); } else { // When not using external IV chaining initIv is just zero's. initIv = new byte[8]; } try { this.fileIv = EncFSCrypto.streamDecode(volume, initIv, fileHeader); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { throw new EncFSCorruptDataException(e); } catch (BadPaddingException e) { throw new EncFSCorruptDataException(e); } } else { // No unique IV per file, just use 0 this.fileIv = new byte[EncFSFile.HEADER_SIZE]; } }