Mein Ver/Entschlüsseln - Eure Meinung

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
TroaX
Beiträge: 661
Registriert: 08.03.2013 14:27
Computerausstattung: PC: Ryzen 9 3950X, 96 GB RAM, RX6800XT, 2.5 TB SSD, 21:9 Display, Pop_OS! | Lappi: Ryzen 7 5800H, 16 GB RAM, 1 TB SSD, Pop_OS!
Wohnort: NRW
Kontaktdaten:

Re: Mein Ver/Entschlüsseln - Eure Meinung

Beitrag von TroaX »

BSP hat geschrieben:Guten morgen TroaX.
Ich habe nochmal nach den Begriffen gegoogelt, die Du so genannt hast.
(Hoffentlich habe ich das so halbwegs richtig verstanden).
Durch das anfügen eines Salt (ans Passwort) müssen ja weitere "Rainbow- Table" angelegt werden,
je länger der Salt, umso mehr Tabellen.
Siehe:
https://de.wikipedia.org/wiki/Rainbow_Table
Der technische Hintergrund einer Rainbow-Table macht deutlich, wie wichtig der Faktor Zeit ist. Genau dafür ist auch der Salt eine Gegenmaßnahme, da er die Passwörter verlängert. Wenn du einen Salt mit 12 Zeichen verwendest und minimal ab 8 Zeichen Passwörter benutzt, dann hat am Ende das Passwort garantiert 20 Zeichen und mehr. Das ist schon deutlich sicherer. Und genau deswegen kann auch der Salt gefahrlos gespeichert werden. Du kannst theoretisch auch in den Rainbowtables schauen, welche "Passwörter" mit dem Salt enden bzw. beginnen. Die Wahrscheinlichkeit, das du da welche findest ist recht gering. Und dann ist ja immernoch das eigentliche Passwort noch nicht ermittelt. Denn es gibt trotzdem noch so viele Kombinationsmöglichkeiten, das sich diese mit einem herkömmlichen Taschenrechner nicht errechnen lassen. Außerdem gibt es ja noch weitere Faktoren. Da wäre noch der Verschlüsselungsalgorithmus, Derivation Ja oder Nein und wenn ja, zu welchen Kosten, Bit-Tiefe. Für jeden dieser Eigenschaften benötigt man wieder zusätzliche Tabellen. Bei einem variablen Kostenfaktor ist in den allermeisten Fällen auszuschließen, das es überhaupt eine Rainbow-Table gibt (zumal allein das Anlegen einer solchen Tabelle vollkommen unwirtschaftlich ist = Unverhältnismäßig hohe Rechenzeit).

Was die Passwortlänge angeht sollte man aber aufpassen, vom Nutzer nicht zu viel zu verlangen. Er kann sich gerne ein kurzes Passwort nehmen, wenn er will. Es sollte nur eben minimum eine bestimmte Zeichenlänge haben, die aber nicht zu hoch sein darf. In der Regel finden Leute bei 8 oder 10 Zeichen eigentlich immer ein Passwort. Das Ende (also die Maximalanzahl an Zeichen) darf aber hoch liegen (64 und mehr Zeichen), um den Leuten auch die Möglichkeit zu geben, lange Passwörter zu verwenden. Aber auch hier muss eine Grenze stehen. Ein Byte hat 256 verschiedene Werte und ein Hash hat 32 Byte. Wenn Passwörter nur aus A-Z, a-z, 0-9 und vielleicht 10 Sonderzeichen, sind das 72 Zeichen. Das bedeutet, das ein Passwort maximal 113 Zeichen (256 / 72 * 32) haben sollte. Der Grund dafür ist, das sich in der Theorie die Kollisionswahrscheinlichkeit bei Zeichenketten ab der Länge erhöhen muss, da der Speicher von 32 Byte nicht mehr ausreicht. Ab der Länge dürfte also die Wahrscheinlichkeit höher liegen, das 2 Strings den gleichen Hash erzeugen, als darunter. Das ist zwar nur eine Milchmädchenrechnung. Aber damit fährt man auf der sicheren Seite. Und ich habe auch nie jemanden gesehen, der solch lange Passwörter nutzt. 64 sollten also reichen.
BSP hat geschrieben:Nun wurde dort auch vom "Pfeffern" gesprochen.
Wird also durch das zerlegen des Salt durch die Quersumme meines Passwortes nicht ein "Pfeffer" statt "Salt"?
Wenn auch nur ein schwacher Pfeffer, denn ganz unbekannt wird der Salt ja nicht, nur vervielfacht.
(Pi mal Auge ums 64 fache, je nach Umfang der erlaubten Zeichen ? (Aa..., 123...usw.))
Oder stellt bereits das bilden der Quersumme eine Gefahr dar?
Beispiel 2 Zeichen: (4 + 4) / 2 = (1 + 7) / 2 = (3 + 5) / 2 usw.
Du darfst nicht vergessen, das sich dieser Artikel überwiegend auf die Webentwicklung bezieht. Zwischen Pepper und Salt wird hier also an Hand des Speicherorts unterschieden. Webanwendungen nutzt im Regelfall Datenbanken, auf denen (wenn sicher konfiguriert niemand außer der Admin Zugriff hat). Der Pepper soll hier also dann eher in einer Datei vorrangig außerhalb des Document-Roots gespeichert werden (auf die, wenn sicher konfiguriert, auch nur der Admin Zugriff hat). Bei einem solchen Tool ist es was anderes. Es ist vollkommen egal, wo du was speicherst. Man findet es immer! Zum Beispiel mit dem Tool ProcessMonitor kannst du alle Systemaktivitäten eines Programms mitschreiben. Zugriff auf Dateien (und welche), Zugriff auf die Registry (und welche Schlüssel) etc. Da muss man nicht einmal ein Cracker sein, um das zu ermitteln. Es gibt also an sich keinen Pepper. Deswegen versuche ich, mit "meinen" Peppern die Rechenzeit künstlich zu erhöhen, in dem ich sie als eine Art Dictonary verwende. Deswegen kam ja auch der Vorschlag mit den verschiedenen Vektoren, die durchprobiert werden, bis die Entschlüsselung funktioniert.

Und löse dich bitte davon, aus bestehenden Daten neue zu errechnen. Das geht zu 99 % in die Hose. Denke immer an den Mathe-Unterricht. Für jede arithmetische Gleichung gibt es immer eine Gegenrechnung und wenn es diese nicht gibt, dann lassen sich trotzdem die Zahlen eingrenzen. Wenn du zum Beispiel aus den ASCII-Werten eines Passwortes einen Salt errechnest, besteht dieser Streng genommen aus Zahlen. Nach dem deassamblieren deines Codes kann ein Angreifer sehen was du da rechnest und findet auch einen Weg, diesen zu brechen. Aus diesem Grund versuche ich seit X Beiträgen dir schon klar zu machen, das du das Passwort nimmst, einen zufälligen Salt generierst, diese einfach nur hintereinander hängst und dann am besten mit einer Derivation (im Wiki-Artikel zur Rainbow-Table als Iterationen bezeichnet) so oft, wie es die Dicke des Fells der Nutzer zulässt, zu hashen. Die Anzahl der Runden, die du dynamisch zufällig auswählst sowie den Salt speicherst du. Beim Vektor fragst du einfach nach einem Benutzernamen (bei dem aber ein einfacher SHA3-256 reicht) oder zeuchst mehrere zufällig und probierst sie einfach beim entschlüsseln durch. Aber versuche niemals, selber die Daten zu verrechnen. Das macht es am Ende nur noch schlimmer. Es sei denn du bist Professor in angewandter oder diskretter Mathematik mit Fachbereich Kryptografie und hast diesen Titel auch schon etliche Jahre. Aber in diesem Fall würde ich deutlich umfangreichere Algorithmen erwarten. Nur dann wäre der Algorithmus proprietär und das hat zusätzliche Nachteile.
BSP hat geschrieben:PS. Ich grüble schon die ganze Zeit über einen weiteren Punkt nach. Aber meine Gedanken verknoten sich langsam.
An einer Stelle in meinem Verschlüsselungslauf greife ich ja einen Wert ab,
den ich dann mit dem Salt verbinde und so zum bilden des AESIni verwende.
Stellt nicht gerade dieses abgreifen eine Tür dar?
Der Vektor wird aus gutem Grund Vektor genannt. Er selbst stellt in der Kryptografie eine Art Initialwert dar und sollte auch als solcher angesehen werden. Du allerdings setzt den Vektor mit dem Schlüssel gleich. In der Theorie kann man das zwar machen. Allerdings ist er für AES-256, egal wie du ihn siehst, nur ein Initialwert. Wie du damit umgehen kannst, hatte ich ja schon erklärt. Mehr brauchst du nicht. Man benötigt beide, um zu verschlüsseln oder zu entschlüsseln. Aber es reicht, nur einen vernünftig abzusichern. Und das sollte der Schlüssel sein. Ich habe den Algorithmus jetzt nicht im Kopf und mir fehlt die Zeit, zu schauen. Aber es kann durchaus sein, das viele unterschiedliche Vektoren zum gleichen Ergebnis führen können (je nach Formeln). Aber beim Schlüssel ist das definitiv nicht der Fall. Denn dafür ist der Algorithmus entwickelt worden und deswegen wird der Parameter als Schlüssel bezeichnet. Und der ist der deutlich wichtigere von beiden.
PC: Ryzen 9 3950X | 96 GB RAM | RX6800XT | 2,5 TB NVMe | Pop_OS!
Notebook: 16" 3:2 | Ryzen 7 5800H | 16 GB RAM | Radeon Vega | 1TB NVMe | Pop_OS!
NAS: Fritz.Box :lol:
Coding: Purebasic 6.04 | PHP | HTML | CSS | Javascript
BSP
Beiträge: 188
Registriert: 01.02.2009 14:04

Re: Mein Ver/Entschlüsseln - Eure Meinung

Beitrag von BSP »

Hallo TroaX.
Ich schulde Dir ja noch eine Antwort.
Ich habe nun noch ausprobiert und viel gelesen.
Und muss erkennen, es macht wirklich keinen Sinn, das Passwort selber noch zum verbiegen zu benutzen.
Ich mach's nun also wie ein Koch. Passwort salzen, ordentlich rumrühren und das Ergebnis mit AES weiter verarbeiten.
Ich hatte überlegt, egal wie oft ich etwas herum rühre, es kommen ja immer 32 Byte dabei heraus.
32 Byte? Das hielt ich bei der heutigen Technik für einen Klacks. Aber das war wohl etwas Überschätzung.
Man muss schon einen enormen Aufwand, auch technischer Art betreiben, um 32 Byte zu knacken.
Da beißt sich scheinbar sogar die NSA die Zähne aus. Noch. Aber sie arbeitet ja daran. Grins.
Allerdings, als Firma, wo es um mehr geht, (Aufträge, Patentschutz, viel viel Geld), wäre ich schon misstrauischer.
Aber da würde ich sowieso Profis holen.
Und die Grundregeln beachten, die für ALLE gelten.
Keine unbekannten E-Mail- Anhänge öffnen, traue keinen gefundenen USB- Stick, nicht mal dem eines Freundes,
Antivieren Software aktuell halten. Usw. Und das Passwort lang genug machen.
8 Zeichen sollten es bei 96 Byte Zeichentiefe min. sein.

Na ja, was soll ich noch sagen? Wäre nun alles nur noch "neunmalkluges" Gerede.
Also belasse ich es dabei und Danke Dir für Deine Mühe und Geduld.
MfG: Bernd

PS. Hier noch der Code: Lässt sich noch optimieren, aber Ihr sollt ja auch was zu tun haben. Smile.

Code: Alles auswählen


UseSHA3Fingerprint()


Procedure.s HexToStr(hex$, w = 2)
  ; w gibt die Länge/Weite des Hex an. Bsp: $FF , $FFFF , $FFFFFF
  Protected str$, i
  For i = 0 To Len(hex$) / w - 1
    str$ + Chr(Val("$" + Mid(hex$, 1+i*w, w)))
  Next
  ProcedureReturn str$
EndProcedure

Procedure.s StrToHex(str$, w = 2)
  ; w gibt die Länge/Weite des Hex an. Bsp: $FF , $FFFF , $FFFFFF
  Protected hex$, i
  For i = 1 To Len(str$)
    hex$ + RSet(Hex(Asc(Mid(str$, i, 1))), w, "0")
  Next
  ProcedureReturn hex$
EndProcedure

Procedure.s Create_RndStr(w, bis, von)
  For i = 1 To w
    s$ + Chr(Random(bis, von))
  Next
  ProcedureReturn s$
EndProcedure

;-

Procedure.s EnAES(String$, Key$, ini$)
  If key$ = "" : ProcedureReturn String$ : EndIf
  
  Protected *CipheredString
 
  While Len(String$) < 16
    String$+Chr(10)
  Wend

  *CipheredString   = AllocateMemory(StringByteLength(String$))
  
  Key$ = HexToStr(Key$);LSet(Key$, 32, Chr(32))
  ini$ = HexToStr(ini$);LSet(ini$, 16, Chr(32))
  
  If AESEncoder(@String$, *CipheredString, StringByteLength(String$), @Key$, 256, @ini$);?Init)
    For n = 0 To Len(String$)-1
      Output$ + Str(PeekC(*CipheredString+n*SizeOf(Character))) + " "
    Next
  EndIf

  FreeMemory(*CipheredString)

  ProcedureReturn Output$
 
EndProcedure

Procedure.s DeAES(String$, Key$, ini$)
  If key$ = "" : ProcedureReturn String$ : EndIf
  
  Protected *Buffer = AllocateMemory(CountString(String$," ")*SizeOf(Character))
  Protected *DecipheredString = AllocateMemory(CountString(String$," ")*SizeOf(Character))
 
  For n = 0 To CountString(String$," ")-1
    PokeC(*Buffer+n*SizeOf(Character), Val(StringField(String$, n+1, " ")))
  Next
  
  Key$ = HexToStr(Key$);LSet(Key$, 32, Chr(32))
  ini$ = HexToStr(ini$);LSet(ini$, 16, Chr(32))
  
  If AESDecoder(*Buffer, *DecipheredString, MemorySize(*Buffer), @Key$, 256, @ini$);?Init)
    Output$ = RTrim(PeekS(*DecipheredString, CountString(String$," ")), Chr(10))
  EndIf

  FreeMemory(*DecipheredString)
  FreeMemory(*Buffer)

  ProcedureReturn Output$
EndProcedure

;-

Procedure.s Create_CryptStr(w)
  *Key = AllocateMemory(w)
  If OpenCryptRandom() And *Key
    CryptRandomData(*Key, w)
    For i = 0 To w-1
      a$ + RSet(Hex(PeekB(*Key+i), #PB_Byte), 2, "0")
    Next i     
    CloseCryptRandom()
  EndIf
  FreeMemory(*Key)
  ProcedureReturn a$
EndProcedure
  
Procedure.s Passwort_Eingeben()
  pw$ = "Passwort"
  ProcedureReturn pw$
EndProcedure


Procedure  Schluessel_pruefen(passwort$, salz$, lauf, AESIni$, kontrollstr$)
  ;lauf = 100000
  
  AESKey$ = passwort$ + salz$
  
  For i = 1 To lauf
    AESKey$ = StringFingerprint(AESKey$, #PB_Cipher_SHA3, 256)
  Next
  klartext$ = DeAES(kontrollstr$, AESKey$, AESIni$)
  a$ = StringField(klartext$, 1, "|")
  b$ = StringField(klartext$, 2, "|")
  If StringFingerprint(a$, #PB_Cipher_SHA3, 512) = b$
    ProcedureReturn 1
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure.s Erzeuge_Schluessel(passwort$)
  Protected schluessel$
  lauf = 200000
  salz$   = Create_CryptStr(32)
  AESKey$ = passwort$ + salz$
  AESIni$ = Create_CryptStr(16)
  
  For i = 1 To lauf
    AESKey$ = StringFingerprint(AESKey$, #PB_Cipher_SHA3, 256)
  Next
  
  a$ = StrToHex(Create_RndStr(128, 255, 1), 2)
  kontrollstring$ = a$ + "|" + StringFingerprint(a$, #PB_Cipher_SHA3, 512)
  kontrollstring$ = EnAES(kontrollstring$, AESKey$, AESIni$)
  
  schluessel$ = Str(lauf) + ":" + salz$ + ":" +AESKey$ + ":" + AESIni$ + ":" + kontrollstring$
  
  ProcedureReturn schluessel$
EndProcedure


; -------------------------------------------------------------------------------------------------

passwort$ = Passwort_Eingeben()

schluessel$ = Erzeuge_Schluessel(passwort$)
Debug schluessel$
lauf     = Val(StringField(schluessel$, 1, ":"))
salz$        = StringField(schluessel$, 2, ":")
AESKey$      = StringField(schluessel$, 3, ":")
AESIni$      = StringField(schluessel$, 4, ":")
kontrollstr$ = StringField(schluessel$, 5, ":")
Debug "   w = " + lauf
Debug "Salz = " + salz$
Debug " Key = " + AESKey$
Debug " Ini = " + AESIni$
Debug " Kon = " + kontrollstr$
; --- Nun "lauf, Salz, Ini, Kontrollstr" speichern
salz$ = (salz$)
; speichern()

; ---

; --- Bei Start des Prgs.
; laden()
salz$ = (salz$)
passwort$ = InputRequester("", "", passwort$)
If Schluessel_pruefen(passwort$, salz$, lauf, AESIni$, kontrollstr$)
  Debug "Ok"
Else
  Debug "Falsch"
EndIf
PB 5.31 (x86) & (x64) Win10
Antworten