# Passwort in XML wegschreiben



## till123 (27. Aug 2008)

Hallo,

ich habe momentan ein kleines Problem.
Bis Dato habe ich PWs immer uncodiert in einer XML-Datei weggeschrieben.

Nun codiere ich das PW mittels RSA und das PW sieht dann wie folgt aus:
 <passWord>lI(sº%Ó‹ˆÊMäg∞Íÿ^&T±ÇΩ&ª&êúAÄP^îåBÑ’x›»¨∆Åv6d≤°±5¿˜πÙ°ØjO¨z»Ò&‘9Â§Qpÿ3áv◊2õn√¯B¶&ÀqÆzãwXóõ‡s–wz9°Å^Ìq¬Y≈BtóY+Âu[_|k</passWord>

Das Wegschreiben funktioniert also.

Wenn ich die XML-Datei nun einlesen möchte, dann bekomme ich folgenden Fehler:

[Fatal Error] :8:21: Character reference "&#xf" is an invalid XML character.
com.thoughtworks.xstream.io.StreamException:  : Character reference "&#xf" is an invalid XML character.
	at com.thoughtworks.xstream.io.xml.DomDriver.createReader(DomDriver.java:86)
	at com.thoughtworks.xstream.io.xml.DomDriver.createReader(DomDriver.java:66)
	at com.thoughtworks.xstream.XStream.fromXML(XStream.java:861)


Habt ihr eine Idee?

Danke.


----------



## Campino (27. Aug 2008)

Ich denke mal, RSA produziert irgendwo einen Wert, der vom XML- Reader als Steuerzeichen interpretiert wird, z.B. ein "<" oder ein ">".


----------



## till123 (27. Aug 2008)

Habe mal nachgeschaut und nichts entsprechendes gefunden.

Und müsste ich da nicht auch schon Probleme beim Wegschreiben bekommen?

NEU:
Habe doch ein & gefunden. Ist soweit ich weiss auch ein Steuerzeichen.

Wie kann ich das denn verhindern? Eine Idee?
(Ich müsste der Verschlüsselung eine Blacklist von Zeichen mitteilen, die sie nicht verwenden darf - aber wie?)

Hier mal die Verschlüsselung:

```
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.Cipher;

public class Crypt {

	private  String ALGORITHM = "RSA";
	PrivateKey privKey;
	PublicKey pubKey;
	
   public Crypt()
   {
	   try {
	   KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGORITHM);
       keyPairGen.initialize(1024); // 1024 maximale Schluesselbreite
       KeyPair keyPair = keyPairGen.generateKeyPair();
       this.privKey = keyPair.getPrivate();
       this.pubKey = keyPair.getPublic();
	   }
	   catch (Exception e) {
		   
	   }
	   
   }
	
   private byte[] encrypt(byte[] plain) throws Exception {
      Cipher cipher = Cipher.getInstance(ALGORITHM);
      cipher.init(Cipher.ENCRYPT_MODE, pubKey);
      // verschluesseln
      return cipher.doFinal(plain);
   }

   private byte[] decrypt(byte[] chiffr)
         throws Exception {
      Cipher cipher = Cipher.getInstance(ALGORITHM);
      cipher.init(Cipher.DECRYPT_MODE, privKey);
      // Entschlusseln
      return cipher.doFinal(chiffr);
   }
   
   public String encryptPassword(String decodedPassword)
   {
	   try {
		     // Es werden die Bytes vom Text benötigt
	         byte[] bytes = decodedPassword.getBytes();

	         byte[] encrypt = encrypt(bytes);
	         
	         return (new String(encrypt));
	         
	      } catch (Exception e) {
	         return null;
	      }
	   } 
   
   public String decodePassword(String encodedPassword)
   {
	   try {
		   

	         // Es werden die Bytes vom Text benötigt
	         byte[] bytes = encodedPassword.getBytes();

	         //byte[] encrypt = encrypt(bytes);
	         byte[] decrypt = decrypt(bytes);
	         
	         return (new String(decrypt));
	         
	      } catch (Exception e) {
	         return null;
	      }
	   } 
   
   }
```
Oder ich müsste den Key in einer anderen Datei speichern. Gibt es einen guten Ersatz?
(Ansonsten müsste ich die Datei über Java serialisieren lassen. Dann ist das PW auch nicht ersichtlich)[/code]


----------



## maki (27. Aug 2008)

CDATA


----------



## ign0rant (28. Aug 2008)

Base64


----------



## kleiner_held (28. Aug 2008)

Die Frage ist wie das XML geschrieben wird.
So ziemlich jedes XML Framework das ich kenne, maskiert die XML Steuerzeichen automatisch wenn man Methode wie element.setText(myText); verwendet. 
Wenn man natuerlich komplett per Hand schreibt, so ala fileWriter.write("<myTag>"+myText+"</myTag>"); dann kommt ein invalides XML Dokument raus.


----------



## Murray (29. Aug 2008)

Etwas ausführlicher:

Das Problem besteht darin, dass die verschlüsselten Daten keine *Text*daten sind, sondern *Binär*daten (eben ein Byte-Array). Wenn man die als *Text*daten interpretiert (was hier passiert, denn eine XML-Datei ist nun mal eine *Text*datei), dann muss das schiefgehen, weil das Byte-Array alle möglichen Zeichen enthalten kann - u.a.  auch solche, die in XML besondere Bedeutung haben.

Würde es jetzt darum gehen, lediglich die für das Parsen von Tags und Entities reservierten Zeichen <,>,& zu behandeln, dann würde eine CDATA-Section reichen (die ist gedacht dafür, *Text*abschnitte, die reservierte Zeichen enthalten, so in der XML-Datei zu verpacken, dass der Parser diesen Bereich später nicht weiter analysiert, sondern 1:1 im DOM belässt).

Mit beliebigen *Binär*daten (wie in diesem Fall) bleiben dann aber zwei Probleme:
1. Mit den hier verwendeten Konstrukten

```
return (new String(encrypt));
```
bzw.

```
return (new String(decrypt));
```
wird bei der Umwandlung von Binärdaten zu (Unicode-)Strings das Default-Encoding der Plattform verwendet. Wenn das Programm jetzt auf verschiedenen Rechnern bzw. VMs läuft, dann muss dieses Default-Encoding nicht notwendigerweise das gleiche sein, so dass u.U. das Ergebnis nicht der ursprüngliche String ist.

2. Die Binärdaten könnten - als Text interpretiert - durchaus die Sequenz "]]" enthalten - und die markiert das Ende einer CDATA-Section; damit wäre das XML wieder nicht mehr well-formed.

Deshalb wäre hier Base-64-Encoding die bessere Wahl: dabei spielt das Encoding keine Rolle mehr, und das Ergebnis enthält garantiert keine Sonderzeichen mehr, die in XML gesondert behandelt werden. Daher ist es auch nicht notwendig (allerdings auch nicht schädlich), die base-64-encodeten Daten nochmal in eine CDATA-Section zu verpacken.


----------



## till123 (29. Aug 2008)

Hättest du denn mal einen guten Link für die Base-64-Encoding unter Java?
(Am Besten mit einem Bsp.)

Super. Danke für eure Hilfe.


----------



## Murray (29. Aug 2008)

Da wird man wie so oft bei Apache fündig: commons-codec


----------



## Murray (29. Aug 2008)

Ach ja, das Beispiel (weder übersetzt noch getestet):


```
import org.apache.commons.codec.binary.Base64;

...

final String charset = "utf-8";
final String str = "abc123äöüÄÖÜß";

System.out.println( "data:    '" + str + "'");

byte[] rawBytes =  str.getBytes( charset);

Base64 b64 = new Base64();

byte encBytes =  b64.encode( str);

String encStr = new String( encBytes, charset); //--- da encBytes keine Sonderzeichen mehr enthält, 
                                                                //-- ist die Angabe des Charsets nicht unbedingt erforderlich


System.out.println( "encoded: '" + encStr + "'");

byte[] decBytes = b64.decode( encStr.getBytes( charset)); //--- oder einfacher; b64.decode( encBytes)

String decStr = new String( decBytes, charset); //--- hier ist das Charset notwendig

System.out.println( "decoded: '" + decStr + "'");
```

//EDIT: Typo


----------



## till123 (29. Aug 2008)

Hallo,

danke für eure Hilfe.

Ich habe mich an folgenden Link gehalten:
http://www.source-code.biz/snippets/java/2.htm

Somit sind all meine Fragen beantwortet.


Danke!


----------



## maki (29. Aug 2008)

commons-codec wäre besser gewesen


----------

