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