Auf Thema antworten

Vielen Dank für den Link und den Hinweis. Wie Tröööt  gesagt hat arbeitet Cipher mir Blöcken. Z.b. Bei DES mit 8-Byte Blöcken. Die Blockgröße kann man einfach mit der Methode cipher.getBlockSize() nachschauen. Ich hätte dann gedacht, dass, wenn 8-Byte geschrieben werden, diese auch losgeschickt werden. Klappt aber erst nach 16-Byte. Warum hab ich nicht herausgefunden. Also wenn 16-Byte geschrieben werden, werden die 1. 8-Byte losgeschickt.


Dann hab ich mir den Quellcode der Cipherstreams angeschaut und nachgeguckt, warum das so ist. Mir ist aufgefallen das diese auf dem Cipher-Objeckt mit cipher.update() arbeiten. Um Daten zu verschlüsseln, die nicht diese vorgeschriebene Blockgöße erreichen, muss cipher.dofinal() aufgerufen werden. Das tun diese Standard-Cipherstreams z.B. bei stream.close().


Ich habe jetzt den Quellcode angepasst. Wird auf dem Stream stream.flush()

aufgerufen, wird ein cipher.dofinal() ausgelöst.


Das geht aber nur auf Umwegen. Der Empfänger muss wissen, ob die Daten in ein einfaches cipher.update() geschrieben werden oder in ein cipher.dofinal().


Ich habe das so lösen können, dass es so eine Art Header gibt. Da steht drin, ob der Empfänger ein cipher.update() oder ein cipher.dofinal() aufrufen soll.


Des weiteren wird eine Art Datenlängenfeld, die angibt wie lang die nächsten Nutzdaten sind, mit geschickt, da sonst ab und zu diese update/dofinal Feld als Nutzdaten gesehen wird und dann abgeschmiert.


Auf Grund deiner Hilfe (danke nochmal Trööt ;-) ) Poste ich jetzt meine Lösung wie ich sie nutze. Mit ein Paar wichtigen Hinweisen:

1) Ich kann nicht versprechen, dass das Fehlerfrei funktioniert. Für mein Anwendungsbereich scheint es zu funktionieren.

2) Und der viel wichtigere Punkt, der den Sicherheitsaspekt betrifft, ist dass dieses update/dofinal Flag sowie dieses Datenlängenfeld in Klartext übermitteltet werden.


Bauchschmerzen macht mir vor allem Punkt 2. Über Feedback würde ich mich sehr freuen.


So genug gelabter hier der Quellcode:


Inputstream:

[code=Java]

package codemaker.stream;


import java.io.FilterInputStream;

import java.io.IOException;

import java.io.InputStream;


import javax.crypto.BadPaddingException;

import javax.crypto.Cipher;

import javax.crypto.IllegalBlockSizeException;

import javax.crypto.NullCipher;


public class OCipherInputStream extends FilterInputStream {


    private Cipher cipher;

    private InputStream input;

    private byte[] ibuffer = new byte[512];

    private boolean done = false;

    private byte[] obuffer;

    private int ostart = 0;

    private int ofinish = 0;


    private boolean deb = false;

    private void println(String line) {


        if (deb) {

            System.out.println(line);

        }

    }

   

    private int getMoreData() throws IOException {

        if (done)

            return -1;


        int dofinal = input.read();

        println("IN_FINAL>" + dofinal);

        int dataLength=input.read();


        int readin = input.read(ibuffer,0,dataLength);

        println("IN_REDED>" + readin);

        for (int i = 0; i < ibuffer.length; i++) {

            if (ibuffer[i] != 0)

                println("IN_DATA>" + ibuffer[i]);

        }

       


        if (readin == -1) {

            done = true;

            try {

                obuffer = cipher.doFinal();

            } catch (IllegalBlockSizeException e) {

                obuffer = null;

            } catch (BadPaddingException e) {

                obuffer = null;

            }

            if (obuffer == null)

                return -1;

            else {

                ostart = 0;

                ofinish = obuffer.length;

                return ofinish;

            }

        }


        if (dofinal == 1) {

            try {

                obuffer = cipher.doFinal(ibuffer, 0, readin);

            } catch (Exception e) {

                throw new IOException(e.getMessage());

            }

        } else {

            try {

                obuffer = cipher.update(ibuffer, 0, readin);

            } catch (IllegalStateException e) {

                obuffer = null;

            }

        }


        ostart = 0;

        if (obuffer == null)

            ofinish = 0;

        else

            ofinish = obuffer.length;


        return ofinish;

    }


    public OCipherInputStream(InputStream is, Cipher c) {

        super(is);

        input = is;

        cipher = c;

    }


    protected OCipherInputStream(InputStream is) {

        super(is);

        input = is;

        cipher = new NullCipher();

    }


    public int read() throws IOException {

        if (ostart >= ofinish) {

            // we loop for new data as the spec says we are blocking

            int i = 0;

            while (i == 0)

                i = getMoreData();


            if (i == -1)

                return -1;

        }

        return ((int) obuffer[ostart++] & 0xff);


    }


    public int intread(byte b[]) throws IOException {

        return read(b, 0, b.length);

    }


    public int read(byte b[], int off, int len) throws IOException {

        if (ostart >= ofinish) {

            // we loop for new data as the spec says we are blocking

            int i = 0;

            while (i == 0)

                i = getMoreData();


            if (i == -1)

                return -1;

        }


        if (len <= 0) {

            return 0;

        }


        int available = ofinish - ostart;


        if (len < available)

            available = len;


        if (b != null) {

            System.arraycopy(obuffer, ostart, b, off, available);

        }


        ostart = ostart + available;

        return available;

    }


    public long skip(long n) throws IOException {

        int available = ofinish - ostart;

        if (n > available) {

            n = available;

        }


        if (n < 0) {

            return 0;

        }


        ostart += n;

        return n;


    }


    public int available() throws IOException {

        return (ofinish - ostart);

    }


    public void close() throws IOException {

        input.close();

        try {

            // throw away the unprocessed data

            cipher.doFinal();

        } catch (BadPaddingException ex) {

        }


        catch (IllegalBlockSizeException ex) {

        }


        ostart = 0;

        ofinish = 0;

    }


    public boolean markSupported() {

        return false;

    }

}

[/code]


Outputstream:

[code=Java]

import java.io.FilterOutputStream;

import java.io.IOException;

import java.io.OutputStream;


import javax.crypto.BadPaddingException;

import javax.crypto.Cipher;

import javax.crypto.IllegalBlockSizeException;

import javax.crypto.NullCipher;


public class OCipherOutputStream extends FilterOutputStream {

    private Cipher cipher;

    private OutputStream output;

    private byte[] ibuffer = new byte[1];

    private byte[] obuffer;


    private boolean deb = false;


    private void println(String line) {

        if (deb) {

            System.out.println(line);

        }

    }


    public OCipherOutputStream(OutputStream os, Cipher c) {

        super(os);

        output = os;

        cipher = c;

    }


    protected OCipherOutputStream(OutputStream os) {

        super(os);

        output = os;

        cipher = new NullCipher();

    }


    private void personalWrite(byte[] arr, boolean dofinal) throws IOException {

        if (arr.length == 0)

            return;


        println("OUT_DOFINAL>" + (dofinal ? "1" : "0"));

        println("OUT_WRITED>" + arr.length);

        for (int i = 0; i < arr.length; i++) {

            println("OUT_DATA>" + arr[i]);

        }


        if (dofinal)

            output.write(1);

        else

            output.write(0);

        output.write(arr.length);

        output.write(arr);

    }


    public void write(int b) throws IOException {

        ibuffer[0] = (byte) b;

        obuffer = cipher.update(ibuffer, 0, 1);


        if (obuffer != null) {

            personalWrite(obuffer, false);

            obuffer = null;

        }

    }


    public void write(byte b[]) throws IOException {

        write(b, 0, b.length);

    }


    public void write(byte b[], int off, int len) throws IOException {

        obuffer = cipher.update(b, off, len);


        if (obuffer != null) {

            personalWrite(obuffer, false);

            obuffer = null;

        }

    }


    public void flush() throws IOException {


        try {

            obuffer = cipher.doFinal();

        } catch (IllegalBlockSizeException e) {

            obuffer = null;

        } catch (BadPaddingException e) {

            obuffer = null;

        }


        if (obuffer != null) {

            personalWrite(obuffer, true);

            obuffer = null;

        }

        output.flush();

    }


    public void close() throws IOException {

        try {

            flush();

        } catch (IOException ignored) {

        }

        out.close();

    }


}


[/code]



Oben