예제 #1
0
  /*
   * (non-Javadoc)
   *
   * @see java.io.FileInputStream#skip(long)
   */
  @Override
  public long skip(long n) throws IOException {
    long bytesSkipped = 0;
    int toSkip;
    int bytesRead;

    byte[] skipBuf = new byte[config.getBlockSize()];

    if (n < 0) {
      throw new IOException("Negative skip count");
    }

    while (bytesSkipped < n) {
      toSkip = (int) Math.min(n - bytesSkipped, config.getBlockSize());
      bytesRead = this.read(skipBuf, 0, toSkip);
      bytesSkipped += bytesRead;
      if (bytesRead == -1) {
        return -1; // Already at EOF
      } else if (bytesRead < toSkip) {
        return bytesSkipped; // Hit EOF now
      }
    }

    return bytesSkipped;
  }
예제 #2
0
  /**
   * 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];
    }
  }
예제 #3
0
  /*
   * Read one block (blockSize bytes) of data from the underlying
   * FileInputStream, decrypt it and store it in blockBuf for consumption via
   * read() methods
   */
  private int readBlock() throws IOException, EncFSCorruptDataException, EncFSUnsupportedException {
    byte[] cipherBuf = new byte[blockSize];
    boolean zeroBlock = false;

    int bytesRead = 0;
    int lastBytesRead = 0;

    // Read until we read a whole block or we reach the end of the input
    while (bytesRead < blockSize) {
      lastBytesRead = in.read(cipherBuf, bytesRead, blockSize - bytesRead);
      if (lastBytesRead > 0) {
        bytesRead += lastBytesRead;
      } else if (lastBytesRead < 0) {
        /*
         * If we read some bytes return that, if not then we're at the
         * end of the stream
         */
        if (bytesRead == 0) {
          bytesRead = -1;
        }
        break;
      }
    }

    if (bytesRead == blockSize) { // block decode
      /*
       * If file holes are allowed then we need to test whether the whole
       * block is made up of 0's. If not (which is going to be the case
       * for MAC header by default), we will do block decryption.
       */
      if (config.isHolesAllowed()) {
        zeroBlock = true;
        for (int i = 0; i < cipherBuf.length; i++)
          if (cipherBuf[i] != 0) {
            zeroBlock = false;
            break;
          }
      }

      try {
        if (zeroBlock == true) {
          blockBuf = cipherBuf;
        } else {
          blockBuf = EncFSCrypto.blockDecode(volume, getBlockIV(), cipherBuf);
        }
      } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
      } catch (IllegalBlockSizeException e) {
        throw new EncFSCorruptDataException(e);
      } catch (BadPaddingException e) {
        throw new EncFSCorruptDataException(e);
      }

      bufCursor = blockHeaderSize;
      blockNum++;
    } else if (bytesRead > 0) { // stream decode
      try {
        blockBuf = EncFSCrypto.streamDecode(volume, getBlockIV(), cipherBuf, 0, bytesRead);
      } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
      } catch (IllegalBlockSizeException e) {
        throw new EncFSCorruptDataException(e);
      } catch (BadPaddingException e) {
        throw new EncFSCorruptDataException(e);
      }
      bufCursor = blockHeaderSize;
      blockNum++;
    }

    // Verify the block header
    if ((bytesRead > 0) && (blockHeaderSize > 0) && (zeroBlock == false)) {
      byte mac[] = EncFSCrypto.mac64(volume.getMac(), blockBuf, numMACBytes);
      for (int i = 0; i < numMACBytes; i++) {
        if (mac[7 - i] != blockBuf[i]) {
          throw new EncFSCorruptDataException("Block MAC mismatch");
        }
      }
    }

    return bytesRead;
  }