1 /* 2 * Copyright (c) 2006-2011 Christian Plattner. All rights reserved. 3 * Please refer to the LICENSE.txt for licensing details. 4 */ 5 package ch.ethz.ssh2.crypto.cipher; 6 7 import java.io.IOException; 8 import java.io.OutputStream; 9 10 /** 11 * CipherOutputStream. 12 * 13 * @author Christian Plattner 14 * @version $Id: CipherOutputStream.java 11 2011-05-27 14:14:06Z dkocher (at) sudo.ch $ 15 */ 16 public class CipherOutputStream 17 { 18 BlockCipher currentCipher; 19 OutputStream bo; 20 byte[] buffer; 21 byte[] enc; 22 int blockSize; 23 int pos; 24 25 /* 26 * We cannot use java.io.BufferedOutputStream, since that is not available 27 * in J2ME. Everything could be improved here alot. 28 */ 29 30 private static final int BUFF_SIZE = 8192; 31 byte[] out_buffer = new byte[BUFF_SIZE]; 32 int out_buffer_pos = 0; 33 34 public CipherOutputStream(BlockCipher tc, OutputStream bo) 35 { 36 this.bo = bo; 37 changeCipher(tc); 38 } 39 40 private void internal_write(byte[] src, int off, int len) throws IOException 41 { 42 while (len > 0) 43 { 44 int space = BUFF_SIZE - out_buffer_pos; 45 int copy = (len > space) ? space : len; 46 47 System.arraycopy(src, off, out_buffer, out_buffer_pos, copy); 48 49 off += copy; 50 out_buffer_pos += copy; 51 len -= copy; 52 53 if (out_buffer_pos >= BUFF_SIZE) 54 { 55 bo.write(out_buffer, 0, BUFF_SIZE); 56 out_buffer_pos = 0; 57 } 58 } 59 } 60 61 private void internal_write(int b) throws IOException 62 { 63 out_buffer[out_buffer_pos++] = (byte) b; 64 if (out_buffer_pos >= BUFF_SIZE) 65 { 66 bo.write(out_buffer, 0, BUFF_SIZE); 67 out_buffer_pos = 0; 68 } 69 } 70 71 public void flush() throws IOException 72 { 73 if (pos != 0) 74 { 75 throw new IOException("FATAL: cannot flush since crypto buffer is not aligned."); 76 } 77 78 if (out_buffer_pos > 0) 79 { 80 bo.write(out_buffer, 0, out_buffer_pos); 81 out_buffer_pos = 0; 82 } 83 bo.flush(); 84 } 85 86 public void changeCipher(BlockCipher bc) 87 { 88 this.currentCipher = bc; 89 blockSize = bc.getBlockSize(); 90 buffer = new byte[blockSize]; 91 enc = new byte[blockSize]; 92 pos = 0; 93 } 94 95 private void writeBlock() throws IOException 96 { 97 try 98 { 99 currentCipher.transformBlock(buffer, 0, enc, 0); 100 } 101 catch (Exception e) 102 { 103 throw (IOException) new IOException("Error while decrypting block.").initCause(e); 104 } 105 106 internal_write(enc, 0, blockSize); 107 pos = 0; 108 } 109 110 public void write(byte[] src, int off, int len) throws IOException 111 { 112 while (len > 0) 113 { 114 int avail = blockSize - pos; 115 int copy = Math.min(avail, len); 116 117 System.arraycopy(src, off, buffer, pos, copy); 118 pos += copy; 119 off += copy; 120 len -= copy; 121 122 if (pos >= blockSize) 123 { 124 writeBlock(); 125 } 126 } 127 } 128 129 public void write(int b) throws IOException 130 { 131 buffer[pos++] = (byte) b; 132 if (pos >= blockSize) 133 { 134 writeBlock(); 135 } 136 } 137 138 public void writePlain(int b) throws IOException 139 { 140 if (pos != 0) 141 { 142 throw new IOException("Cannot write plain since crypto buffer is not aligned."); 143 } 144 internal_write(b); 145 } 146 147 public void writePlain(byte[] b, int off, int len) throws IOException 148 { 149 if (pos != 0) 150 { 151 throw new IOException("Cannot write plain since crypto buffer is not aligned."); 152 } 153 internal_write(b, off, len); 154 } 155 } 156