package com.emc.vipr.transform.encryption;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import com.emc.vipr.transform.util.CountingInputStream;
public class EncryptionInputFilter extends InputStream {
boolean closed = false;
byte[] digest = null;
private DigestInputStream digestStream;
private CountingInputStream counterStream;
private CipherInputStream cipherStream;
public EncryptionInputFilter(InputStream in, Cipher cipher, MessageDigest digest) {
// Construct the filter chain:
// user stream->CountingInputStream->
// DigestInputStream(optional)->CipherInputStream
counterStream = new CountingInputStream(in);
if(digest != null) {
digestStream = new DigestInputStream(counterStream, digest);
cipherStream = new CipherInputStream(digestStream, cipher);
} else {
cipherStream = new CipherInputStream(counterStream, cipher);
}
}
@Override
public int read() throws IOException {
return cipherStream.read();
}
@Override
public int read(byte[] b) throws IOException {
return cipherStream.read(b);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return cipherStream.read(b, off, len);
}
@Override
public void close() throws IOException {
if(closed) return;
closed = true;
cipherStream.close();
if(digestStream != null) {
// Get the digest. We can only do this once due to the way
// MessageDigest works.
digest = digestStream.getMessageDigest().digest();
}
}
@Override
public int available() throws IOException {
return cipherStream.available();
}
@Override
public long skip(long n) throws IOException {
return cipherStream.skip(n);
}
public byte[] getDigest() {
if(!closed) {
throw new IllegalStateException("Cannot get digest until stream is closed");
}
return digest;
}
public long getByteCount() {
return counterStream.getByteCount();
}
}