com.github.isaichkindanila.crypt.lib.stream.DecryptedInputStream Maven / Gradle / Ivy
Show all versions of crypt-lib Show documentation
package com.github.isaichkindanila.crypt.lib.stream;
import com.github.isaichkindanila.crypt.lib.cipher.StreamCipher;
import java.io.IOException;
import java.io.InputStream;
/**
* {@code InputStream} wrapper used to decrypt data as it's being read.
*
* @see EncryptedOutputStream
*/
public class DecryptedInputStream extends InputStream {
private final InputStream in;
private final StreamCipher cipher;
/**
* Creates new instance of {@code DecryptedInputStream}.
*
* {@code DecryptedInputStream} automatically detects which cipher was used to encrypt it.
*
* @param in wrapped {@code InputStream}
* @param password password to be used as cipher key
* @throws IOException if {@code IOException} occurs while stream header is being read
* @throws MalformedStreamHeaderException if stream header is malformed
* @throws UnsupportedCipherException if the stream was encrypted with cipher which is not supported by this version of Crypt Lib
* @throws IncorrectPasswordException if the stream was encrypted with different password
*/
public DecryptedInputStream(InputStream in, String password) throws IOException {
CryptStream stream = new CryptStream(in, null);
stream.checkStreamSignature();
byte[] key = stream.hash(password);
byte[] iv = stream.readIV();
this.cipher = stream.readCipher().newInstance(key, iv);
this.in = in;
byte[] passHash = stream.hash(key, iv);
byte[] streamPassHash = new byte[passHash.length];
if (this.read(streamPassHash) != streamPassHash.length) {
throw new IncorrectPasswordException();
}
for (int i = 0; i < passHash.length; i++) {
if (streamPassHash[i] != passHash[i]) {
throw new IncorrectPasswordException();
}
}
}
/**
* Reads and decrypts a byte from wrapped stream.
*
* @return decrypted byte from wrapped stream
* @throws IOException if IOException occurs
*/
@Override
public int read() throws IOException {
int c = in.read();
return c == -1 ? -1 : cipher.apply((byte) c) & 0xff;
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int result = in.read(b, off, len);
cipher.apply(b, off, result);
return result;
}
@Override
public void close() throws IOException {
in.close();
}
}