aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/ch/ethz/ssh2/crypto/cipher/CipherInputStream.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/ch/ethz/ssh2/crypto/cipher/CipherInputStream.java')
-rw-r--r--src/main/java/ch/ethz/ssh2/crypto/cipher/CipherInputStream.java160
1 files changed, 160 insertions, 0 deletions
diff --git a/src/main/java/ch/ethz/ssh2/crypto/cipher/CipherInputStream.java b/src/main/java/ch/ethz/ssh2/crypto/cipher/CipherInputStream.java
new file mode 100644
index 0000000..d35c90d
--- /dev/null
+++ b/src/main/java/ch/ethz/ssh2/crypto/cipher/CipherInputStream.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
+ * Please refer to the LICENSE.txt for licensing details.
+ */
+package ch.ethz.ssh2.crypto.cipher;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * CipherInputStream.
+ *
+ * @author Christian Plattner
+ * @version $Id: CipherInputStream.java 11 2011-05-27 14:14:06Z dkocher@sudo.ch $
+ */
+public class CipherInputStream
+{
+ BlockCipher currentCipher;
+ InputStream bi;
+ byte[] buffer;
+ byte[] enc;
+ int blockSize;
+ int pos;
+
+ /*
+ * We cannot use java.io.BufferedInputStream, since that is not available in
+ * J2ME. Everything could be improved alot here.
+ */
+
+ private static final int BUFF_SIZE = 8192;
+ byte[] input_buffer = new byte[BUFF_SIZE];
+ int input_buffer_pos = 0;
+ int input_buffer_size = 0;
+
+ public CipherInputStream(BlockCipher tc, InputStream bi)
+ {
+ this.bi = bi;
+ changeCipher(tc);
+ }
+
+ private int fill_buffer() throws IOException
+ {
+ input_buffer_pos = 0;
+ input_buffer_size = 0;
+ input_buffer_size = bi.read(input_buffer, 0, BUFF_SIZE);
+ return input_buffer_size;
+ }
+
+ private int internal_read(byte[] b, int off, int len) throws IOException
+ {
+ if (input_buffer_size < 0)
+ {
+ return -1;
+ }
+
+ if (input_buffer_pos >= input_buffer_size)
+ {
+ if (fill_buffer() <= 0)
+ {
+ return -1;
+ }
+ }
+
+ int avail = input_buffer_size - input_buffer_pos;
+ int thiscopy = (len > avail) ? avail : len;
+
+ System.arraycopy(input_buffer, input_buffer_pos, b, off, thiscopy);
+ input_buffer_pos += thiscopy;
+
+ return thiscopy;
+ }
+
+ public void changeCipher(BlockCipher bc)
+ {
+ this.currentCipher = bc;
+ blockSize = bc.getBlockSize();
+ buffer = new byte[blockSize];
+ enc = new byte[blockSize];
+ pos = blockSize;
+ }
+
+ private void getBlock() throws IOException
+ {
+ int n = 0;
+ while (n < blockSize)
+ {
+ int len = internal_read(enc, n, blockSize - n);
+ if (len < 0)
+ {
+ throw new IOException("Cannot read full block, EOF reached.");
+ }
+ n += len;
+ }
+
+ try
+ {
+ currentCipher.transformBlock(enc, 0, buffer, 0);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Error while decrypting block.");
+ }
+ pos = 0;
+ }
+
+ public int read(byte[] dst) throws IOException
+ {
+ return read(dst, 0, dst.length);
+ }
+
+ public int read(byte[] dst, int off, int len) throws IOException
+ {
+ int count = 0;
+
+ while (len > 0)
+ {
+ if (pos >= blockSize)
+ {
+ getBlock();
+ }
+
+ int avail = blockSize - pos;
+ int copy = Math.min(avail, len);
+ System.arraycopy(buffer, pos, dst, off, copy);
+ pos += copy;
+ off += copy;
+ len -= copy;
+ count += copy;
+ }
+ return count;
+ }
+
+ public int read() throws IOException
+ {
+ if (pos >= blockSize)
+ {
+ getBlock();
+ }
+ return buffer[pos++] & 0xff;
+ }
+
+ public int readPlain(byte[] b, int off, int len) throws IOException
+ {
+ if (pos != blockSize)
+ {
+ throw new IOException("Cannot read plain since crypto buffer is not aligned.");
+ }
+ int n = 0;
+ while (n < len)
+ {
+ int cnt = internal_read(b, off + n, len - n);
+ if (cnt < 0)
+ {
+ throw new IOException("Cannot fill buffer, EOF reached.");
+ }
+ n += cnt;
+ }
+ return n;
+ }
+}