@Override @SuppressForbidden("just delegating") public int available() { return ccis.available(); }
private int read(byte[] b, int off, int len, boolean readPlain) throws IOException { int total = 0; if (remainingBytes() <= 0) { return -1; final int chunkMask = getChunkMask(); while (len > 0) { if (!chunkIsValid) { try { nextChunk(); chunkIsValid = true; } catch (GeneralSecurityException e) { int avail = remainingBytes(); if (avail == 0) { return total;
/** * @return the absolute position in the stream */ public long getPosition() { return ccis.getPos(); }
@Override public long skip(final long n) { long start = pos; long skip = Math.min(remainingBytes(), n); if ((((pos + skip) ^ start) & ~getChunkMask()) != 0) { chunkIsValid = false; } pos += skip; return skip; }
private void nextChunk() throws GeneralSecurityException, IOException { if (chunkSize != -1) { int index = (int)(pos >> chunkBits); initCipherForBlock(cipher, index); if (lastIndex != index) { long skipN = (index - lastIndex) << chunkBits; if (super.skip(skipN) < skipN) { throw new EOFException("buffer underrun"); } } lastIndex = index + 1; } final int todo = (int)Math.min(size, chunk.length); int readBytes, totalBytes = 0; do { readBytes = super.read(plain, totalBytes, todo-totalBytes); totalBytes += Math.max(0, readBytes); } while (readBytes != -1 && totalBytes < todo); if (readBytes == -1 && pos+totalBytes < size && size < Integer.MAX_VALUE) { throw new EOFException("buffer underrun"); } System.arraycopy(plain, 0, chunk, 0, totalBytes); invokeCipher(totalBytes, totalBytes == chunkSize); }
@Override public int read() throws IOException { byte[] b = { 0 }; // FIXME: compare against -1 or 1? (bug 59893) return (read(b) == 1) ? -1 : b[0]; }
protected abstract Cipher initCipherForBlock(Cipher existing, int block) throws GeneralSecurityException;
@Override public void readFully(byte[] buf, int off, int len) { if (shouldSkipEncryptionOnCurrentRecord) { readPlain(buf, off, buf.length); } else { ccis.readFully(buf, off, len); } }
@Override public int readInt() { if (shouldSkipEncryptionOnCurrentRecord) { readPlain(buffer, 0, LittleEndianConsts.INT_SIZE); return LittleEndian.getInt(buffer); } else { return ccis.readInt(); } }
@Override public byte readByte() { if (shouldSkipEncryptionOnCurrentRecord) { readPlain(buffer, 0, LittleEndianConsts.BYTE_SIZE); return buffer[0]; } else { return ccis.readByte(); } }
@Override public long skip(final long n) { long start = pos; long skip = Math.min(remainingBytes(), n); if ((((pos + skip) ^ start) & ~getChunkMask()) != 0) { chunkIsValid = false; } pos += skip; return skip; }
private void nextChunk() throws GeneralSecurityException, IOException { if (chunkSize != -1) { int index = (int)(pos >> chunkBits); initCipherForBlock(cipher, index); if (lastIndex != index) { long skipN = (index - lastIndex) << chunkBits; if (super.skip(skipN) < skipN) { throw new EOFException("buffer underrun"); } } lastIndex = index + 1; } final int todo = (int)Math.min(size, chunk.length); int readBytes, totalBytes = 0; do { readBytes = super.read(plain, totalBytes, todo-totalBytes); totalBytes += Math.max(0, readBytes); } while (readBytes != -1 && totalBytes < todo); if (readBytes == -1 && pos+totalBytes < size && size < Integer.MAX_VALUE) { throw new EOFException("buffer underrun"); } System.arraycopy(plain, 0, chunk, 0, totalBytes); invokeCipher(totalBytes, totalBytes == chunkSize); }
@Override public int read(byte[] b, int off, int len) throws IOException { return read(b, off, len, false); }
public ChunkedCipherInputStream(InputStream stream, long size, int chunkSize, int initialPos) throws GeneralSecurityException { super(stream); this.size = size; this.pos = initialPos; this.chunkSize = chunkSize; int cs = chunkSize == -1 ? 4096 : chunkSize; this.chunk = IOUtils.safelyAllocate(cs, MAX_RECORD_LENGTH); this.plain = IOUtils.safelyAllocate(cs, MAX_RECORD_LENGTH); this.chunkBits = Integer.bitCount(chunk.length-1); this.lastIndex = (int)(pos >> chunkBits); this.cipher = initCipherForBlock(null, lastIndex); }
public Biff8DecryptingStream(InputStream in, int initialOffset, EncryptionInfo info) throws RecordFormatException { try { byte initialBuf[] = IOUtils.safelyAllocate(initialOffset, MAX_RECORD_LENGTH); InputStream stream; if (initialOffset == 0) { stream = in; } else { stream = new PushbackInputStream(in, initialOffset); ((PushbackInputStream)stream).unread(initialBuf); } Decryptor dec = info.getDecryptor(); dec.setChunkSize(RC4_REKEYING_INTERVAL); ccis = (ChunkedCipherInputStream)dec.getDataStream(stream, Integer.MAX_VALUE, 0); if (initialOffset > 0) { ccis.readFully(initialBuf); } } catch (Exception e) { throw new RecordFormatException(e); } }
@Override public int readInt() { if (shouldSkipEncryptionOnCurrentRecord) { readPlain(buffer, 0, LittleEndianConsts.INT_SIZE); return LittleEndian.getInt(buffer); } else { return ccis.readInt(); } }
@Override public byte readByte() { if (shouldSkipEncryptionOnCurrentRecord) { readPlain(buffer, 0, LittleEndianConsts.BYTE_SIZE); return buffer[0]; } else { return ccis.readByte(); } }
private int read(byte[] b, int off, int len, boolean readPlain) throws IOException { int total = 0; if (remainingBytes() <= 0) { return -1; final int chunkMask = getChunkMask(); while (len > 0) { if (!chunkIsValid) { try { nextChunk(); chunkIsValid = true; } catch (GeneralSecurityException e) { int avail = remainingBytes(); if (avail == 0) { return total;
/** * Used when BIFF header fields (sid, size) are being read. The internal * {@link Cipher} instance must step even when unencrypted bytes are read * */ @Override public void readPlain(byte b[], int off, int len) { if (len <= 0) { return; } try { int readBytes, total = 0; do { readBytes = read(b, off, len, true); total += Math.max(0, readBytes); } while (readBytes > -1 && total < len); if (total < len) { throw new EOFException("buffer underrun"); } } catch (IOException e) { // need to wrap checked exception, because of LittleEndianInput interface :( throw new RuntimeException(e); } }
protected abstract Cipher initCipherForBlock(Cipher existing, int block) throws GeneralSecurityException;