PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Java zertifikat-konversion & Probleme



Smartie
17.08.2005, 16:49
Hey Leute,
ich hab eine Klasse, die mir einen Schlüsselpaar erstellt, und dieses wird erstmal in Name.priv/pub gespeichert. Danach hole ich es da raus, base64-encodiere es, entferne die newlines und speichere es in einer anderen datei. Wenn ich allerdings jetzt die newlines wieder einfuege, und es base64-decodiere, hab ich nicht die gleiche Bytekette, wie vorher. :(
Weiss einer, was an meinen convert_sig_byte und/oder convert_sig_String Methoden falsch ist?
convert_sig_byte codiert das byte array in einen base64 string und entfernt mittels PatternMatching alle \n.
und convert_sig_String macht das gleiche genau umgekehrt.




package de.freakbu.tool;

import java.io.*;
import java.security.*;
import java.security.spec.*;
import sun.misc.*;

public class sigtool {
public static void generate(String filename) {
try {
KeyPairGenerator keyGen = KeyPairGenerator
.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keyGen.initialize(1024, random);
byte seed[] = random.generateSeed(20);
random.setSeed(seed);
KeyPair pair = keyGen.generateKeyPair();
PrivateKey priv = pair.getPrivate();
PublicKey pub = pair.getPublic();
byte[] pubKey = pub.getEncoded();
FileOutputStream keyfos = new FileOutputStream(filename + ".pub");
keyfos.write(pubKey);
keyfos.close();
byte[] privKey = priv.getEncoded();
FileOutputStream keyfos2 = new FileOutputStream(filename + ".priv");
keyfos2.write(privKey);
keyfos2.close();
} catch (Exception e) {
System.err.println("Exception: " + e.toString());
System.exit(1);
}
}

public static boolean verify_msg(String txt, String pubkey, byte signature[]) {
boolean wahr = false;
try {
byte[] encKey = convert_sig_byte(pubkey);
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
KeyFactory keyFactory = KeyFactory.getInstance("DSA", "SUN");
PublicKey myPubKey = keyFactory.generatePublic(pubKeySpec);
Signature sigDecoded = Signature.getInstance("SHA1withDSA", "SUN");
sigDecoded.initVerify(myPubKey);
String sigToCompare = txt;
sigDecoded.update(sigToCompare.getBytes());
boolean ver = sigDecoded.verify(signature);
wahr = ver;
} catch (SignatureException g) {
System.err.println("Exception: " + g.toString());
System.exit(1);
} catch (InvalidKeyException f) {
System.err.println("Exception: " + f.toString());
System.exit(1);
} catch (NoSuchProviderException e) {
System.err.println("Exception: " + e.toString());
System.exit(1);
} catch (InvalidKeySpecException d) {
System.err.println("Exception: " + d.toString());
System.exit(1);
} catch (NoSuchAlgorithmException c) {
System.err.println("Exception: " + c.toString());
System.exit(1);
}
return wahr;
}

public static byte[] create_msg_sig(String message, String privkey) {
byte signature[] = null;
try {
byte[] encKey = convert_sig_byte(privkey);
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encKey);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PrivateKey myPrivKey = keyFactory.generatePrivate(privKeySpec);
Signature sig = Signature.getInstance("SHA1withDSA", "SUN");
sig.initSign(myPrivKey);
String sigString = message;
sig.update(sigString.getBytes());
signature = sig.sign();
} catch (SignatureException g) {
System.err.println("Exception: " + g.toString());
System.exit(1);
} catch (InvalidKeyException f) {
System.err.println("Exception: " + f.toString());
System.exit(1);
} catch (NoSuchProviderException e) {
System.err.println("Exception: " + e.toString());
System.exit(1);
} catch (InvalidKeySpecException d) {
System.err.println("Exception: " + d.toString());
System.exit(1);
} catch (NoSuchAlgorithmException c) {
System.err.println("Exception: " + c.toString());
System.exit(1);
}
return signature;
}

public static byte[] convert_sig_byte(String text) {
byte foo[] = null;
try {
String g = insertnewlines(text);
foo = new BASE64Decoder().decodeBuffer(text);
} catch (IOException a) {
System.err.println("error:" + a.toString());
System.exit(1);
}
return foo;
}

public static String convert_sig_String(byte text[]) {
String foo = null;

foo = new BASE64Encoder().encode(text);
Pattern p = Pattern.compile("\n");
Matcher m = p.matcher(foo);
String mungedString = m.replaceAll("");
return mungedString;
}

public static String insertnewlines(String text) {
String foo = null;
int ll = 76;
int newcounter = 0, zeichen = 0, mal = 0;
zeichen = text.length() - (text.length() % ll);
mal = (zeichen / ll);
zeichen = text.length() + mal;
char neuertext[] = new char[zeichen];
char altertext[] = text.toCharArray();
neuertext[0] = altertext[0];
for(int i = 1; i < text.length(); i++) {
if( (i % (ll-1)) == 0 ) {
neuertext[newcounter] = '\n';
newcounter++;
}
neuertext[newcounter] = altertext[i];
newcounter++;
}
foo = neuertext.toString();
return foo;
}

}


Da sowas durchaus interessant ist, hab ich mal noch create_msg und verify_msg dabei gelassen. fuer mein problem sind allerdings nur die convert* methoden relevant.

Ich hoff mal mir kann einer helfen :(

Smartie
17.08.2005, 18:31
Da mir gesagt wurde, dass das ganze doch zu gross und umstaendlich sei, bevor man mir helfen wolle, will ich das ganze hier genauer darlegen :-)

Mit diesem Sourcecode:


public static String convert_sig_String(byte text[]) {
String foo = null;

foo = new BASE64Encoder().encode(text);
Pattern p = Pattern.compile("\n");
Matcher m = p.matcher(foo);
String mungedString = m.replaceAll("");
return mungedString;
}

Nehme ich einen beliebigen ByteBlock, codiere ihn mit Base64, und loesche alle '\n', also den Zeilenneuanfang aus dem erzeugten Base64-String.
So weit, so gut.
Jetzt habe ich folgende Operation, die in den String diese newlines wieder einfuegt, und von dem Base64-format wieder in den byteblock konvertiert


public static String insertnewlines(String text) {
String foo = null;
int ll = 76;
int newcounter = 0, zeichen = 0, mal = 0;
zeichen = text.length() - (text.length() % ll);
mal = (zeichen / ll);
zeichen = text.length() + mal;
char neuertext[] = new char[zeichen];
char altertext[] = text.toCharArray();
neuertext[0] = altertext[0];
for(int i = 1; i < text.length(); i++) {
if( (i % (ll-1)) == 0 ) {
neuertext[newcounter] = '\n';
newcounter++;
}
neuertext[newcounter] = altertext[i];
newcounter++;
}
foo = neuertext.toString();
return foo;
}
}
public static byte[] convert_sig_byte(String text) {
byte foo[] = null;
try {
String g = insertnewlines(text);
foo = new BASE64Decoder().decodeBuffer(text);
} catch (IOException a) {
System.err.println("error:" + a.toString());
System.exit(1);
}
return foo;
}

Da der Base64-Decoder nicht fehlerhaft sein wird, schaetze ich stark, dass meine newlineinsert funktion fehlerhaft ist, aber ich komm nicht drauf, was nicht stimmt
Nach 76 Zeichen des Strings soll ein '\n' eingefuegt werden. und das wars auch schon. aber irgendwie gehts nicht.

Ich hoffe, es ist nun etwas klarer. Ich bin mit meinem latein am Ende ..

nait
17.08.2005, 19:13
Sieht doch eigentlich ganz gut aus, hast du mal ein System.Out.println("newline") oder so was in die if-Abfrage gesetzt?
Einfach um zu sehen ob es eingefügt wird. Falls es eingefügt wird, kann es sein, dass ein '\n' (warum auch immer) nicht als Newline erkannt wird?
So wie hier:
http://www.leepoint.net/notes-java/GUI/components/40textarea/40newline.html

kuchen
18.08.2005, 00:46
Seh ich das richtig, dass newcounter beim ersten Durchlauf der Schleife auf 0 gesetzt ist, die Schleife selbst aber bei Zeichen 1 beginnt? Damit überschreibst du das erste Zeichen (warum auch immer du das in einer extra Zeile machst, starte den 'Schleifenzähler' doch einfach bei 0 und verzichte auf die Zeile darüber).

Guts nächtle.

nait
18.08.2005, 00:51
Gutes Auge hast du da. ;-)
Der Index 0 kann aber nicht mit in die Schleife weil dann in der if-Abfrage true rauskommt und ein newline eingefügt wird.

DarkTom
18.08.2005, 03:28
Das geht schon beim Entfernen schief. Ich kann nicht genau sagen, woran es liegt. Erstens hast du wohl statt "\n" eher "\\n" gemeint. Erinnere dich an die Regeln für Escape-Sequenzen in Java.
Leider hilft das auch nicht weiter. Es bleibt weiterhin ein CR/LF bestehen, nichts wird ersetzt. Anscheinend nehmen line terminators in den RegEx noch eine Sonderstellung ein. Was funktioniert ist ein Match auf Whitespace-Characters: "\p{javaWhitespace}" bzw. korrekt escaped "\\p{javaWhitespace}".

Was mir noch ins Auge gesprungen ist, ist, dass du zwar deine insertnewlines(...) aufrufst, dann aber den ursprünglichen String dekodierst. Das solltest du noch ändern.

Desweiteren hat ein char[]-Array keine toString()-Methode, die den Inhalt ausgibt. Du solltest du am Ende deiner insertnewlines stattdessen schreiben
foo = new String(neuertext);Ansonsten bekommst du nur etwas wie [C@address (Typ Char-Array und Adresse im Speicher)

Ausserdem musst du in der Methode die Variable newcounter mit 1 statt mit 0 initialisieren. Ach, und in der if-Bedingung in der Schleife ist das -1 zu viel:
if( (i % (ll)) == 0 ) {

Abschliessend sei noch gesagt, dass die Geschichte mit dem Wiedereinfügen der Zeilenumbrüche doch eigentlich unnötig ist. Der Decoder vermisst die nicht. :p

kuchen
18.08.2005, 08:06
Der Index 0 kann aber nicht mit in die Schleife weil dann in der if-Abfrage true rauskommt und ein newline eingefügt wird.
Omg klar, 0 % n == 0.. Hab ich im Eifer des Gefechts ganz übersehen.

Ach, und in der if-Bedingung in der Schleife ist das -1 zu viel
Sowas, schon wieder ein Fehler übersehen beim Modulo. Ich habs (leider) mit Mathe fast so wenig wie mit Java. :) .oO(wie unkool..)
Hätt' glaub ich rein gefühlsmäßig dasselbe wie Deknos gemacht, sehr seltsam (vlcht. wg. nullbasiertem Index?). Aber wenn mans mal genauer betrachtet ist das schon quark.. geht hierbei ja nicht um das letzte Zeichen der Zeile.


d f g d f g [..] f g h \n
0 1 2 3 4 5 [..] 73 74 75 76

Ach, und in deiner Korrektur sind die Klammern zuv^Wunnötig. ;p
Nja, genau genommen sind sie imho schon in der Ursprungsfassung unnötig, außer Java braucht das tatsächlich so.
Aber um noch was einigermaßen sinnvolles beizutragen ein Vorschlag für die Schleife:


for(int i=1, int nlcount=0; i<text.length(); i++)
{
if(i % ll == 0)
{
neuertext[i+nlcount] = '\n'; // oder halt \\n laut darktom
nlcount++;
}
neuertext[i+nlcount] = altertext[i];
}



Der Decoder vermisst die nicht. :p
bwahaha. xD

Smartie
18.08.2005, 11:33
Was ich mittlerweile auch herausgefunden habe(hab die erwaehnten fehler gestern noch selbst gefunden)(trotzdem nochmal danke :-) ), dass wenn ich einen beliebigen Bytestring erst encodiere, und dann gleich wieder decodiere, dass dann nicht das gleiche rauskommt, was rein kam -.-

DarkTom
18.08.2005, 11:50
Ach, und in deiner Korrektur sind die Klammern zuv^Wunnötig. ;pNochmal bitte. Was meinst du damit? Welche Klammern?

neuertext[i+nlcount] = '\n'; // oder halt \\n laut darktomNein, da nicht. Das '\n' ist da vollkommen richtig. Nur in dem regex soll stehen "\n" und dazu musst du den Backslash escapen, weil das sonst zu einem Zeichen wird.
Was ich mittlerweile auch herausgefunden habe(hab die erwaehnten fehler gestern noch selbst gefunden)(trotzdem nochmal danke :-) ), dass wenn ich einen beliebigen Bytestring erst encodiere, und dann gleich wieder decodiere, dass dann nicht das gleiche rauskommt, was rein kam -.- :confused:
Also, ich habe das bei mir hier ausprobiert, funktioniert tadellos.

Waah, muss los, ich häng die Datei mal so an.

Smartie
18.08.2005, 13:09
Bei "Pattern p = Pattern.compile("\\p{javaWhitespace}");" gibt mir eclipse folgende Meldung aus:


Exception in thread "main" java.util.regex.PatternSyntaxException: Unknown character category {javaWhitespace} near index 17
\p{javaWhitespace}
^
at java.util.regex.Pattern.error(Pattern.java:1528)
at java.util.regex.Pattern.familyError(Pattern.java:2 209)
at java.util.regex.Pattern.retrieveCategoryNode(Patte rn.java:2200)
at java.util.regex.Pattern.family(Pattern.java:2172)
at java.util.regex.Pattern.sequence(Pattern.java:1598 )
at java.util.regex.Pattern.expr(Pattern.java:1545)
at java.util.regex.Pattern.compile(Pattern.java:1279)
at java.util.regex.Pattern.<init>(Pattern.java:1035)
at java.util.regex.Pattern.compile(Pattern.java:779)
at de.freakbu.tool.sigtool.convert_sig_String(sigtool .java:141)
at de.freakbu.tool.mainclass.main(mainclass.java:33)


BTW: Wenn ich den standardmaessigen Decoder BASE64Encoder/Decoder einsetze kommt bei diesem inhalt der funktion try_pack(...)


try {
String codiert = new BASE64Encoder().encode(foo);
String murks = codiert;
byte rat[] = new BASE64Decoder().decodeBuffer(murks);
if(rat.equals(foo)) {
System.out.println("funktioniert");
} else {
System.out.println("scheisse");
}
} catch(Exception e) {
System.err.println("try_pack exception" + e.toString());
}

immer "scheisse" raus. also, kann der en/decoder nicht funktionieren.
egal, was die byte eingabe ist. :(
hab ich jetzt ein brett vorm kopf, oder ist die software buggy?

kuchen
18.08.2005, 14:04
Nochmal bitte. Was meinst du damit? Welche Klammern?
Ist nicht wichtig; meinte nur, die Klammern (Klammer auf, Klammer zu ( '(', ')' ) halt) sind nicht unbedingt nötig - bei beiden Fassungen.
Also if( (i % (ll-1)) == 0 ) könnte man zu if(i % ll == 0) verkürzen.


Nein, da nicht. Das '\n' ist da vollkommen richtig. Nur in dem regex [...]
Ahjo ok. Hatte das nur überflogen und mir die erste lange Fassung garnicht angeschaut - garnicht gecheckt dass hier irgendwo Regex ebnutzt werden. ;)


Deknos; laut "Java ist auch eine Insel (http://www.galileocomputing.de/openbook/javainsel4/javainsel_04_003.htm#Rxx365java04003040001431F04A1 09)" ist da irgendwas suspektes an sun.misc.BASE64*.. vielleicht stimmt damit wirklich was nicht ebi dir?
Wie gesagt, kein Peil von Java -> reine Vermutung.

Smartie
18.08.2005, 14:59
NARF.
Arrays vergleicht man mit Arrays.equals(array1,array2); aus java.util.*;
mit arrayinst.equals wird hoechstens die instanz oder referenz verglichen.
kann man sich eigentlich denken. Der base64 en/decoder aus sun.misc.*
funktioniert bei mir jetzt.

DarkTom
18.08.2005, 23:58
Das \p{javaWhitespace} scheint in 1.5 neu zu sein. Zumindest, wenn man die Dokumentation zu der Klasse Pattern vergleicht.