Mercurial > 510Connectbot
diff src/com/trilead/ssh2/crypto/cipher/CipherOutputStream.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/CipherOutputStream.java Thu May 22 10:41:19 2014 -0700 @@ -0,0 +1,126 @@ + +package com.trilead.ssh2.crypto.cipher; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * CipherOutputStream. + * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: CipherOutputStream.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ + */ +public class CipherOutputStream { + BlockCipher currentCipher; + OutputStream bo; + byte[] buffer; + byte[] enc; + int blockSize; + int pos; + + /* + * We cannot use java.io.BufferedOutputStream, since that is not available + * in J2ME. Everything could be improved here alot. + */ + + final int BUFF_SIZE = 2048; + byte[] out_buffer = new byte[BUFF_SIZE]; + int out_buffer_pos = 0; + + public CipherOutputStream(BlockCipher tc, OutputStream bo) { + this.bo = bo; + changeCipher(tc); + } + + private void internal_write(byte[] src, int off, int len) throws IOException { + while (len > 0) { + int space = BUFF_SIZE - out_buffer_pos; + int copy = (len > space) ? space : len; + System.arraycopy(src, off, out_buffer, out_buffer_pos, copy); + off += copy; + out_buffer_pos += copy; + len -= copy; + + if (out_buffer_pos >= BUFF_SIZE) { + bo.write(out_buffer, 0, BUFF_SIZE); + out_buffer_pos = 0; + } + } + } + + private void internal_write(int b) throws IOException { + out_buffer[out_buffer_pos++] = (byte) b; + + if (out_buffer_pos >= BUFF_SIZE) { + bo.write(out_buffer, 0, BUFF_SIZE); + out_buffer_pos = 0; + } + } + + public void flush() throws IOException { + if (pos != 0) + throw new IOException("FATAL: cannot flush since crypto buffer is not aligned."); + + if (out_buffer_pos > 0) { + bo.write(out_buffer, 0, out_buffer_pos); + out_buffer_pos = 0; + } + + bo.flush(); + } + + public void changeCipher(BlockCipher bc) { + this.currentCipher = bc; + blockSize = bc.getBlockSize(); + buffer = new byte[blockSize]; + enc = new byte[blockSize]; + pos = 0; + } + + private void writeBlock() throws IOException { + try { + currentCipher.transformBlock(buffer, 0, enc, 0); + } + catch (Exception e) { + throw(IOException) new IOException("Error while decrypting block.").initCause(e); + } + + internal_write(enc, 0, blockSize); + pos = 0; + } + + public void write(byte[] src, int off, int len) throws IOException { + while (len > 0) { + int avail = blockSize - pos; + int copy = Math.min(avail, len); + System.arraycopy(src, off, buffer, pos, copy); + pos += copy; + off += copy; + len -= copy; + + if (pos >= blockSize) + writeBlock(); + } + } + + public void write(int b) throws IOException { + buffer[pos++] = (byte) b; + + if (pos >= blockSize) + writeBlock(); + } + + public void writePlain(int b) throws IOException { + if (pos != 0) + throw new IOException("Cannot write plain since crypto buffer is not aligned."); + + internal_write(b); + } + + public void writePlain(byte[] b, int off, int len) throws IOException { + if (pos != 0) + throw new IOException("Cannot write plain since crypto buffer is not aligned."); + + internal_write(b, off, len); + } +}