Nachdem wir das RSA-Verfahren uns in den beiden Beispielen C01 und C02 angeschaut haben, wollen wir nun einen Blick auf die Funktionsweise richten. Ich habe lange im Netz gesucht und sehr viele Seiten mit dem „strengen“ mathematischen Blickwinkel gefunden, nur konnte ich in der praktischen Umsetzung in Java nicht viel damit anfangen.
Vor ein paar Jahren hatte ich zum Thema RSA-Verschlüsselung eine Facharbeit eines Schülers im Netz gefunden, von der ich mir glücklicherweise einen Ausdruck gemacht habe. Leider ist die Facharbeit von der Webseite der Schule verschwunden und ich stelle Euch den Scan der Arbeit über diesen Link zur Verfügung, da es die beste einfache Beschreibung des RSA-Verfahrens ist. Ganz ausdrücklich weise ich darauf hin, das es sich nicht um mein eigenes Werk handelt und alle Rechte beim Autor liegen. Hier die Kurzdaten zur Facharbeit: Verfasser: Alexander Lignow, Thema: Das Public Key-Verschlüsselungsverfahren RSA am Beispiel PGP, Erstellungsdatum Februar 1997.
Bei den Variablennamen habe ich mich eng an die Benennung in der Facharbeit gehalten, um das „Nacharbeiten“ einfacher zu gestalten. Da bei der manuellen Berechnungsmethode zum Teil sehr große Zahlen benutzt werden, verwende ich teilweise BigInteger-Variablen, welche gegenüber Integer-Werten andere Methodenaufrufe benötigen.
Auch wenn das Programm so aussieht, als wäre es sehr einfach aufgebaut, ist es dennoch eine voll funktionsfähige RSA-Implementierung. Viel Spaß bei der Betrachtung der Funktionsweise und vielleicht eigene Ergänzungen.
Bitte die nachfolgende Routine nicht für den Echteinsatz nutzen, da sie aus kryptographischer Sicht sehr angreifbar ist !
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
package net.bplaced.javacrypto.asymmetricencryption; /* Basis dieses Programms ist eine Facharbeit, in der das Public Key-Verschlüsselungsverfahren RSA erläutert wird. Leider ist die Seite im Internet nicht mehr verfügbar, auf meiner Webseite finden Sie den Scan der Arbeit. Städtische Fachoberschule 1, Facharbeit aus der Mathematik Thema: Das Public Key-Verschlüsselungsverfahren RSA am Beispiel PGP Fachlehrer: Herr Gregor Verfasser: Alexander Lignow Klasse: 12 G Abgabetermin: 24.02.1997 */ /* * Herkunft/Origin: http://javacrypto.bplaced.net/ * Programmierer/Programmer: Michael Fehr * Copyright/Copyright: frei verwendbares Programm (Public Domain) * Copyright: This is free and unencumbered software released into the public domain. * Lizenttext/Licence: <http://unlicense.org> * getestet mit/tested with: Java Runtime Environment 8 Update 191 x64 * Datum/Date (dd.mm.jjjj): 26.12.2018 * Funktion: manuelle RSA-Verschlüsselung (Asymmetrisch) * Function: manual RSA-encryption (asymmetric) * * Sicherheitshinweis/Security notice * Die Programmroutinen dienen nur der Darstellung und haben keinen Anspruch auf eine * korrekte Funktion, insbesondere mit Blick auf die Sicherheit ! * Prüfen Sie die Sicherheit bevor das Programm in der echten Welt eingesetzt wird. * The program routines just show the function but please be aware of the security part - * check yourself before using in the real world ! */ import java.math.BigInteger; import javax.xml.bind.DatatypeConverter; public class C03_RsaManuell { // hinweis: die benennung der variablen erfolgt so nahe wie möglich an der // benennung in der facharbeit // diese variablen werden auch in den methoden benötigt static BigInteger zBig; // ergebnis von p*q static int divisorCountInt = 0; // anzahl der teiler in den methoden findDivisors und foundDivisors static BigInteger[] divisorBig = new BigInteger[10]; // gefundene teiler in den methoden findDivisors und static boolean verboseBool = true; // schalter für die ausgaben des programms: // true = nur sehr wenige ausgaben, false = sehr viele ausgaben public static void main(String[] args) { System.out.println("C03 RSA-Verfahren manuell mit Signatur"); // kapitel 2.2 System.out.println("\nKapitel 2.2 Erstellung von 3 Schlüsselpaaren"); // erzeugung von 3 schlüsselpaaren für alice, bob und charlie, kurz A, B und C // schlüsselpaar für A alice int pInt = 3; int qInt = 11; // ab hier wird das schlüsselpaar berechnet int createRsaPairResultInt = 1; // 0 = exakt 2 teiler gefunden, 1 = ergebnis darf nicht verwendet werden createRsaPairResultInt = createRsaPair(pInt, qInt); if (createRsaPairResultInt == 1) { System.out.println("Die angegebenen Werte für p:" + pInt + " und q:" + qInt + " ergeben keinen gültigen Schlüssel, das Programm wird beendet"); System.exit(0); } // übernahme der werte aus der methode createRsaPair BigInteger publicAliceBig = divisorBig[3]; // d = öffentlicher schlüssel von a alice BigInteger privateAliceBig = divisorBig[2]; // e = privater schlüssel von a alice BigInteger zAliceBig = zBig; // z = modulus der schlüssel von a alice // ausgabe der werte System.out.println("Erzeuge ein Schlüsselpaar für A Alice private:" + privateAliceBig + " public:" + publicAliceBig + " z:" + zAliceBig); // schlüsselpaar für b bob pInt = 17; qInt = 3; // ab hier wird das schlüsselpaar berechnet createRsaPairResultInt = 1; // 0 = exakt 2 teiler gefunden, 1 = ergebnis darf nicht verwendet werden createRsaPairResultInt = createRsaPair(pInt, qInt); if (createRsaPairResultInt == 1) { System.out.println("Die angegebenen Werte für p:" + pInt + " und q:" + qInt + " ergeben keinen gültigen Schlüssel, das Programm wird beendet"); System.exit(0); } // übernahme der werte aus der methode createRsaPair BigInteger publicBobBig = divisorBig[3]; // d = öffentlicher schlüssel von b bob BigInteger privateBobBig = divisorBig[2]; // e = privater schlüssel von b bob BigInteger zBobBig = zBig; // z = modulus der schlüssel von b bob // ausgabe der werte System.out.println("Erzeuge ein Schlüsselpaar für B Bob private:" + privateBobBig + " public:" + publicBobBig + " z:" + zBobBig); // schlüsselpaar für c charlie pInt = 5; qInt = 17; // ab hier wird das schlüsselpaar berechnet createRsaPairResultInt = 1; // 0 = exakt 2 teiler gefunden, 1 = ergebnis darf nicht verwendet werden createRsaPairResultInt = createRsaPair(pInt, qInt); if (createRsaPairResultInt == 1) { System.out.println("Die angegebenen Werte für p:" + pInt + " und q:" + qInt + " ergeben keinen gültigen Schlüssel, das Programm wird beendet"); System.exit(0); } // übernahme der werte aus der methode createRsaPair BigInteger publicCharlieBig = divisorBig[3]; // d = öffentlicher schlüssel von b bob BigInteger privateCharlieBig = divisorBig[2]; // e = privater schlüssel von b bob BigInteger zCharlieBig = zBig; // z = modulus der schlüssel von b bob // ausgabe der werte System.out.println("Erzeuge ein Schlüsselpaar für C Charlie private:" + privateCharlieBig + " public:" + publicCharlieBig + " z:" + zCharlieBig); // kapitel 3.1 System.out.println("\nKapitel 3.1 Verschlüsselung einer Nachricht"); // da die mathematischen routinen nicht mit sehr großen zahlen umgehen können // ersetzen wir die werte // tabelle mit werten // a = asc97 = 2 // b = asc98 = 3 // c = asc99 = 4 // - = asc45 = 5 // beispiel a - b = 2 5 3 // variablen für die routinen byte[] plaintextByte = { 2, 5, 3 }; // unsere nachricht zur verschlüsselung // verschlüsselte nachricht BigInteger[] ciphertextBig = new BigInteger[3]; // entschlüsselte nachricht BigInteger[] decryptedtextBig = new BigInteger[3]; // senden der nachricht von alice an bob // alice verschlüsselt die nachricht mit dem public key von bob for (int i = 0; i < plaintextByte.length; i++) { ciphertextBig[i] = rsaEncryption(plaintextByte[i], publicBobBig, zBobBig); } System.out.println("Verschlüsselung des Textes a-b mit dem PublicKey von Bob"); System.out.println("Klartext :" + DatatypeConverter.printByte(plaintextByte[0]) + " " + DatatypeConverter.printByte(plaintextByte[1]) + " " + DatatypeConverter.printByte(plaintextByte[2])); System.out.println("Verschlüsselt :" + DatatypeConverter.printInteger(ciphertextBig[0]) + " " + DatatypeConverter.printInteger(ciphertextBig[1]) + " " + DatatypeConverter.printInteger(ciphertextBig[2])); // die verschlüsselte nachricht wird an bob gesendet // bob entschlüsselt die nachricht mit seinem private key for (int i = 0; i < ciphertextBig.length; i++) { BigInteger ciphertextSingleBig = ciphertextBig[i]; BigInteger decryptedtextSingleBig = rsaDecryption(ciphertextSingleBig, privateBobBig, zBobBig); decryptedtextBig[i] = decryptedtextSingleBig; } System.out.println("\nEntschlüsselung des Textes a-b mit dem PrivateKey von Bob"); System.out.println("Verschlüsselt :" + DatatypeConverter.printInteger(ciphertextBig[0]) + " " + DatatypeConverter.printInteger(ciphertextBig[1]) + " " + DatatypeConverter.printInteger(ciphertextBig[2])); System.out.println("Entschlüsselt :" + DatatypeConverter.printInteger(decryptedtextBig[0]) + " " + DatatypeConverter.printInteger(decryptedtextBig[1]) + " " + DatatypeConverter.printInteger(decryptedtextBig[2])); // kapitel 3.3 System.out.println("\nKapitel 3.3 Verschlüsselung mit Signatur eines Klartextes"); // nun wird eine nachricht von b bob an a alice geschickt // zusätzlich wird ein unterschriftswert mitgeschickt // beispiel b - a = 3 5 2 6 // variablen für die routinen byte[] plaintextByte2 = { 3, 5, 2, 6 }; // unsere nachricht zur verschlüsselung // verschlüsselte nachricht BigInteger[] ciphertextBig2 = new BigInteger[4]; // entschlüsselte nachricht BigInteger[] decryptedtextBig2 = new BigInteger[4]; // senden der nachricht von bob an alice // bob verschlüsselt die nachricht mit dem public key von alice for (int i = 0; i < plaintextByte2.length; i++) { ciphertextBig2[i] = rsaEncryption(plaintextByte2[i], publicAliceBig, zAliceBig); } System.out.println("Verschlüsselung des Textes b-a mit dem PublicKey von Alice"); System.out.println("Klartext :" + DatatypeConverter.printByte(plaintextByte2[0]) + " " + DatatypeConverter.printByte(plaintextByte2[1]) + " " + DatatypeConverter.printByte(plaintextByte2[2]) + " " + DatatypeConverter.printByte(plaintextByte2[3])); System.out.println("Verschlüsselt :" + DatatypeConverter.printInteger(ciphertextBig2[0]) + " " + DatatypeConverter.printInteger(ciphertextBig2[1]) + " " + DatatypeConverter.printInteger(ciphertextBig2[2]) + " " + DatatypeConverter.printInteger(ciphertextBig2[3])); // die verschlüsselte nachricht wird an alice gesendet // alice entschlüsselt die nachricht mit ihrem private key for (int i = 0; i < ciphertextBig2.length; i++) { BigInteger ciphertextSingleBig2 = ciphertextBig2[i]; BigInteger decryptedtextSingleBig2 = rsaDecryption(ciphertextSingleBig2, privateAliceBig, zAliceBig); decryptedtextBig2[i] = decryptedtextSingleBig2; } System.out.println("\nEntschlüsselung des Textes b-a mit dem PrivateKey von Alice"); System.out.println("Verschlüsselt :" + DatatypeConverter.printInteger(ciphertextBig2[0]) + " " + DatatypeConverter.printInteger(ciphertextBig2[1]) + " " + DatatypeConverter.printInteger(ciphertextBig2[2]) + " " + DatatypeConverter.printInteger(ciphertextBig2[3])); System.out.println("Entschlüsselt :" + DatatypeConverter.printInteger(decryptedtextBig2[0]) + " " + DatatypeConverter.printInteger(decryptedtextBig2[1]) + " " + DatatypeConverter.printInteger(decryptedtextBig2[2]) + " " + DatatypeConverter.printInteger(decryptedtextBig2[3])); // kapitel 3.4 System.out.println("\nKapitel 3.4 Eine dritte Person fängt eine verschlüsselte Nachricht ab"); // nun wird eine nachricht von b bob an a alice geschickt // zusätzlich wird ein unterschriftswert mitgeschickt // beispiel b - a = 3 5 2 6 // variablen für die routinen byte[] plaintextByte3 = { 3, 5, 2, 6 }; // unsere nachricht zur verschlüsselung // verschlüsselte nachricht BigInteger[] ciphertextBig3 = new BigInteger[4]; // entschlüsselte nachricht BigInteger[] decryptedtextBig3 = new BigInteger[4]; // senden der nachricht von bob an alice // bob verschlüsselt die nachricht mit dem public key von alice for (int i = 0; i < plaintextByte3.length; i++) { ciphertextBig3[i] = rsaEncryption(plaintextByte3[i], publicAliceBig, zAliceBig); } System.out.println("Verschlüsselung des Textes b-a mit dem PublicKey von Alice"); System.out.println("Klartext :" + DatatypeConverter.printByte(plaintextByte3[0]) + " " + DatatypeConverter.printByte(plaintextByte3[1]) + " " + DatatypeConverter.printByte(plaintextByte3[2]) + " " + DatatypeConverter.printByte(plaintextByte3[3])); System.out.println("Verschlüsselt :" + DatatypeConverter.printInteger(ciphertextBig3[0]) + " " + DatatypeConverter.printInteger(ciphertextBig3[1]) + " " + DatatypeConverter.printInteger(ciphertextBig3[2]) + " " + DatatypeConverter.printInteger(ciphertextBig3[3])); // die verschlüsselte nachricht wird an alice gesendet, aber von charlie // abgefangen // charlie entschlüsselt die nachricht mit seinem private key for (int i = 0; i < ciphertextBig3.length; i++) { BigInteger ciphertextSingleBig3 = ciphertextBig3[i]; BigInteger decryptedtextSingleBig3 = rsaDecryption(ciphertextSingleBig3, privateCharlieBig, zCharlieBig); decryptedtextBig3[i] = decryptedtextSingleBig3; } System.out.println("\nEntschlüsselung des Textes b-a mit dem PrivateKey von Charlie"); System.out.println("Verschlüsselt :" + DatatypeConverter.printInteger(ciphertextBig3[0]) + " " + DatatypeConverter.printInteger(ciphertextBig3[1]) + " " + DatatypeConverter.printInteger(ciphertextBig3[2]) + " " + DatatypeConverter.printInteger(ciphertextBig3[3])); System.out.println("Entschlüsselt:" + DatatypeConverter.printInteger(decryptedtextBig3[0]) + " " + DatatypeConverter.printInteger(decryptedtextBig3[1]) + " " + DatatypeConverter.printInteger(decryptedtextBig3[2]) + " " + DatatypeConverter.printInteger(decryptedtextBig3[3])); System.out.println("Hinweis: hier kommt es zu einer Abweichung zur Facharbeit !"); System.out.println("\nC03 RSA-Verfahren manuell mit Signatur beendet"); } public static void findDivisors(BigInteger num) { BigInteger limit = num; BigInteger counter = BigInteger.ONE; while (counter.compareTo(limit) < 0) { if (num.mod(counter).compareTo(BigInteger.ZERO) == 0) { foundDivisors(counter); BigInteger partner = num.divide(counter); foundDivisors(partner); limit = partner; // shorten the loop } counter = counter.add(BigInteger.ONE); } } public static void foundDivisors(BigInteger divisor) { divisorBig[divisorCountInt] = divisor; // ein treffer erhöht den zähler divisorCountInt++; if (verboseBool == false) { System.out.println("Teiler:" + divisor); } } public static int createRsaPair(int pInt, int qInt) { int resultInt = 1; // 0 = genau 2 teiler gefunden 1 = mehr oder weniger teiler gefunden, falsch if (verboseBool == false) { System.out.println("createRSA Keypair p:" + pInt + " q:" + qInt); } BigInteger pBig = BigInteger.valueOf(pInt); BigInteger qBig = BigInteger.valueOf(qInt); // z ermitteln als p * q BigInteger zInternBig = pBig.multiply(qBig); zBig = zInternBig; // übergabe an die Hauptroutine if (verboseBool == false) { System.out.println("zInternBig:" + zInternBig); } // phi(z) ermitteln als (p-1) * (q-1) // phizA = (pA - 1) * (qA - 1); BigInteger einsBig = new BigInteger("1"); BigInteger phizBig = pBig.subtract(einsBig).multiply(qBig.subtract(einsBig)); if (verboseBool == false) { System.out.println("phi(z):" + phizBig); } // phi(z) + 1 errechnen BigInteger phizPeBig = phizBig.add(einsBig); if (verboseBool == false) { System.out.println("phi(z)+1:" + phizPeBig); } // suche nach dem teiler von phizPeAbig if (verboseBool == false) { System.out.print("Teiler von " + phizPeBig + ": "); } if (verboseBool == false) { System.out.println(); } // anzahl teiler auf null setzen divisorCountInt = 0; findDivisors(phizPeBig); if (verboseBool == false) { System.out.println("Anzahl Teiler (gewünscht: exakt 4):" + divisorCountInt); } if (divisorCountInt == 4) { // es ist die richtige anzahl teiler, aber sind sie auch unterschiedlich ? if ((divisorBig[2]) != (divisorBig[3])) { resultInt = 0; if (verboseBool == false) { System.out.println("gefundene Teiler ohne Start und Ende:" + divisorBig[2] + "+" + divisorBig[3]); } } } if (verboseBool == false) { System.out.println("= = = fertig = = ="); } return resultInt; } public static BigInteger rsaEncryption(int plaintextInt, BigInteger publicKeyBig, BigInteger zBig) { BigInteger ThochPublicKeyModZBig = BigInteger.valueOf(plaintextInt).modPow(publicKeyBig, zBig); if (verboseBool == false) { System.out.println("ThochPublicKeyModZBig(" + plaintextInt + "):" + ThochPublicKeyModZBig); } return ThochPublicKeyModZBig; } public static BigInteger rsaDecryption(BigInteger ciphertextBig, BigInteger privateKeyBig, BigInteger zBig) { BigInteger ThochPrivateKeyModZBig = ciphertextBig.modPow(privateKeyBig, zBig); if (verboseBool == false) { System.out.println("ThochPrivateKeyModZBig(" + ciphertextBig + "):" + ThochPrivateKeyModZBig); } return ThochPrivateKeyModZBig; } public static BigInteger rsaSignature(int plaintextInt, BigInteger privateKeyBig, BigInteger zBig) { BigInteger ThochPrivateKeyModZBig = BigInteger.valueOf(plaintextInt).modPow(privateKeyBig, zBig); if (verboseBool == false) { System.out.println("ThochPrivateKeyModZBig(" + plaintextInt + "):" + ThochPrivateKeyModZBig); } return ThochPrivateKeyModZBig; } public static BigInteger rsaVerification(BigInteger signatureBig, BigInteger publicKeyBig, BigInteger zBig) { BigInteger ThochPublicKeyModZBig = signatureBig.modPow(publicKeyBig, zBig); if (verboseBool == false) { System.out.println("ThochublicKeyModZBig(" + signatureBig + "):" + ThochPublicKeyModZBig); } return ThochPublicKeyModZBig; } public static Boolean rsaVerificationCheck(BigInteger[] decryptedtextBig, BigInteger[] verificationBig) { // rückgabe true = arrays sind gleich, false = arrays sind nicht gleich boolean arraysGleich = false; int arrayDecryptedtextLengthInt = decryptedtextBig.length; int arrayVerificationLengthInt = verificationBig.length; if (arrayDecryptedtextLengthInt == arrayVerificationLengthInt) { boolean arraysSingleGleich = true; if (verboseBool == false) { System.out.println("Decryption + Verification Länge gleich"); } int res; // für späteren BigInteger-Vergleich for (int i = 0; i < arrayDecryptedtextLengthInt; i++) { if (verboseBool == false) { System.out.println("i:" + i + " decryptedtextBig[i]" + decryptedtextBig[i] + " verificationBig[i]:" + verificationBig[i]); } res = decryptedtextBig[i].compareTo(verificationBig[i]); if (res != 0) { arraysSingleGleich = false; } arraysGleich = arraysSingleGleich; } } return arraysGleich; } } |
Nun noch die Ausgabe auf der Konsole:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
C03 RSA-Verfahren manuell mit Signatur Kapitel 2.2 Erstellung von 3 Schlüsselpaaren Erzeuge ein Schlüsselpaar für A Alice private:3 public:7 z:33 Erzeuge ein Schlüsselpaar für B Bob private:3 public:11 z:51 Erzeuge ein Schlüsselpaar für C Charlie private:5 public:13 z:85 Kapitel 3.1 Verschlüsselung einer Nachricht Verschlüsselung des Textes a-b mit dem PublicKey von Bob Klartext :2 5 3 Verschlüsselt :8 11 24 Entschlüsselung des Textes a-b mit dem PrivateKey von Bob Verschlüsselt :8 11 24 Entschlüsselt :2 5 3 Kapitel 3.3 Verschlüsselung mit Signatur eines Klartextes Verschlüsselung des Textes b-a mit dem PublicKey von Alice Klartext :3 5 2 6 Verschlüsselt :9 14 29 30 Entschlüsselung des Textes b-a mit dem PrivateKey von Alice Verschlüsselt :9 14 29 30 Entschlüsselt :3 5 2 6 Kapitel 3.4 Eine dritte Person fängt eine verschlüsselte Nachricht ab Verschlüsselung des Textes b-a mit dem PublicKey von Alice Klartext :3 5 2 6 Verschlüsselt :9 14 29 30 Entschlüsselung des Textes b-a mit dem PrivateKey von Charlie Verschlüsselt :9 14 29 30 Entschlüsselt:59 29 54 30 Hinweis: hier kommt es zu einer Abweichung zur Facharbeit ! C03 RSA-Verfahren manuell mit Signatur beendet |
Die Lizenz zum obigen Beispiel findet Ihr auf der eigenen Lizenz-Seite.
Letzte Aktualisierung: 26.12.2018