148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood/* 248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Copyright (c) 2006-2011 Christian Plattner. All rights reserved. 348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Please refer to the LICENSE.txt for licensing details. 448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodpackage ch.ethz.ssh2.crypto.cipher; 648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.IOException; 848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.InputStream; 948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 1048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood/** 1148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * CipherInputStream. 1248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * 1348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @author Christian Plattner 1448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @version $Id: CipherInputStream.java 11 2011-05-27 14:14:06Z dkocher@sudo.ch $ 1548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 1648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodpublic class CipherInputStream 1748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood{ 1848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood BlockCipher currentCipher; 1948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood InputStream bi; 2048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood byte[] buffer; 2148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood byte[] enc; 2248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int blockSize; 2348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int pos; 2448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 2548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* 2648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * We cannot use java.io.BufferedInputStream, since that is not available in 2748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * J2ME. Everything could be improved alot here. 2848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 2948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 3048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private static final int BUFF_SIZE = 8192; 3148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood byte[] input_buffer = new byte[BUFF_SIZE]; 3248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int input_buffer_pos = 0; 3348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int input_buffer_size = 0; 3448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 3548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public CipherInputStream(BlockCipher tc, InputStream bi) 3648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 3748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood this.bi = bi; 3848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood changeCipher(tc); 3948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 4048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 4148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private int fill_buffer() throws IOException 4248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 4348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood input_buffer_pos = 0; 4448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood input_buffer_size = 0; 4548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood input_buffer_size = bi.read(input_buffer, 0, BUFF_SIZE); 4648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return input_buffer_size; 4748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 4848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 4948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private int internal_read(byte[] b, int off, int len) throws IOException 5048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 5148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (input_buffer_size < 0) 5248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 5348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return -1; 5448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 5548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 5648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (input_buffer_pos >= input_buffer_size) 5748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 5848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (fill_buffer() <= 0) 5948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 6048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return -1; 6148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 6248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 6348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 6448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int avail = input_buffer_size - input_buffer_pos; 6548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int thiscopy = (len > avail) ? avail : len; 6648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 6748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood System.arraycopy(input_buffer, input_buffer_pos, b, off, thiscopy); 6848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood input_buffer_pos += thiscopy; 6948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 7048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return thiscopy; 7148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 7248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 7348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void changeCipher(BlockCipher bc) 7448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 7548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood this.currentCipher = bc; 7648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood blockSize = bc.getBlockSize(); 7748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood buffer = new byte[blockSize]; 7848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood enc = new byte[blockSize]; 7948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood pos = blockSize; 8048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 8148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 8248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private void getBlock() throws IOException 8348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 8448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int n = 0; 8548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood while (n < blockSize) 8648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 8748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int len = internal_read(enc, n, blockSize - n); 8848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (len < 0) 8948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 9048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("Cannot read full block, EOF reached."); 9148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 9248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood n += len; 9348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 9448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 9548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 9648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 9748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood currentCipher.transformBlock(enc, 0, buffer, 0); 9848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 9948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (Exception e) 10048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 10148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("Error while decrypting block."); 10248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 10348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood pos = 0; 10448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 10548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 10648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public int read(byte[] dst) throws IOException 10748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 10848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return read(dst, 0, dst.length); 10948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 11048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 11148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public int read(byte[] dst, int off, int len) throws IOException 11248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 11348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int count = 0; 11448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 11548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood while (len > 0) 11648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 11748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (pos >= blockSize) 11848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 11948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood getBlock(); 12048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 12148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 12248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int avail = blockSize - pos; 12348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int copy = Math.min(avail, len); 12448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood System.arraycopy(buffer, pos, dst, off, copy); 12548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood pos += copy; 12648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood off += copy; 12748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood len -= copy; 12848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood count += copy; 12948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 13048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return count; 13148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 13248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 13348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public int read() throws IOException 13448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 13548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (pos >= blockSize) 13648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 13748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood getBlock(); 13848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 13948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return buffer[pos++] & 0xff; 14048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 14148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 14248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public int readPlain(byte[] b, int off, int len) throws IOException 14348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 14448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (pos != blockSize) 14548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 14648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("Cannot read plain since crypto buffer is not aligned."); 14748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 14848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int n = 0; 14948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood while (n < len) 15048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 15148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int cnt = internal_read(b, off + n, len - n); 15248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (cnt < 0) 15348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 15448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("Cannot fill buffer, EOF reached."); 15548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 15648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood n += cnt; 15748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 15848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return n; 15948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 16048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood} 161