Keygenerator

asdfman

Commander
Registriert
März 2008
Beiträge
2.315
Mahlzeit.

Im Rahmen eines aktuellen Projekts ist mir nebenbei eine Idee für einen
Produktkeygenerierungsalgorithmus eingefallen.
Ich möchte den kurz mal beschreiben und wollte fragen, ob jemandem
auf die Schnelle irgendwelche offensichtlichen Schwächen auffallen.

€: Falls das Verfahren irgendjemandem gefallen sollte, kann er es gern
so frei er will verwenden. Ich verzichte da auf jegliche Ansprüche geistigen
Eigentums.

Generieren des Key:

1. Man generiere eine sichere 256-bit Zufallszahl S und halte diese geheim.
2. Man generiere vier 32-bit Zahlen P0-3 mit folgenden Eigenschaften:
2a. P0 enthält 32 Bits mit Flags über die Art des Accounts (Admin, Moderator etcpp)
2b. P1 setze man auf einen beliebigen Wert.
2c. P2 ist eine für jeden Nutzer eindeutige ID
2d. P3 sind die letzten 32 Bit von S
3. Man Bilde P durch aneinanderhängen von P0 bis P3
4. Man verschlüssle P mit Rijndael (Blocklänge 128 Bit, Schlüssellänge 256 Bit) mit S als Schlüssel und erhält so K.
5. K ist der Product Key

Verifizieren des Key:

1. Man entschlüssle K mit Rijndael mit S als Schlüssel und erhält P
2. Man teile P in P0 bis P3
3. Man überprüfe, ob die letzten 32 Bit von S und P3 identisch sind. Falls nicht lehne man den Key ab.
3. Man überprüfe, ob P2 mit der ID des Users übereinstimmt. Falls nicht, lehne man den Key ab.
4. Man akzeptiert den Key und setzt die Rechte des Nutzers entsprechend P0
 
Zuletzt bearbeitet:
Da du Informationen in dem Key speicherst, würd ich auch in P1 was sinnvolles speichern.
Man könnte doch z.B. das Kaufdatum eintragen(wär ein beliebiger Wert).
Ungefähr so: 20080921 (für heute). Dann könnte man noch eine Zahl von 0 - 9 hinzufügen.
Die hinzugefügte Zahl gibt dann die Anzahl der Jahre an, indem ab Kauftag Support geleistet wird.
Nur mal so als Beispiel.
 
Ack:

Ja könnte man so machen. Ich denke mir nur, dass ein potentieller Angreifer
so wie das Verfahren jetzt steht, schon 64 Bits von P kennt. Wenn ich jetzt
noch in P1 bekannte Daten speichere, steigt das auf 96 Bits an.
Ich denke mir deshalb, es wäre wohl sicherer, P1 zufällig zu lassen.

Ein anderer Punkt wäre, dass mit festem P0-2 für jeden Wert von S
nur noch genau ein Wert für K herauskommen kann. Bei variablem P1
gäbe es aber 2^32 Möglichkeiten.
Das hätte den Vorteil, dass falls der Benutzer einen Key verliert, ein neuer
gültiger ausgestellt werden kann, und man den alten blacklisten kann.
 
Inwiefern blacklisten? Ich kann mir das momentan nur so vorstellen, dass bei der Verifizierung eine Verbindung zu einem Server besteht, der den Key abcheckt. Indem Fall könnte man bei Verlust einfach den alten Key aus dem Server nehmen und ihn dem Kunden geben.
 
Blacklisten im Sinne von blacklisten halt. Dass vorherige Keys des Benutzers nicht
mehr akzeptiert werden, wenn er einen Ersatz anfordert. Das ist auch nur ein Einfall
den ich hatte. Muss man so natürlich nicht umsetzen; es ist ja auch die UID Teil
des Schlüssels und deshalb dürfte ein anderer Benutzer sich damit nicht anmelden
können.

Wichtiger finde ich eh, dass ein Angreifer bei 32 zufälligen Bits in P weniger Information
hat, die er nutzen könnte um im Extremfall S zu ermitteln (wenn beispielsweise ein
known-plaintext Angriff gegen Rijndael bekannt würde).
 
Was ich mir noch nicht ganz vorstellen kann: Wie soll jemand wissen, wie der Schlüssel aufgebaut ist? Dazu müsste die Vorgehensweise bekannt sein.
Das einzige was man weiß: Der Key beinhaltet Informationen über UID, Rechte und Datum und noch etwas. Aber wie das zusammen den Schlüssel bildet, weiß man nicht.
Natürlich bedeutet eine komplette 32 bit Zahl die zufällig erstellt wurde höhere Sicherheit. Ich frage mich aber in der Hinsicht, ob die Sicherheit ohne Zufallszahl nicht auch völlig ausreichend ist.
Wenn der Aufbau nicht bekannt ist, könnte man höchstens Reverse Engineering benutzen, um es herauszufinden. Aber dann bringt kein Produktkey mehr was.
 
Naju die Vorgehensweise ist ja bekannt. Immerhin hab ich sie hier gepostet.
Worauf ich hoffe, ist dass die Sicherheit des Verfahrens allein von S abhängt.

Wenn diese Bedingung erfüllt ist, kann ja ruhig jeder wissen, wie der Key
generiert wird. Er wird keinen fälschen können, solange S geheim bleibt.

Aber ist diese Bedingung erfüllt? Wie schwer ist es, bei bekanntem K und
mindestens 64, aber meinetwegen auch 96 bekannten Bits von P, S zu
ermitteln? Wäre das einfach, stürzt alles in sich zusammen.

Aber vielleicht kann man auch ohne Kenntnis von S gefälschte K erzeugen.
Ich bin kein Experte auf diesem Gebiet. Vielleicht kann jemand anders mehr
sagen.

Was die Nutzung von P0-3 angeht, bin ich auch für Vorschläge offen.

Soll ich die Speicherung der UID herausnehmen, so dass man allgemeingültige
Keys erzeugen kann, die jeder benutzen darf, dann aber nach Benutzung
nicht mehr von einem anderen User akzeptiert werden?

Ist es sicher, Teile von S in P3 zu verwenden? Sagen wir es würde
ein Angriff bekannt, bei dem man aus K ohne S zu kennen, P ermitteln könnte.
Dann hätte der Angreifer die 32bit von S die in P3 gespeichert sind,
und damit immerhin schon ein achtel der Daten, die er benötigt, um das ganze
Schema umkippen zu lassen.

P3 wird beim Vergleich mit S zur Verifikation benutzt. Ich gehe davon
aus, dass ein Angreifer P3 nicht kennt. Aber was ist, wenn er aus
der Information, dass die letzten 32bit des Schlüssels mit P3 identisch
sind einen Angriff konstruieren kann?

Was könnte ich stattdessen in P3 benutzen, mit dem die Gültigkeit des
Schlüssels kontrolliert werden kann?

Was wären grundsätzlich ganz andere Ideen, P zu füllen?
 
Zuletzt bearbeitet:
Naja, allein diese Befürchtungen sagen schon alles aus. Jedes System ist irgendwie knackbar.
Das sieht man ja auch an den großen Herstellern. Die bekommen auch nichts anständiges hin.

Aber ich meinte jetzt in Sachen "nicht wissen welches Verschlüsselungssystem", dass es zwar bekannt ist, aber wenn man eine Software schreibt, muss man ja nicht sagen, welches System man verwendet.

Aber es ist was wahres dran, dass in P3 ein Teil des Schlüssels steckt. Da sollte vielleicht eher eine Variable drin stehen, die anders abgecheckt werden sollte.
Aber ohne vollständig bekannten Schlüssel ist keine Entschlüsselung möglich.
Ich sehe das bezüglich Verschlüsselung so: Um einen Schlüssel zu bestimmen, ist eine große Anzahl von Daten nötig. Da aber in diesem Fall der Schlüssel größer ist, als der Key, bezweifle ich, dass eine Rekonstruktion möglich ist.

Edit: Natürlich kann man, wenn man weiß, dass dieser Algorithmus benutzt wurde, sich P einfach "zusammenbasteln". Aber das bringt einem nichts, da die Anwendung nur K als Eingabe erwartet. Und ohne den Schlüssel kommt man nicht auf K.
 
Zuletzt bearbeitet:
Hallo,

einen Teil von S in P zu speichern, halte ich für keine gute Idee. Ich vermute (!), dass das die Stärke der Verschlüsselung reduziert.

Stattdessen könntest du eine Prüfsumme o.ä. in P(3) speichern, wobei die Prüfsumme auch nur Daten von P(0-2) enthält und damit die Entropie reduziert. Im Endeffekt hast du so nur maximal (!! - ich vermute eher bedeutend weniger) 96 Bit an Informationen.

Gegen letzteren Punkt könntest du den Key vor der Verschlüsselung mit ungenutzten Zufallsdaten auffüllen - von mir aus jedes zweite Byte. Verlängert aber natürlich wieder den Schlüssel. Kommt also nur in Frage, wenn K auch länger als 128 Bit sein darf.

Interessante Daten für den Schlüssel wären z.B. auch noch:
- Lizenzerzeugungsdatum
- Ablaufdatum
- Für welches Produkt
- Für welchen Kunden
- Benutzer, der die Lizenz ausgestellt hat


Davon abgesehen, wenn du Rijndael einsetzt, wird sich niemand die Mühe machen die Verschlüsselung zu knacken sondern das Programm angreifen und S auslesen. Je nach dem groß du das aufziehen willst, solltest du wohl nicht zuuu viel Aufwand betreiben die Information zu verstecken, wenn S einfach im Programm auszulesen ist. Falls eine serverseitige Prüfung stattfindet und der Server nicht in Hand des Kunden ist, ist das natürlich wiederum kein Problem. Dann wäre allerdings die Stelle, die das entschlüsselte P verwertet, Angriffsziel.

Noch ein Punkt, ich hoffe du erzeugst gute Zufallszahlen - bzw. vermutlich Pseudozufallszahlen. Der C-PRNG (Pseudo Random Number Generator) ist für sowas absolut nicht geeignet. Google mit RNG oder PRNG bringt viele gute Treffer.
 
Zuletzt bearbeitet:
7H3 N4C3R schrieb:
Hallo,

einen Teil von S in P zu speichern, halte ich für keine gute Idee. Ich vermute (!), dass das die Stärke der Verschlüsselung reduziert.
Ich eben auch. :/

Stattdessen könntest du eine Prüfsumme o.ä. in P(3) speichern, wobei die Prüfsumme auch nur Daten von P(0-2) enthält und damit die Entropie reduziert. Im Endeffekt hast du so nur maximal (!! - ich vermute eher bedeutend weniger) 96 Bit an Informationen.
32 Bit Prüfsumme sind nun leider sehr schwach. Ich habe einen Teil von S für P
benutzt, um sicher zu gehen, dass der Benutzer auf jeden Fall P nicht komplett
kennen kann. Eine Prüfsumme wäre ja am Ende für jede Eingabe eindeutig und
vorausberechenbar.

Gegen letzteren Punkt könntest du den Key vor der Verschlüsselung mit ungenutzten Zufallsdaten auffüllen - von mir aus jedes zweite Byte. Verlängert aber natürlich wieder den Schlüssel. Kommt also nur in Frage, wenn K auch länger als 128 Bit sein darf.
Rijndael erlaubt Blockgrößen von allen Vielfachen von 32 Bit im bereich 128-256. Das
wäre also möglich. Nur je länger K wird desto unhandlicher wird es für den Benutzer.

Interessante Daten für den Schlüssel wären z.B. auch noch:
- Lizenzerzeugungsdatum
- Ablaufdatum
- Für welches Produkt
- Für welchen Kunden
- Benutzer, der die Lizenz ausgestellt hat
Lizenzerzeugungsdatum wurde ja schon als Beispiel genannt. Ablaufdatum ließe sich leicht
integrieren. Die Unterscheidung nach Produkt ließe sich durch ein individuelles S für jedes
Produkt/Version/Ausgabe etc. umsetzen.
Der Kunde ist in der aktuellen Version als UID in P enthalten. Der Aussteller der Lizenz wäre
natürlich interessant, wenn man Lizenzen von drittanbietern erteilen lässt.

Davon abgesehen, wenn du Rijndael einsetzt, wird sich niemand die Mühe machen die Verschlüsselung zu knacken sondern das Programm angreifen und S auslesen. Je nach dem groß du das aufziehen willst, solltest du wohl nicht zuuu viel Aufwand betreiben die Information zu verstecken, wenn S einfach im Programm auszulesen ist. Falls eine serverseitige Prüfung stattfindet und der Server nicht in Hand des Kunden ist, ist das natürlich wiederum kein Problem. Dann wäre allerdings die Stelle, die das entschlüsselte P verwertet, Angriffsziel.
Ich dachte dabei an einen Onlinedienst, der einen individuellen Client benötigt, der sich
dann eben per Key authentifiziert. Da läge S dann natürlich auf dem Lizenzserver.

Noch ein Punkt, ich hoffe du erzeugst gute Zufallszahlen - bzw. vermutlich Pseudozufallszahlen. Der C-PRNG (Pseudo Random Number Generator) ist für sowas absolut nicht geeignet. Google mit RNG oder PRNG bringt viele gute Treffer.
Für Testzwecke hab ich mir 16 Bytes aus /dev/random geholt. Das dürfte meinen
Anforderungen so genügen.
 
Wenn du davon ausgehst, dass S sowieso geheim ist, ist es doch vom Design her völlig egal, ob in P nun ein Teil von S oder eine Prüfsumme steht, da der Anwender (bzw. der Client) das dekodierte P doch sowieso nie zu Gesicht bekommt. Und selbst wenn, ist er durch fehlende Kenntnis von S nicht in der Lage, aus P's korrekte K's zu erzeugen um sich zu authentifizieren. Außerdem könnte man P(3) beim Retransfer an den Client einfach nicht mitschicken, falls P dort benötigt wird.

Im übrigen muss dann natürlich auch die Server-Verbindung verschlüsselt sein, da man sich sonst durch ein einfaches LD_PRELOAD vor die Anwendung hängen kann und die Server-Antwort faket. Und selbst dann muss man sich gegen Replay-Angriffe absichern.
 
Zurück
Oben