# ObjectInputStream mit CypherInputStream hängt



## klaina (8. Okt 2008)

Moin,

Glaube ich bin ein wenig zu Blöd. Mein Ziel ist es, vom Server den Öffentlichen Schlüssel mit einem ObjectInputStream zu empfangen. Das klappt so weit. Jetzt soll aber über die selbe Socketverbindung nach empfang des Schlüssels der Datenaustausch verschlüsselt ablaufen. Mein Ansatz war folgender:



```
ObjectInputStream oisUnsecure = new ObjectInputStream(this.s.getInputStream());
            PublicKey key = (PublicKey)oisUnsecure.readObject();
            
            
            System.out.println("blub");
            
            Cipher cin = Cipher.getInstance("RSA");
            cin.init(Cipher.DECRYPT_MODE, this.key);
            System.out.println("blub");
            ObjectInputStream ois = new ObjectInputStream(new CipherInputStream(oisUnsecure,cin));
```

Bei der letzten Zeile hängt das Programm. Probiere jetzt schon seit Stunden rum und habe nicht brauchbares an Informationen bekommen warum das nicht funktioniert.

Wär für schnelle Hilfe dankbar.


----------



## SlaterB (9. Okt 2008)

ich weiß in diesem Fall nicht genau wie es richtig geht, aber zwei Dinge scheinen mir ganz falsch:

1.
zwei Arten von Datenmengen in einem Stream, erst der key und danach noch mehr Daten, wie schreibst du die auf dem Server?
in den gleichen ObjectOutpustream verschlüsselt (wie sollte das gehen?) oder mit einem neuen ObjectOutpustream,
dann musst du das beim Client auch entsprechend auslesen,

2.
der CipherInputStream kann garantiert nicht von einem ObjectInputStream lesen, der ObjectInputStream leitet die bytes nicht einfach so weiter als wäre nix

ich empfehle:
auf dem Server hast du zwei Stream, den für den Key und den anderen,
die schreiben jeweils in einen ByteArrayOutputStream, dann hast du am Ende zwei byte[],
die schickst du über den Socket-Stream, irgendwie getrennt, oder am Anfang in den ersten 4 Bytes steht die Länge des ersten Arrays oder ähnliches,
(*)

Ziel: beim Client hast du dann am Ende auch die beiden byte[] vorliegen,
aus den beiden Arrays erstellst du mit ByteArrayInputStream +evtl. CipherInputStream +  ObjectInputStream die ois, aus denen du die Objekte lesen kannst,

wichtig: keine ObjectInputStream/ ObjectOutputStream direkt auf die Socketverbindung,
aber wie gesagt nur meine Meinung, um mit den begrenzten Mitteln umzugehen,

-----

(*)
wenn du nur genau die beiden fertigen byte[]-Arrays übertragen willst, ginge das für sich sogar vielleicht auch mit ObjectStreams, 
aber nur genau EINER, der zwei einfache byte[] überträgt und sonst nix,

nicht mehrere ObjectStream da reinbauen, zwischendurch verschlüsseln und wer weiß was noch alles


----------



## kaina (9. Okt 2008)

Da ein ObjectInputStream auch ein InputStream ist müsste ich eigentlich auch dem CipherInputStream den ObjectInputStream geben können. 

Auf der Serverseite funktioniert es analog dazu mit nem ObjectOutputStream. Ich erstelle nen Schlüssel den ich erst über nen Unverschlüsselten ObjectOutputStream schicke (dieser kommt beim client auch korrekt an) und dann jage ich den in nen CipherOutputStream (welcher wiederum in nen neuen OutputStream kommt). Über den will ich dann Objekte verschlüsselt zum client (bzw später auch anders rum) schicken. 
Die Serverseite hängt beim erstellen des zweiten ObjectOutputStreams nicht. Es wird sogar ein Objekt gesendet (Zum testen nocheinmal den PublicKey). 

Das das Prinzip funktionieren müsste zeigt die Tatsache, dass das senden auch funktioniert. 

Nur Die Clientseite hängt an der Stelle. Genau das selbe passiert auch wenn ich dem CipherInputStream direkt den InputStream meines Sockets gebe. 

Das mit den Beiden Streams auf dem Server habe ich nicht ganz verstanden. Letzten endes geht doch beides durch den Stream des Sockets. Ich will den "unverschlüsselten" Stream nur so lange nutzen wie ich den Schlüssel noch nicht übertragen habe. Die einfachste Möglichkeit wär wohl dem Cipher objekt irgendwie zu sagen das er nicht entschlüsseln bzw verschlüsseln soll. Dann könnte ich das nach der ersten Übertragung umstellen. Aber das ist meines wissens ja nicht möglich.


----------



## klaina (9. Okt 2008)

Nach einigem Herumsuchen habe ich herausgefunden, dass der Konstruktor des ObjectInputStreams so lange blockt wie der ObjectOutputStream auf der anderen seite noch nicht initialisiert wurde (Schreibt wohl nen Header in den Socket) 
Die Server Seite sieht zum testen so aus:



```
Cipher c = Cipher.getInstance("RSA");
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(512);
            KeyPair kp = kpg.genKeyPair();
           
            PublicKey puk = kp.getPublic();
            PrivateKey  prk = kp.getPrivate();
            
            c.init(Cipher.DECRYPT_MODE, prk);
            
            //Hier sende ich den PublicKey zum Client
            ServerSocket ss = new ServerSocket(1254);
            Socket s = ss.accept();
            ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
            oos.writeObject(puk);
            oos.flush();
            
            // Hier sende ich ihn nocheinmal, aber verschlüsselt
            oos = new ObjectOutputStream(new CipherOutputStream(oos,c));
            oos.writeObject(puk);
            oos.flush();
```

Bevor die Frage kommt warum ich den Schlüssel zwei mal sende. Es lässt mich später beim Client überprüfen ob das ver und Entschlüsseln fehlerfrei geklappt hat indem ich beide Schlüssel vergleiche.


----------



## SlaterB (9. Okt 2008)

> Da ein ObjectInputStream auch ein InputStream ist müsste ich eigentlich auch dem CipherInputStream den ObjectInputStream geben können. 


hier ein Testprogramm:


```
public class Test
{
    public static void main(String[] args)
        throws Exception
    {
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream o = new ObjectOutputStream(bo);
        o.writeObject("Test");
        o.close();
        byte[] a = bo.toByteArray();
        System.out.println("a: " + a.length);
        ByteArrayInputStream bi = new ByteArrayInputStream(a);
        System.out.println("erstes Byte: " + bi.read()+", available: "+bi.available());

        ObjectInputStream oi = new ObjectInputStream(new ByteArrayInputStream(a));
        System.out.println("erstes Byte: " + oi.read()+", available: "+oi.available());
    }
}

Ausgabe
a: 11
erstes Byte: 172, available: 10
erstes Byte: -1, available: 0
```

> Das das Prinzip funktionieren müsste zeigt die Tatsache, dass das senden auch funktioniert. 

klar funktioniert der erste Stream, was am Ende für bytes stehen ist dafür doch erstmal irrelevant,
aber der zweite nicht (unbedingt), wie kann das Einlesen der ersten Objekts das beweisen?

> Die Serverseite hängt beim erstellen des zweiten ObjectOutputStreams nicht.

warum auch, durcheinander schreiben ist leichter als aus einem Durcheinander irgendwas sinnvolles zu lesen


----------



## klaina (9. Okt 2008)

Danke habs nur verstanden. Auch das mit den byteArray. Jetzt nur noch eine frage. Wie schicke ich am besten ein byteArray durch nen Socket und verhindere das der Client ein byteArray ausliest das noch nicht alle Elemente enthält?

Meine Lösung sieht jetzt so aus das ich die Objekte erst in ein byteArray schreibe und dann entweder unverschlüsselt (den Schlüssel) oder halt mit cipher.doFinal() verschlüsselt sende. 

Ich könnte natürlich jetzt wieder nen normalen ObjectOutputStream nehmen um das byteArray mit writeObject() zu senden, aber das würde ja bedeuten das ich das Objekt jeweils 2 mal serialisiere und 2 mal deserialisiere. Für die Performance dürfte das wohl tötlich sein.


----------



## SlaterB (9. Okt 2008)

über Performance darf man wohl nicht reden, 
wenns nach Performance geht, dann geht wohl nur deine allererste Variante,
und dann musst du auf ClientSeite mühsam das Ende des ersten ObjectStreams herausfinden 
und dafür sorgen, dass exakt ab dem nächsten Byte alles beim zweiten Stream landet,
weiß nicht genau, ob das automatisch passiert, vielleicht ja schon nachdem du nun ein Problem beseitigt hast


die beiden byte[] zu versenden wäre mittel-performant und mittel-schwer auseinanderzuhalten

am besten 'wieder nen normalen ObjectOutputStream', gut zu handeln, und vielleicht auch nicht wirklich langsamer, 
ein byte[] muss ja beim Versenden zumindest nicht groß umkodiert werden, 
auf Client-Seite werden byte[]-Objecte erstellt, in der mittleren Variante aber auch


----------



## klaina (9. Okt 2008)

Gut. hab das jetzt so gelöst das ich das ganze dann wieder mit nem ObjectOutputStream durchs Netzwerk schicke. Ist  am einfachsten zu handhaben. Falls es irgendwann wirklich mal probleme mit der Performance geben sollte muss ich es halt irgendwie anders lösen. Dank OOP ist ja alles irgendwie austauschbar.

Danke für die Hilfe


----------

