view 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 source


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;
    }
}