view app/src/main/java/ch/ethz/ssh2/crypto/cipher/CipherInputStream.java @ 438:d29cce60f393

migrate from Eclipse to Android Studio
author Carl Byington <carl@five-ten-sg.com>
date Thu, 03 Dec 2015 11:23:55 -0800
parents src/ch/ethz/ssh2/crypto/cipher/CipherInputStream.java@071eccdff8ea
children
line wrap: on
line source

/*
 * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
 * Please refer to the LICENSE.txt for licensing details.
 */
package ch.ethz.ssh2.crypto.cipher;

import java.io.IOException;
import java.io.InputStream;

/**
 * CipherInputStream.
 *
 * @author Christian Plattner
 * @version $Id: CipherInputStream.java 11 2011-05-27 14:14:06Z dkocher@sudo.ch $
 */
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.
     */

    private static final int BUFF_SIZE = 8192;
    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 = 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;
    }
}