RSA encrypt / decrypt

Lord_Aratorn

Aktives Mitglied
Ich habe folgenden Code geschrieben. Die jeweilige funktion soll entweder das übergebene byte[] verschlüsseln oder entschlüsseln. Wenn ich jedoch nun versuche eine Nachricht mit eine länge von 157 byte zu verschlüsseln resultiert dies in ein 256byte langes Array. Soll dieses nun abschließend wieder entschlüsselt werden, wird eine "javax.crypto.BadPaddingException: Message is larger than modulus" geworfen mit der ich nichts anfangen kann. Ich habe selbst nach mehrmaligem suchen keinen Fehler entdecken können. Darum möchte ich hier fragen, ob ich etwas übersehen habe.

Java:
public byte[] encryptRSA(Key publickey, byte[] data) {
		try {
			final int blocksize = Setup.ENCRYPTION_RSA_KEY_SIZE / 8 - 11; //Setup.ENCRYPTION_RSA_KEY_SIZE = 2048
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			for (int i = 0; i < data.length; i = i + blocksize) {
				byte[] tmp = new byte[blocksize];

				if (tmp.length < data.length - i) {
					System.arraycopy(data, i, tmp, 0, tmp.length);
				} else {
					for (int j = 0; j < data.length - i; j++) {
						tmp[j] = data[i + j];
					}
				}
				Cipher cipher = Cipher
						.getInstance(Setup.ENCRYPTION_KEY_ALGORITHEM); //Setup.ENCRYPTION_KEY_ALGORITHEM = "RSA"
				cipher.init(Cipher.ENCRYPT_MODE, publickey);
				tmp = cipher.doFinal(tmp);
				bos.write(tmp);
			}

			return bos.toByteArray();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
[/Java]
[Java]
	
	public byte[] decryptRSA(Key privateKey, byte[] encrypted) {
		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			final int blocksize = Setup.ENCRYPTION_RSA_KEY_SIZE / 8;  //Setup.ENCRYPTION_RSA_KEY_SIZE = 2048
			for (int i = 0; i < encrypted.length; i = i + blocksize) {
				byte[] tmp = new byte[blocksize];
				System.arraycopy(encrypted, i, tmp, 0, blocksize);
				Cipher cipher = Cipher
						.getInstance(Setup.ENCRYPTION_KEY_ALGORITHEM);  //Setup.ENCRYPTION_KEY_ALGORITHEM = "RSA"
				cipher.init(Cipher.DECRYPT_MODE, privateKey);
				tmp = cipher.doFinal(tmp);
				bos.write(tmp);
			}
			return bos.toByteArray();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
 

kay73

Bekanntes Mitglied
Du kannst nicht einfach an der blocksize herumrechnen und einen wahrscheinlichen 11 bit Overhead abziehen, auch wenn man das in anderen Foren liest. RSA benötigt halt ein Padding-Schema und die Chiffre ist bei einem 2048-Bit Schlüssel eben 256 byte lang und nicht 245. Die Implementierung verlangt eben nach dem gesamten verschlüsselten Block. Mach' Dir das Leben leicht und lass' einfach Java das Ganze machen. Ist auch weniger Code.

Java:
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Logger;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class RSADemo {

    private static final Logger logger = Logger.getLogger(RSADemo.class.getSimpleName());

    public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        
        final KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(2048);
        
        final KeyPair kp = kpg.generateKeyPair();        
        logger.info("Generated keypair...");
        
        final Cipher cipher = Cipher.getInstance("RSA");        
        cipher.init(Cipher.ENCRYPT_MODE, kp.getPublic());
        
        final String plaintext = "HelloWorld";
        
        final byte [] encrypted = cipher.doFinal(plaintext.getBytes());
        logger.info("Encrypted plaintext, "+encrypted.length+" byte.");
        
        cipher.init(Cipher.DECRYPT_MODE, kp.getPrivate());
        final byte [] decrypted = cipher.doFinal(encrypted);
        
        logger.info("Decrypted "+decrypted.length+" byte.");
        
        final String plaintext2 = new String(decrypted);
        logger.info("Decryption "+(plaintext2.equals(plaintext) ? "ok" : "not ok!"));
    }
}
 
Zuletzt bearbeitet:

Lord_Aratorn

Aktives Mitglied
Ich habe vor, Daten zu verschlüsseln, die länger sind als der RSA-Schlüssel. Daher erstelle ich mir die Blöcke und entschlüssel sie einzeln
 

kay73

Bekanntes Mitglied
Und wo ist das Problem?

P.s.: RSA ist teuer. Ueblicherweise nimmt man fuer grosse Daten eine Blockchiffre wie AES oder Blowfish mit zufaelligem Schluessel und verschluesselt diesen Schluessel mit RSA um ihn sicher zu tauschen.
 
Zuletzt bearbeitet:
G

<GUEST>SPiKEe

Gast
es ist schon möglich mit RSA daten zu verschlüsseln die länger als die BLOCK-size sind *PKCS1Padding*
jedoch gestaltet sich das entschlüsseln meist etwas schwierig
wie bereits gesagt : in der regel verwendet man hybrid-systeme

die verschlüsselung selbst wird mit einem symetrischen verfahren *meist AES* realiesiert
um jetzt aber sicher die beiden secrets der symetrischen verschlüsselung *KEY und IV *bei BlockChiffren** sicher zu übertragen werden nur diese in RSA verpackt und dann damit gesichert
grund dafür liegt darin das bei einem AES-128 sowohl der IV als auch der KEY der blocklänge von RSA-1024 entsprechen womit sich weder ver- noch entschlüsselungs-probleme ergeben

desssweiteren würde ich dir auch *aus eigener erfahrung* von "Sun" als crypto-provider abraten ... nimm hier lieber BouncyCastle ... nicht nur das dieser provider deutlich höhere crypto-stärken erlaubt *der standard SUN-provider ist laut aussage von Sun wegen export-richtlinien eingeschränkt* sondern auch fertige voll-implementierte klassen bereitstellt mit denen das ganze was du sonst selbst in zig zeilen code implementieren müsstest mit weniger als 10 zeilen umsetzbar ist ...
 

Lord_Aratorn

Aktives Mitglied
So, ich muss nochmal den Thread aus den Tiefen des Forums holen.

Ich habe immer noch das selbe Problem. Das da heißt Daten mit RSA verschlüsseln, die länger sind als die zugelassenen Daten.

Es sollen nämlich wieder ein RSA-Schlüssel mit RSA verschlüsselt und über eine Netzwerkanbindung verschickt werden. (Stichwort: Zertifizierung)

Natürlich ist der serialisierte RSA-Schlüssel länger als die zulässige Läge der Daten zum verschlüsseln. [Exkurs: Da ich einen 2048byte großen RSA-Schlüssel benutze, kann dieser nur maximal 256 Byte verschlüsseln (Der zu verschlüsselnde Schlüssel ist aber wiederum serialisiert 551 Byte lang.]
Java:
public static void main(String[] args) throws Exception {
		Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
		int keySize = 2048;
		
		KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
		SecureRandom random = new SecureRandom();
		generator.initialize(keySize, random);
		KeyPair pair = generator.generateKeyPair();
		Key pubKey = pair.getPublic();
		Key privKey = pair.getPrivate();

		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream oos;
		oos = new ObjectOutputStream(bos);
		oos.writeObject(pubKey);
	    byte[] input = bos.toByteArray();
	    
	    Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", "BC");


	    cipher.init(Cipher.ENCRYPT_MODE, pubKey, random);
	    byte[] cipherText = cipher.doFinal(input);
	    System.out.println("cipher: " + new String(cipherText));

	    cipher.init(Cipher.DECRYPT_MODE, privKey);
	    byte[] plainText = cipher.doFinal(cipherText);
	    System.out.println("plain : " + new String(plainText));
	  }

liefert
Java:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block
	at org.bouncycastle.jce.provider.JCERSACipher.engineDoFinal(Unknown Source)
	at javax.crypto.Cipher.doFinal(Cipher.java:1813)
	at test.RSACryptTest.main(RSACryptTest.java:77)
Die Frage ist nun, wie realisiere ich dies möglichst geschickt, ohne dass ich mich lange in Bibliotheken oder Frameworks einlesen muss?

P.S.Das was SPiKEe geschrieben hat, hört sich sehr interessant an, jedoch find ich die Seite mehr als unübersichtlich und bin ehrlich gesagt ein wenig überfordert, sowohl bei der Frage, welches das richtige Pakte ist, wie auch wie ich es anschließend benutze. Trotzdem danke SPiKEe.
 
Zuletzt bearbeitet:
D

despikyxd

Gast
RSA Signature Generation : RSA algorithmSecurityJava Tutorial
das scheint ganz gut auszusehen ...
habe ihn umgeschrieben auf RSA 2048 mit SHA512 ... und das OHNE mir mal eben BouncyCastle geladen zu haben ... sondern nur der standard SUN-provider

Java:
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;

public class MainClass
{
	public static void main(String[] args) throws Exception
	{
		//Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

		KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
		//mit BC : KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "BC");

		keyGen.initialize(2048, new SecureRandom());

		KeyPair keyPair = keyGen.generateKeyPair();
		Signature signature = Signature.getInstance("SHA512withRSA");
		//mit BC : Signature signature = Signature.getInstance("SHA512withRSA", "BC");

		signature.initSign(keyPair.getPrivate(), new SecureRandom());

		byte[] message = "abc".getBytes();
		//das String.getBytes() durch PublicKey.getEncoded ersetzen
		signature.update(message);

		byte[] sigBytes = signature.sign();
		signature.initVerify(keyPair.getPublic());
		signature.update(message);
		System.out.println(signature.verify(sigBytes));
	}
}

da musst du dann halt noch den RSA-key übergeben den du signieren willst ...
also java hat genug mittel ... da musst du nichts selbst implementieren =)
 

Lord_Aratorn

Aktives Mitglied
danke despikyxd, doch möchte ich nicht 3byte encrypten sondern eine Nachricht, die länger ist als der RSA Schlüssel selbst!

Möglichkeit A: Ich könnte ja dafür die Nachricht in Blöcke aufteilen, jeden Block verschlüsseln die ersten 4 Byte in der Übertragung für die Größe eines Blockes reservieren, die jeweilige Länge eines Blockes anschließend hineinschreiben. Und nach dem Empfangen jeweils die Längen auslesen, entschlüsseln, und am ende wieder zusammen setzen.
Doch dieses ist sehr kompliziert, da ich nicht weiß wie viel Byte ich mit dem Schlüssel maximal verschlüsseln kann und ich die Schlüssellänge dynamisch erzeugen will.
 
Zuletzt bearbeitet:
D

despikyxd

Gast
ich glaube du hast meine comments nich ganz verstanden ...
ich habe jetzt mal dieses beispiel mit einem RSA-PUBLIC-KEY gemacht ...
dessen länge sind 294 BYTE also 2352 BIT ... die schlüssellänge von RSA-2048 ist aber nur 256 BYTE lang ... also die angegebenen 2048 BIT
zeigt also das Signature überlange input-arrays automatisch irgendwie in blöcke unterteilt ... es ist also einfach möglich zum beispiel einen RSA-PUBLIC-KEY zu signieren *halt in dem mit nem zweiten key-pair signiert wird* ... oder bestimmt entsprechend andere daten
selbst ein 16kByte großes array *also 16384Byte = 131072 Bit* ist mit Signature kein problem ... du siehst also das das notwendige splitting in blöcke von Signature selbst übernommen wird ... du brauchst da nichts weiter drumrum basteln
 

Jatoll

Bekanntes Mitglied
Du kannst nicht einfach an der blocksize herumrechnen und einen wahrscheinlichen 11 bit Overhead abziehen, auch wenn man das in anderen Foren liest. RSA benötigt halt ein Padding-Schema und die Chiffre ist bei einem 2048-Bit Schlüssel eben 256 byte lang und nicht 245. Die Implementierung verlangt eben nach dem gesamten verschlüsselten Block. Mach' Dir das Leben leicht und lass' einfach Java das Ganze machen. Ist auch weniger Code.

Java:
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Logger;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class RSADemo {

    private static final Logger logger = Logger.getLogger(RSADemo.class.getSimpleName());

    public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        
        final KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(2048);
        
        final KeyPair kp = kpg.generateKeyPair();        
        logger.info("Generated keypair...");
        
        final Cipher cipher = Cipher.getInstance("RSA");        
        cipher.init(Cipher.ENCRYPT_MODE, kp.getPublic());
        
        final String plaintext = "HelloWorld";
        
        final byte [] encrypted = cipher.doFinal(plaintext.getBytes());
        logger.info("Encrypted plaintext, "+encrypted.length+" byte.");
        
        cipher.init(Cipher.DECRYPT_MODE, kp.getPrivate());
        final byte [] decrypted = cipher.doFinal(encrypted);
        
        logger.info("Decrypted "+decrypted.length+" byte.");
        
        final String plaintext2 = new String(decrypted);
        logger.info("Decryption "+(plaintext2.equals(plaintext) ? "ok" : "not ok!"));
    }
}

Hallo, ich schreibe gerade einen eigenen kleinen Messenger/chatroom (hauptsächlich zum üben) und wüsste gern ob und wie ich das verwenden kann um die verbindung zwischen client und Server zu verschlüsseln?
 

Lord_Aratorn

Aktives Mitglied
Hallo, ich schreibe gerade einen eigenen kleinen Messenger/chatroom (hauptsächlich zum üben) und wüsste gern ob und wie ich das verwenden kann um die verbindung zwischen client und Server zu verschlüsseln?
Hey Jatoll,
du könntest es, wie schon gesagt wurde verwenden um mittels einem asymmetrischen verfahren (bsp. RSA) einen symmetrischen Schlüssel(bsp. AES) zu verschlüsseln. Diesen dann zu übertragen und anschließend für deine Verbindung zu nutzen indem du jede Nachricht mit diesem Schlüssel verschlüsselst. Der Vorteil ist, dass ein symmetrisches Verfahren sehr viel zeit in Anspruch nimmt, und du mittels dem Misch sowohl die Sicherheit eines asymmetrischen Verfahrens hast als auch die Geschwindigkeit eines Symmetrischen.

Ich würde dir empfehlen dich in entsprechende Literatur einzulesen, da meine Erklärung auch nur sehr kurz gehalten wurde. Für den Anfang reicht da Wikipedia.


Kommen wir zurück zu meinem Problem.

Ich glaube wir reden an einander vorbei :)
Ich möchte gerne zum Signieren und zum Verschlüsseln die selbe Funktion nutzen, denn die Verfahren unterscheiden sich ja nur von dem übergebenen Schlüssel.

Also formuliere ich die Problemstellung anders. Ich möchte Daten mit RSA verschlüsseln, die länger sind als die zulässige Länge der Daten, die man mit dem gewählten Schlüssel verschlüsseln darf.
 
Zuletzt bearbeitet:

Jatoll

Bekanntes Mitglied
@Lord_Aratorn
ich weiß nur leider nicht wie das geht... also der datenaustausch passiert über einen InputStreamReader... und ich versteh diesen vorgang nicht so ganz ... könntest du mir das kurz erklären (bitte in einfacher sprache :D )
 

Lord_Aratorn

Aktives Mitglied
Ich könnte dir meine Klasse schicken.

Die kann Schlüssel erstellen, byte[] verschlüsseln:byte[] und byte[] entschlüsseln:byte[]
Doch wie gesagt, ist die maximale Länge der zu verschlüsselnden Daten stets abhängig von der Schlüssellänge.
 

Jatoll

Bekanntes Mitglied
Ich könnte dir meine Klasse schicken.

Die kann Schlüssel erstellen, byte[] verschlüsseln:byte[] und byte[] entschlüsseln:byte[]
Doch wie gesagt, ist die maximale Länge der zu verschlüsselnden Daten stets abhängig von der Schlüssellänge.

macht
Java:
final KeyPair kp = kpg.generateKeyPair();
das denn nicht schon?

also versteh mich nicht falsch... ich weiß ja grundsätzlich wie RSA funktioniert ... nur krieg ich in meinem kopf die brücke zwischen meinen 2 gedankengängen nicht hin...
also auf der einen seite einen chat mit verschlüsselterverbindung und passwort und auf der anderen seite RSA... ich hab halt noch nie gemacht und steh gerade ein bisschen aufm schlauch
 
Zuletzt bearbeitet:

Lord_Aratorn

Aktives Mitglied
Das ist eigentlich gar nicht so schwer. Du hast deinen Chatserver. Bei dem muss sich der Client erstmal unverschlüsselt anmelden.
Ich schreib dir mal die Schritte auf:

1) Server wartet auf Anmeldung
2) Client meldet sich mit Hello-Paket an
3) Server generiert RSA-Schlüsselpaar
4) Server speichert sich den Privaten Schlüssel (ich habe ihn in einer Datei auf einem Remote-Laufwerk gespeichert, oder du machst ihn grundsätzlich final) für jeden Client
5) Der Server sendet den publicKey zum Client
6) Der Client, generiert einen AES-Schlüssel und verschlüsselt den mit dem publicKey des Servers, und schickt dies zum Server
7) Server entschlüsselt das Paket, und speichert sich den AES-Schlüssel in einer Hashmap, wobei die ID des Clients der Key ist
8) der Server schickt dem Client das erste mit AES verschlüsselte Paket(von da an sollten alle Pakete, die ausgetauscht werden mit dem AES-Schlüssel verschlüsselt werden)

9) FERTIG
 
D

despikyxd

Gast
gut ... ich weis jetzt nicht wem von euch beiden ich zuerst antworten soll ...
ich glaube ich fang mit jatoll an ... das wird einfacher und kürzer

@jatoll

ich habe hier im forum bereits ein fertiges RSA/AES - system gepostet
http://www.java-forum.org/allgemeine-java-themen/112839-netzwerk-sicherheit-hybrid-kryptosystem.html
zu übergeben sind BufferedReader und PrintStream
zur erzeugung der streams
BufferedReader : new BufferedReader(new InputStreamReader(Socket.getInputStream()))
PrintStream : new PrintStream(Socket.getOutputStream())
allerdings stellt sich für mich die frage : chat-system mit verschlüsselung ? ... ich würde es allerhöchstens noch fürs login durchgehen lassen um die user-daten zu schützen ... das kann man dann aber in einem einzelnen RSA-block unterkriegen
aber naja ... natürlich ist es möglich so ein system komplett zu verschlüsseln ... erzeugt halt nur overhead *den meine klassen eh erzeugen*
also ... kuggs dir an und wenn du interesse gefunden hast oder fragen zu hast ... einfach in dem thread posten ...
zur erklärung wie ein hybrides-system funktioniert hab ich bei lord's art und weise einen kleinen manko anzumerken
normalerweise hat der server EIN statisches KeyPair ... und so sollte man es auch implementieren ... *ja .. ist bei mir auch so das für jede verbindung ein neues keypair erzeugt wird ... aber für ein multi-client system war es ursprünglich eingentlich nicht gedacht =P*
und nach dem der symetrische key ausgetauscht wurde braucht man das rsa-keypair auch nicht mehr ...
was man unbedingt vermeiden sollte : punkt 4 : verbindungsdaten *schlüssel oder dergleichen* nicht physisch auf einem datenträger speichern ... und wenn doch : dann an das löschen nach verbindungs-ende denken !


und nur zu lord selbst

ja ... mag sein das wir an einander vorbei reden ... aber das was du WILLST ... oder meinet wegen auch WOLLTEST war das hier

So, ich muss nochmal den Thread aus den Tiefen des Forums holen.

Ich habe immer noch das selbe Problem. Das da heißt Daten mit RSA verschlüsseln, die länger sind als die zugelassenen Daten.

Es sollen nämlich wieder ein RSA-Schlüssel mit RSA verschlüsselt und über eine Netzwerkanbindung verschickt werden. (Stichwort: Zertifizierung)

Natürlich ist der serialisierte RSA-Schlüssel länger als die zulässige Läge der Daten zum verschlüsseln. [Exkurs: Da ich einen 2048byte großen RSA-Schlüssel benutze, kann dieser nur maximal 256 Byte verschlüsseln (Der zu verschlüsselnde Schlüssel ist aber wiederum serialisiert 551 Byte lang.]

erstmal : man verschlüsselt einen RSA-PUBLIC-KEY nicht mit einem noch weiteren ... das ist totaler schwachsinn ...
RSA beruht darauf das eben diese PUBLIC keys auch PUBLIC werden können ohne das gleich das ganze system in gefahr geräht ...
lediglich die PRIVATE keys sind geheimzuhalten

und zweitens ... das was du da gebastelt hast würde man so nie verwenden ... das verteilen eines RSA-PUBLIC der mit einem weiteren verschlüsselt wurde ...
das würde man allerhöchstens ... und auch nur dann in sonderfällen bei der signierung von zertifikaten verwenden ...
aber selbst wird erstens nicht der key selbst sondern nur ein hash-wert dessen signiert ... und zweitens wird mit dem PRIVATE signiert und mit dem PUBLIC verifiziert ...

ansonsten hast du entweder n ziemlich harten denkfehler oder du weist scheinbar selbst nicht was du willst und wie du es ausdrücken sollst
 

Lord_Aratorn

Aktives Mitglied
was man unbedingt vermeiden sollte : punkt 4 : verbindungsdaten *schlüssel oder dergleichen* nicht physisch auf einem datenträger speichern ... und wenn doch : dann an das löschen nach verbindungs-ende denken !
Da hast du recht, darum speichere ich den Schlüssel auch nicht lokal auf dem Server sondern, remote auf einem verschlüsselten Laufwerk, das nur über das Intranet erreichbar ist.

und nur zu lord selbst

ja ... mag sein das wir an einander vorbei reden ... aber das was du WILLST ... oder meinet wegen auch WOLLTEST war das hier
[qoute]
So, ich muss nochmal den Thread aus den Tiefen des Forums holen.

Ich habe immer noch das selbe Problem. Das da heißt Daten mit RSA verschlüsseln, die länger sind als die zugelassenen Daten.

Es sollen nämlich wieder ein RSA-Schlüssel mit RSA verschlüsselt und über eine Netzwerkanbindung verschickt werden. (Stichwort: Zertifizierung)

Natürlich ist der serialisierte RSA-Schlüssel länger als die zulässige Läge der Daten zum verschlüsseln. [Exkurs: Da ich einen 2048byte großen RSA-Schlüssel benutze, kann dieser nur maximal 256 Byte verschlüsseln (Der zu verschlüsselnde Schlüssel ist aber wiederum serialisiert 551 Byte lang.]
[/qoute]
erstmal : man verschlüsselt einen RSA-PUBLIC-KEY nicht mit einem noch weiteren ... das ist totaler schwachsinn ...
RSA beruht darauf das eben diese PUBLIC keys auch PUBLIC werden können ohne das gleich das ganze system in gefahr geräht ...
lediglich die PRIVATE keys sind geheimzuhalten

und zweitens ... das was du da gebastelt hast würde man so nie verwenden ... das verteilen eines RSA-PUBLIC der mit einem weiteren verschlüsselt wurde ...
das würde man allerhöchstens ... und auch nur dann in sonderfällen bei der signierung von zertifikaten verwenden ...
aber selbst wird erstens nicht der key selbst sondern nur ein hash-wert dessen signiert ... und zweitens wird mit dem PRIVATE signiert und mit dem PUBLIC verifiziert ...

ansonsten hast du entweder n ziemlich harten denkfehler oder du weist scheinbar selbst nicht was du willst und wie du es ausdrücken sollst

Puh! Ja ich weiß, dass es sich komisch anhört, und man im Normalfall nicht RSASchlüssel mit RSA verschlüsselt. Und wenn ich jemals geschrieben habe, dass ich mit dem Publickey signieren will, habe ich mich verschrieben. Denn natürlich weiß ich, dass man mit dem Private signiert, mit dem Public verschlüsselt, da man Daten, die mit dem Privatekey verschlüsselt sind, wieder mit dem Public entschlüsseln kann. Und da davon ausgegangen wird, dass den Private nur 1ner besitzt, wird davon ausgegangen, dass genau dieser die Nachricht auch signiert hat.

Naja banannarama. Ich habe halt gefragt, weil ich nicht weiß wie ich die Aufgabe, die mir aufgetragen wurde(publickey mit publickey verschlüsseln) bewältigen soll, ohne dass ich mir ein neues Protokoll überlege. Und bevor ich dies tu dachte ich mir: "fragste im Forum". Die Aufgabe ändert sich daher nicht und ich soll immer noch einen Publickey mit einem Publickey verschlüsseln. :/
 
D

despikyxd

Gast
ach ... mensch ... nein ... du verstehst das mit dem NICHT SPEICHERN nicht ...
wenn du einmalig ein festes ServerKeyPair generierst speicherst du es einmal fest auf platte ... liest es beim server-start ein und hälts es dann im speicher ...
wenn du allerdings *wie auch lieder meine klassen* für jede verbindung ein neues RSA pair generierst ... und dann damit einen für jede verbindung neuen symetrischen schlüssel verschlüsselst und wieder zurück sendest brauchst du das KeyPair nur ein einziges mal und ab dann nur noch den symetrischen schlüssel ... bedeutet das du das KeyPair nach erhalt des keys ausm speicher nehmen kannst *also referrenzen null setzen* und brauchst dann nur noch den key im speicher halten ...
wenn du mir jetzt allerdings erklärst warum die schlüssel oder sonstwas auf platte speichern willst dann können wir uns gerne darüber unterhalten
und ob du es lokal auf der server platte oder auf irgend nem remote-drive speicherst ... und ob das nu verschlüsselt is oder nich is auch egal *eher im gegenteil ... wenn das remote-drive verschlüsselt is erzeugt das nur noch mehr overhead*
das ist das was ich versucht hab dir mit PUNKT 4 klar zumachen ...

und nu zur aufgabe selbst

du hast also die aufgabe einen RSAPublicKey mit einem weiteren RSAPublicKey zu verschlüsseln ...
gut ... also musst du den key erstmal in eine form bringen die man in ein byte-array stecken kann ... und auch aus einem solchen wieder problemlos in einen RSAPublicKey bekommt ...

einmal könntest du mit nem ByteArrayOutputStream und nem drübergelegtem ObjectOutputStream den RSAPublic in eine serialisierte form bringen ... hast dann also n byte-array ... und das übergibst du dann an den normalen Cipher der mit ENCRYPT initialisiert wurde ... ob dann aber das byte-array größer als die schlüssellänge is weiß ich nich ...
falls das aber der fall sein sollte kugg dir mal die methode
private byte[] crypt(byte[] input, Cipher cip)
in meinem gepostetem krypto-system an http://www.java-forum.org/allgemeine-java-themen/112839-netzwerk-sicherheit-hybrid-kryptosystem.html
die splittet das array in die zulässige block-größe ... sollte also auch mit RSA funzen ... ich verwende die methode ja nur für die symetrische verschlüsselung

die zweite methode wäre das du dir umständlich die beiden BigInteger modulus und exponent aus dem PublicKey-object holst ... diese dann irgendwie in byte[]-form bringst und dann eigentlich wie im obrigen beispiel vorgehst ...
beim empfangen musst du dann halt den entsprechenden rückwärts-weg gehen ... also entweder deserialisieren oder mit ner key-factory und der RSAPublicKeySpec n RSAPublicKey wieder neu erzeugst ...

also wie du siehst kommst du selbst mit den beiden möglichkeiten wie du einen PublicKey überhaupt in eine verwendbare form wie ein byte-array umwandelst an einem manuellen splitten dieses arrays nicht vorbei kommst ...
ich gebe zu ... die crypt-methode ist nicht aus meiner feder ... ich habe sie auch nur aus dem netz kopiert *weiß aber leider nicht mehr wo ... denn auf dieser seite wurde auch ein ähnliches problem erklärt und gelöst wie du jetzt hast

ich hoffe ich konnte dir jetzt irgendwie weiterhelfen ... weil eine noch andere möglichkeit würde mir jetzt auch nicht mehr einfallen ...
*und ps : RSA in einen Blockmodus mit padding zu initialisieren ... das scheint irgendwie unmöglich ... oder selbst wenn du es hinbekommst schlägt das de-compilen fehl weil nicht erkennbar ist wann halt nur update() oder schon doFinal() aufgerufen werden muss ...*
 

Lord_Aratorn

Aktives Mitglied
Danke, jedoch funktioniert es nicht wie gedacht!

also ich habe folgende main. (die cryptMethode ist die deinige)

Java:
public static void main(String[] args) {
		try {
			IVIRNNCryptor cryptor = new IVIRNNCryptor();
			KeyPair Keys = cryptor.generateRSAKeyPair();
			Key publicKey = Keys.getPublic();
			Key privateKey = Keys.getPrivate();

			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			ObjectOutputStream oos;
			oos = new ObjectOutputStream(bos);
			oos.writeObject(publicKey);
			byte[] input = bos.toByteArray();
			
			Cipher ersaCipher = Cipher.getInstance("RSA");
			ersaCipher.init(Cipher.ENCRYPT_MODE, publicKey);

			Cipher drsaCipher = Cipher.getInstance("RSA");
			drsaCipher.init(Cipher.DECRYPT_MODE, privateKey);
			
			byte[] encrypted = cryptor.crypt(input, ersaCipher);
			byte[] decrypted = cryptor.crypt(encrypted, drsaCipher);

			if(Arrays.areEqual(input, decrypted)) {
				System.out.println("successfully decrypted");
			}
			else {
				System.out.println("Cryption failed");
			}System.out.println("input.length:"+input.length+"\noutput.length:"+decrypted.length);
			System.out.println("input:"+new String(input)+"\noutput:"+new String(decrypted));
					
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

wenn ich das ausführe bekomme ich folgende exception:

Java:
java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block
	at org.bouncycastle.jce.provider.JCERSACipher.engineUpdate(Unknown Source)

Die schlüssel wurden mit
Java:
public static synchronized KeyPair generateRSAKeyPair() {
		try {
			KeyPairGenerator pairgen;
			pairgen = KeyPairGenerator.getInstance("RSA", "BC");
			SecureRandom random = new SecureRandom();
			pairgen.initialize(2048,
					random);
			KeyPair keyPair = pairgen.generateKeyPair();
			return keyPair;
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return null;
	}
generiert
 
D

despikyxd

Gast
gut ... ich antworte jetzt mal OHNE meinen test-code zu posten

das eine excpetion fliegt und dann mit dieser msg ... post DU bitte erstmal deinen kompletten test-code ... und bitte auch den vollständigen StackTrace

aber meine antwort ist kurz um dir zu erklären warum und was hier nicht geht
du kannst mit meiner crypt(byte[] b, Cipher c) nicht arbeiten da ein RSA cipher nunmal eine BlockSize von 0 hat ...
was dann in der crypt methode passiert ist einfach : er versucht die ganze zeit in ein 0 byte großes input-array zu lesen ...
warum bei mir desswegen keine exception fliegt kann nur daran liegen das das array richtig initialisiert wurde aber lediglich ne größe von 0 hat ... wobei hier auch schon wieder n schöner bug is den man melden sollte : in sämtlichen read-methoden prüfen ob array größer 0 ist ... aber nunja ... egal

aber eigentlich sollte die exception ganz wo anderst fliegen ... nämlich an der init stelle wo du versuchst einen BC-key an einen SUN-cipher zu übergeben ... vllt liegt es daran ... ich hab echt keinen bock mir BC zu laden ums zu testen

EDIT : gut ich hab mir doch mal BC gezogen und dabei was erstaunliches rausbekommen
die BC-impl von JCERSA hat beim ENCRYPT eine BlockSize von 255 ... und eine BlockOutputSize von 256 //RSA-2048
beim DECRYPT allerdings umgekehrt ... also BS 256 / OS 255 //RSA-2048
und ebenfalls das decrypt schmeist genau die selbe exception obwohl ihr zum test ein byte-array mit size 2048 übergeben wurde *inhalt übrigens NULL bzw (byte)0x00 ... weis ich nich*

wie oben gesagt hat die SUN-impl sowohl im EN- also auch im DE-crypt eine BS von 0 und eine OS von 256 //RSA-2048
was halt RSA als block-cipher in SUN nicht zulässt da nicht implementiert

der fehler liegt also hier in der BC-implementierung ...
ab JETZT sind DIE für dich zuständig ... du kannst dich dann HIER wieder melden wenn du eine antwort hast ... und hoffentlich ne brauchbare ...
tipp : durchsuch erstmal den bug-tracker

und was dieses wort DEINIGE angeht ... es hätte auch DEINE gereicht -.-'


von daher ist hier in diesem forum mit deiner fragerei wie man daten die GRÖßER als die KEYSIZE sind mit BC crypted frage bitte im BC - forum ...
das es mit dem standard SUN halt eben NICHT geht beweisen die ausgaben der CRYPT-methode wenn man einfach mal die beiden ints BS und OS ausgibt ... und wie geschrieben ergeben diese mit SUN und RSA-2048 das paar 0 / 256

PUNKT SCHLUSS AUS UND ENDE
 
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben