Array NullPointerException

Funk

Mitglied
Hey Jungs und Mädels,

ich bräuchte dringend Hilfe, da ich den RSA-Algorithmus für meine Facharbeit in Java implementieren muss und da die nächsten fertig sein muss 🙂

Folgender Quelltext:

Java:
import java.math.BigInteger;
import java.util.Random;

public class RSAAlgorithmus
{

    Random rng;
    BigInteger p;
    BigInteger q;
    BigInteger e;
    BigInteger n;
    String klartext;
  

  
    public RSAAlgorithmus()
    {
       rng = new Random();
    }

  
    public void gibSchluessel()
    {
       p = BigInteger.probablePrime (32, rng);
       rng.nextInt();      
       q = BigInteger.probablePrime (32, rng);
       n = p.multiply(q);
       BigInteger phi_n = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
       e = BigInteger.probablePrime (31, rng);
       while (phi_n.gcd(e).equals(BigInteger.ONE) == false)
       {
           e = BigInteger.probablePrime (31, rng);
       }
       BigInteger d = e.modInverse(phi_n);
       System.out.println(" n; " + n.toString() + " phi_n; " + phi_n.toString() + " e; " + e.toString() + " d; " + d.toString());
      
    }


    public void verschluesseln(String pKlartext)
    {
        klartext = pKlartext;
        char[] klartextArray = klartext.toCharArray();
        BigInteger[] codBuchstabenWertArray = new BigInteger[klartextArray.length];
        
        for(int i = 0; i < klartext.length(); i++)
        {
            BigInteger buchstabenWert = BigInteger.valueOf((int)klartextArray[i]); 
            codBuchstabenWertArray[i] = buchstabenWert.modPow(e,n); 
           
        }
        
    }

Ich habe zunächst die benötigten Schlüssel mit gibSchluessel generieren lassen und wollte dann mit der Methode verschluesseln() den eingegeben Klartext verschlüsseln. Wenn ich die Methode jetzt ausführe, kriege ich eine NullPointerException bei:

at java.math.BigInteger.modPow(BigInteger.java:1547)
at RSAAlgorithmus.verschluesseln(RSAAlgorithmus.java:56)

Ich weiß leider nicht, warum. Dachte erst, das Array würde für Zahlen im 32 Bit Bereich nicht reichen, aber auch wenn ich oben 4 Bit übergebe, klappt es trotzdem nicht.

Wäre euch echt dankbar, wenn wir das Problem schnell gelöst bekommen 🙂

Viele Grüße
 
Hey, am besten du gibst uns mal die Zeile RSAAlgorithmus.java:56. Du hast nicht die gesamte Klasse gepostet insofern können wir mit der Zeilenangabe nix anfangen.

edit 2: War doch Mist, moment lass mich mal den source code von BigInteger auschecken
 
Zuletzt bearbeitet:
Ok also der Code der zur NPE führt lautet:

Java:
m1 = m.shiftRight(p); // m/2**p

D.h. "m" ist null. Und m ist der zweite übergebene Parameter, in deinem Fall also die Instanz-Variable "n". Die ist null... Ich weiß jetzt nicht genau wofür diese ganzen Variablen in deiner Klasse stehen und was das sein soll. Du solltest dir sinnige Variablen-Namen einfallen lassen, nicht einfach nur irgendwelche Buchstaben, so versteht ja kein Mensch deinen Code 😉
 
Ach tut mir Leid, ich bin auch ein Honk. Bevor ich die verschluesseln() aufrufe, sollte ich natürlich vorher gibSchluessel() aufrufen, damit ich überhaupt erstmal ein n habe 😀


Aber vielleicht habe ich später noch fragen, könntet dann eventuell den Thread offen lassen 🙂
 
Ja du könntest darüber nachdenken die Methoden zusammenzuführen. Die gibSchluessel() Methode ist eh parameterlos, macht also wohl immer das selbe. Die beiden Methoden hängen doch zusammen oder nicht, beides zusammen ist doch erst der gesamte Verschlüsselungsvorgang.
Also pack das gleich alles in die verschluesseln Methode. Oder - falls du den Code getrennt halten willst - pack einen gibSchluessel()-Aufruf als erste Zeile in die verschluessle Methode und mach sie (die gibSchluessel) private! Oder falls du das auch nicht willst, prüfe wenigstens beim verschlüsseln ob die Werte null sind, und wenn ja, dann schmeiß ein:

Java:
throw new IllegalStateException("Verschlüsseln erst möglich nach gibSchluessel()-Aufruf") ;

rein, oder irgendwie so halt 😉
 
Das passt schon so, dass soll ja kein Programm sein für die Praxis, ich muss es einfach nur dokumentieren und dann geht das schon.

Aber eine andere Sache: Jetzt würd ich gern beim entschluesseln einen geheimtext in Zahlen, also meinetwegen entsprechen 909192 = 656667 (65=A, 66=B usw.), übergeben. Jedoch muss ich die Zahlenfolge wieder aufteilen, dachte dass ich das mit substring machen kann, aber irgendwie weiß ich nicht, wie ich das lösen soll.
 
Das passt schon so, dass soll ja kein Programm sein für die Praxis, ich muss es einfach nur dokumentieren und dann geht das schon.

Kein Programm wird für die Praxis sein, solange du nicht als angestellter Programmierer arbeitest. Das Problem ist dass du das nur dann werden kannst wenn du ordentlichen Code schreibst. Also gewöhn dir das an - der Code sollte immer sauber sein, nur ein gut gemeinter Ratschlag...

Jedoch muss ich die Zahlenfolge wieder aufteilen, dachte dass ich das mit substring machen kann, aber irgendwie weiß ich nicht, wie ich das lösen soll.
Welche Zahlenfolge? Du meinst das Array, dass die Verschlüsseln Methode erzeugt? (Btw nur lokal, das ist dir schon klar oder?) Wieso dann Aufteilen, das Array enthält doch die Zeichen getrennt durch die Fächer?
 
Nein nein, wenn ich die Methode entschluesseln(int geheimerText) habe und ich dann wie oben die Zahlen 909192, dann muss ich die in Zweierpäkchen aufteilen und dann am Besten in ein Array reinpacken.
 
Sorry, ich verstehe deinen Satz nicht. Du hast nach dem Verschlüsseln ein Array von Zahlen. Was willst du jetzt genau mit irgendeinem geheimen Text machen?
 
Ich ab zum einen die Methode verschluesseln und zum anderen entschluesseln. Beim verschluesseln habe ich Buchstaben (ABC) in ASCII umgewandelt (656667). Dann habe ich die Buchstaben einzeln (!), also zum Beispiel das A (65) zu 91. Die 91 wäre jetzt der verschlüsselte Buchstabe nur in Zahlenform.

Jetzt möchte ich aber bei der Methode entschluesseln einen bereits vorhandenen verschlüsselten Text in Zahlenform als Parameter übergeben und diese Zahlen dann wieder in die ASCII-Code Zahlen umwandeln. Da ich aber, wie gesagt, die Buchstaben jeweils einzeln ver- und entschluessele, muss ich also den übergegeben verschlüsselten Text in Pakete einteilen, die jeweils aus 2 Zahlen bestehen.
 
Achso ok. Naja natürlich muss man bei Verschlüsselung darauf achten eine Form zu bekommen die man auch wieder eindeutig entschlüsseln kann. Mit deinem Verschlüsselungs-Algorithmus geht das wohl nicht, da man nicht weiß ob 91 nun eine Zahl repräsentiert oder zwei (9 und 1). Ist die Frage welche Werte du überhaupt bekommen kannst, aber ich weiß jetzt nicht genau was für werte diese mod() Methode liefert. Du könntest jetzt beim Verschlüsseln noch ein Token zur Trennung einbauen, zB "-".

"91-55-13-1-99" oder sowas.

In der Entschlüsselungsmethode nutzt die dieses Token zum Aufteilen, und ja genau, dafür kann man split verwenden. Dann hast du ein Array bestehend aus "91" "55" "13" usw im obigen Beispiel. Dann noch die Strings in Zahlen umwandeln:

Java:
String[] split = text.split("-");
for(int i = 0; i<split.length; i++){
   int zahl = Integer.parseInt(split[i]);
}
 
Stimmt hast recht, daran habe ich noch gar nichts gedacht, dass es gar nicht eindeutig ist. Jetzt habe ich ein Problem. Gibt es da vielleicht eine Lösung ?
 
Achso, du hast was anderes gemeint. Ich meinte jedenfalls, dass wenn man einen geheimenText übergibt, meinetwegen 909192, dann ist ja nicht klar, welche Zahlen jetzt genau eine Zahl beschreiben. Beschreibt z.B. nur die erste 9 das A oder womöglich sogar die 909. Das war das was ich meinte.
 
Ja, schon klar. Aber du musst ja selber definieren wie ein Text aussehen muss damit du ihn nach deinem Algorithmus entschlüsseln kannst. D.h. wenn nicht klar ist was 909192 heißt, dann passt dein Algorithmus einfach nicht. Deshalb ja mein Vorschlag:

Baue "-" ein beim Verschlüsseln.
Und Entschlüsseln wird ja wohl einen Text erwarten, der deiner Verschlüsselung entspricht. Sonst passt beides ja gar nicht zusammen, du schreibst ja nicht eine Verschlüsselung x und dann eine Entschlüsselung für y 😉 Und dann kannst du halt nicht 909192 übergeben zum Entschlüsseln, weil das kein Text ist der deiner Verschlüsselung entspricht, so einfach.
 
Ok, dann belasse ich es dabei, dass ich den Teil den ich verschlüsselt habe, auch wieder entschlüssel.

Ich weiß nicht so recht, was du mit diesem Token, meinst, aber wenn ich es teste klappt alles soweit...
Das einzige Problem, das ich jetzt noch habe, ist, dass ich beim entschlüsseln den ganzen Kram vom codierten Array (codBuchstabenWertArray) in ein decodiertes Array packen möchte und die Werte widerum in ein Klartext Array und dieses Array dann ausgeben möchte. Habe bis jetzt folgenden Quellcode:

Java:
public void entschluesseln()
    {
       BigInteger[]decBuchstabenWertArray = new BigInteger[klartext.length()];
       for (int i = 0; i<klartext.length(); i++)
       {
           decBuchstabenWertArray[i] = codBuchstabenWertArray[i].modPow(d,n);
           klartextArray[i] = BigInteger.valueOf(decBuchstabenWertArray[i]); //Hier weiß ich nicht genau, wie das valueOf() genau auszusehen hat.
       }
    }
 
Ich pushe nochmal. Hab übrigens jetzt von meinem Lehrer einen Lösungsansatz bekommen. Soll eine eigene Zahlenzuweisung der Buchstaben machen, die eine maximale Länge an Zahlen hat. Also ein A wäre dann "001" . . . . Z "026". Nur bin ich mir jetzt unsicher, wie ich das umsetzen soll. Kann ich eine zweite Klasse erstellen, wo ich die Buchstaben dann einzeln einer Zahl zuweise und dann als Variable speicher und dann noch eine Methode schreibe, die dann den entsprechenden Buchstaben in die Zahl umgewandelt zurückgibt ?
 
Ich verstehe irgendwie nicht was für Probleme du damit hast 😉 Du stellst Fragen, deren Antworten du selbst definieren kannst. Du kannst einen String kodieren wie auch immer du lustig bist und genauso wieder dekodieren.

Kann ich eine zweite Klasse erstellen, wo ich die Buchstaben dann einzeln einer Zahl zuweise und dann als Variable speicher und dann noch eine Methode schreibe, die dann den entsprechenden Buchstaben in die Zahl umgewandelt zurückgibt ?

Logisch:

Java:
public class Mapping{

   private static final Map<String,String> map = new HashMap<String,String>();
   
   static{
           map.put("A", "001");
           map.put("B", "002");
           // usw
   }

   public static String convert(String letter){
          return map.get(letter);
   }
}
 
Naja mein Problem ist, dass ich sowas, wie du es gepostet hast, nicht kenne. Würds gern so übernehmen, aber ich muss es leider auch kommentieren danach 🙁
 
Was genau verstehst du daran nicht?

Es wird eine statische Variable vom Typ HashMap angelegt. HashMap ist eine Klasse, welche das (generische) Interface Map implementiert. Und eine Map ist eine Zuordnung zwischen Schlüssel und Wert. <String,String> heißt: Wir wählen für Schlüssel und Werte der Map den Datentyp String.
D.h. das ist dann eine Art Liste, in die wir Paare von <String-String> Zuordnungen reinlegen können.

static { ... }

ist ein statischer Initialisierungsblock, der automatisch ausgeführt wird, sobald die Klasse geladen wird, also zum ersten mal benutzt wird. (zB wenn du die Methode convert aufrufst).
Darin befüllen wir die Map mit den Buchstaben als Schlüssel und den Zahlen als Wert.

Die Methode convert holt sich dann für den jeweiligen Schlüssel (der buchstabe) die Zahl raus.
Natürlich ist die "Zahl" hier auch noch ein String - du kannst für die Werte auch den Datentyp Integer wählen:

Java:
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("A", 1);
 
Ok, hab mir paar Erklärungen angeguckt, scheint doch nicht so schwer zu sein. Aber wenn ich deinen Code jetzt 1:1 übernehme, kriege ich direkt hier
Java:
Map<String, Integer> map = new HashMap<String, Integer>();
den Fehler "type HashMap does not take parameters".
 
Das Problem hat sich gelöst, nun ist aber wieder das nächste dran ;(

Ab dem Buchstaben H=008 sagt er mir, dass die Integer-Zahl zu lang wäre.
 

Neue Themen


Zurück
Oben