Mercurial > 510Connectbot
diff src/com/trilead/ssh2/crypto/cipher/CipherInputStream.java @ 0:0ce5cc452d02
initial version
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 22 May 2014 10:41:19 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/trilead/ssh2/crypto/cipher/CipherInputStream.java Thu May 22 10:41:19 2014 -0700 @@ -0,0 +1,136 @@ + +package com.trilead.ssh2.crypto.cipher; + +import java.io.IOException; +import java.io.InputStream; + +/** + * CipherInputStream. + * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: CipherInputStream.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ + */ +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. + */ + + final int BUFF_SIZE = 2048; + 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 = 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; + } +}