[Modul] cmCipher : PureAES Ersatz

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
Bisonte
Beiträge: 2465
Registriert: 01.04.2007 20:18

[Modul] cmCipher : PureAES Ersatz

Beitrag von Bisonte »

Hallo....

Ich hab mich mal daran versucht, die PureAES UserLibrary von Gnozal aus dem engl. Forum in ein Modul
zu verfrachten, da seit PB 5.0 keine Updates mehr von ihm kamen.
Es ist natürlich nicht sein Originaler Code, und es ist mein erster Gehversuch in Sachen AES...

Momentan besteht dieses Modul aus 2 Funktionen.
AES_Encrypt() verschlüsselt einen Speicherblock per AES 256 und
AES_Decrypt() entschlüsselt ihn wieder.

Verbesserungsvorschläge und/oder Kritik ? Immer her damit ;)

Eventuell erweitere ich das ganze noch ... (oder wir alle zusammen!)
  • V0.002
  • Der MD5 - "EncryptionKey" - auf ASCII festgesetzt
  • Die Berechnung des EncryptionKeys in Prozedur ausgelagert
Hier der Code inklusive Beispiel :

Code: Alles auswählen

DeclareModule cmCipher
  
  ;:- common module Cipher
  ;:--------------------------------------------------------------------------
  ;:- Author  : George Bisonte
  ;:- Date    : 20. February 2014
  ;:- PB      : 5.21
  ;:- OS      : Windows/Linux/MacOS
  ;:-           Use it at your own risk
  ;:--------------------------------------------------------------------------
  ;:- V0.002  : EncryptionKey fixed to ASCII
  ;:- V0.001  : Try to replace the PureAES Userlibrary 
  ;:--------------------------------------------------------------------------
  
  ; Original PureAES (by gnozal) Syntax (compatibility)
  Declare PureAES_Encrypt(*Buffer, Dummy, EncryptionKey.s)
  Declare PureAES_Decrypt(*Buffer, Dummy, EncryptionKey.s)
  
  ; Needed Syntax
  Declare AES_Encrypt(*Buffer, EncryptionKey.s)
  Declare AES_Decrypt(*Buffer, EncryptionKey.s)
  
EndDeclareModule
Module cmCipher
  
  ;:--------------------------------------------------------------------------
  ;:- Author  : George Bisonte
  ;:- Date    : 20. February 2014
  ;:- PB      : 5.21 x86/x64
  ;:- OS      : Windows/Linux/MacOS
  ;:-           Use it at your own risk
  ;:--------------------------------------------------------------------------
  
  EnableExplicit
  
  Procedure AES_AsciiKey(EncryptionKey.s)
    
    Protected *Key = AllocateMemory(32)
    
    If Not *Key : ProcedureReturn #False : EndIf
    EncryptionKey = MD5Fingerprint(@EncryptionKey, StringByteLength(EncryptionKey, #PB_Ascii))  
    PokeS(*Key, EncryptionKey, 32, #PB_Ascii)
    
    ProcedureReturn *Key
    
  EndProcedure
  
  Procedure AES_Encrypt(*Buffer, EncryptionKey.s)
    
    Protected Result = #False
    Protected *IVector, *Input, *Output, Size
    Protected *Key = AES_AsciiKey(EncryptionKey)
    
    If *Key
      OpenCryptRandom()
      If *Buffer
        Size = MemorySize(*Buffer)
        If Size < 32 : Size = 32 : EndIf
        *Input = AllocateMemory(Size)
        If *Input
          CopyMemory(*Buffer, *Input, Size)
          *IVector = AllocateMemory(32)
          If *IVector
            CryptRandomData(*IVector, 32)
            *Output = AllocateMemory(Size + 32)
            If *Output
              CopyMemory(*IVector, *Output, 32)
              If AESEncoder(*Input, *Output + 32, Size, *Key, 256, *IVector, #PB_Cipher_CBC)
                Result = *Output
              Else
                FreeMemory(*Output)
              EndIf
            EndIf
            FreeMemory(*IVector)
          EndIf
          FreeMemory(*Input)
        EndIf
      EndIf
      
      CloseCryptRandom()
      FreeMemory(*Key)
      
    EndIf
    
    ProcedureReturn Result
    
  EndProcedure  
  Procedure AES_Decrypt(*Buffer, EncryptionKey.s)
    
    Protected Result = #False
    Protected Size, *IVector, *Output
    Protected *Key = AES_AsciiKey(EncryptionKey)
        
    If *Key
      If *Buffer
        Size = MemorySize(*Buffer)
        *IVector = AllocateMemory(32)
        If *IVector
          CopyMemory(*Buffer, *IVector, 32)
          *Output = AllocateMemory(Size - 32)
          If *Output
            If AESDecoder(*Buffer + 32, *Output, Size - 32, *Key, 256, *IVector, #PB_Cipher_CBC )
              Result = *Output
            Else
              FreeMemory(*Output)
            EndIf
          EndIf
          FreeMemory(*IVector)
        EndIf
      EndIf
      FreeMemory(*Key)
    EndIf
    
    ProcedureReturn Result
    
  EndProcedure
  
  Procedure PureAES_Encrypt(*Buffer, Dummy, EncryptionKey.s)
    ProcedureReturn AES_Encrypt(*Buffer, EncryptionKey)
  EndProcedure
  Procedure PureAES_Decrypt(*Buffer, Dummy, EncryptionKey.s)
    ProcedureReturn AES_Decrypt(*Buffer, EncryptionKey)
  EndProcedure
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  EnableExplicit
    
  Define InFile.s, OutFile.s
  Define AESKey.s = "MyKey" ; <- The Key to encode and decode the data
  
  Procedure AESCrypt(SourceFile.s, DestinationFile.s, Key.s, Mode = #False)
    
    Protected fHnd, *File, *Memory, Result = #False
    
    fHnd = ReadFile(#PB_Any, SourceFile) ; <- Read   
    If fHnd
      *File = AllocateMemory(Lof(fHnd))
      If *File
        ReadData(fHnd, *File, Lof(fHnd))
      EndIf
      CloseFile(fHnd)
    EndIf
    
    If *File
      If Mode = #False
        *Memory = cmCipher::AES_Encrypt(*File, Key)
      Else
        *Memory = cmCipher::AES_Decrypt(*File, Key)
      EndIf
      FreeMemory(*File)
    EndIf
    
    If *Memory
      fHnd = CreateFile(#PB_Any, DestinationFile)
      If fHnd
        WriteData(fHnd, *Memory, MemorySize(*Memory))
        CloseFile(fHnd)
        Result = #True  
      EndIf
      FreeMemory(*Memory)   
    EndIf
    
    ProcedureReturn Result
    
  EndProcedure
  
  InFile = OpenFileRequester("Encode : Select an inputfile", "", "", 0)
  If InFile <> ""
    OutFile = OpenFileRequester("Encode : Select an outputfile", "", "", 0)
    If OutFile <> ""
      AESCrypt(InFile, OutFile, AESKey, 0)
    EndIf
  EndIf
  
  InFile = OpenFileRequester("Decode : Select an inputfile", "", "", 0)
  If InFile <> ""
    OutFile = OpenFileRequester("Decode : Select an outputfile", "", "", 0)
    If OutFile <> ""
      AESCrypt(InFile, OutFile, AESKey, 1)
    EndIf
  EndIf  
  
CompilerEndIf
Zuletzt geändert von Bisonte am 21.02.2014 13:10, insgesamt 1-mal geändert.
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: [Modul] cmCipher : PureAES Ersatz

Beitrag von STARGÅTE »

Kannst du kurz erklären, warum du den Initialisierungsvektor mit in den Buffer schreibst?
Macht das nicht den eigentlichen Sinn kaputt, das ein Hacker eben nicht weiß, welcher Anfangsvektor für die Verschlüsselung genutzt wurde?
Ich meine selbst CryptRandomData() erscheint mir dann quatsch, wenn du die Zahl "im Klartext" am Anfang des Buffer schreibst, da könnte man genauso eine Zufallszahl von Random() verwenden, oder halt garkein Initialisierungsvektor.

Das andere wäre der MD5 vom Passwort.

Code: Alles auswählen

MD5Fingerprint(@EncryptionKey, StringByteLength(EncryptionKey))
Hier gibts Probleme (verschiedene MD5), wenn du das Passwort mit Unicode oder Ascii erzeugst.
Hier vielleicht erst mit PokeS() einen Unicode String erzeugen und dann MD5 anwenden.

Gleiches gilt für das Resultet von MD5:

Code: Alles auswählen

AESEncoder(*Input, *Output + 32, Size, @EncryptionKey, 256, *IVector, #PB_Cipher_CBC)
EncryptionKey kann ja entweder 32 Byte oder 64 Byte haben unter Unicode ...
Dort den MD5 dann erst in Ascii umwandeln. Sonst nutzt er nur die erste hälfte vom MD5
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
Bisonte
Beiträge: 2465
Registriert: 01.04.2007 20:18

Re: [Modul] cmCipher : PureAES Ersatz

Beitrag von Bisonte »

Das mit dem Initialisierungsfaktor ist einfach erklärt... In der Hilfe zu AES steht, dass man den gleichen Vektor
benutzen muss, wie beim verschlüsseln. Und dann ist natürlich die Frage, wie geb ich den mit ?
Kann man denn dann die Verschluesselung so einfach knacken, wenn man den kennt ?

Wo Du Recht hast, hast Du Recht. Das mit dem Unicode und Ascii hab ich natürlich mal wieder voll verpennt.
Da muss ich gleich nachbessern...
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: [Modul] cmCipher : PureAES Ersatz

Beitrag von STARGÅTE »

Bisonte hat geschrieben:Und dann ist natürlich die Frage, wie geb ich den mit ?
Ich würde ihn zB ähnlich wie das Passwort übergeben. Kann ja auch n String sein, der dann mit MD5 zu einem Vektor wird.
Bisonte hat geschrieben:Kann man denn dann die Verschluesselung so einfach knacken, wenn man den kennt ?
Natürlich nicht. So oder so braucht man das Passwort um den Speicher zu dekodieren.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Christian+
Beiträge: 213
Registriert: 13.07.2008 10:05
Computerausstattung: Windows 8.1 Pro
AMD Phenom II X4 955 @ 3.2 GHz
4GB RAM
NVIDIA GeForce GTX 660

Re: [Modul] cmCipher : PureAES Ersatz

Beitrag von Christian+ »

Den Initialisierungsvektor kannst du problemlos einfach davor schrieben das beeinträchtigt die Sicherheit nicht.
AES verschlüsselt in Blöcken von 16 Byte für jeden Block dient dabei der Block davor als Initialisierungsvektor.
Da der erste Block aber keinen vorherigen hat verwendet man da den Initialisierungsvektor.

Der Sinn eines guten Initialisierungsvektors ist, dass ein gleicher Text verschlüsselt mit dem gleichen Password niemals den gleichen Geheimtext ergibt, denn das würde Angriffsmöglichkeiten bieten.
Das gilt auch auf Ebene der 16 Byte Blocke. Im CBC Modus werden auch gleiche 16 Byte zu einen verschieden Geheimtext, da jeder 16 Byte Block einen anderen Initialisierungsvektor (=den Block zuvor) hat. Somit ist es erheblich sicherer als der ECB Modus bei dem die gleichen 16 Byte auch immer zum selben Geheimtext werden.

Du kannst sehr leicht testen wie Unbedeutend es ist ob du den Initialisierungsvektor kennst oder nicht. Kommentiere in der der Decrypt Methode einfach das CopyMemory(*Buffer, *IVector, 32) aus. (Alternativ kannst du auch das CopyMemory(*IVector, *Output, 32) im Encrypt auskommentieren)
Wie du dann siehst, wird außer dem ersten 16 Byte Block für den der Initialisierungsvektor gilt immer noch alles richtig entschlüsselt und ob dieser bekannt ist oder nicht hat wenig Relevanz.
Das bedeutet die ersten 16 Byte kannst du egal ob sie der Initialisierungsvektor sind oder nicht einfach als Initialisierungsvektor verwenden, denn sie sind auf jeden Fall der IV für den nächsten 16 Byte Block. Das einzige Problem ist, dass falls keiner davor stand du 16 Byte vom Verschlüsselten Inhalt abgeschnitten hast.

Die Sicherheit ist also einzig und allein davon Abhängig, ob ein gutes Password als Key verwendet wird.
Windows 8.1 Pro 64Bit | AMD Phenom II X4 955 @ 3.2 GHz | 4GB RAM | NVIDIA GeForce GTX 660
walbus
Beiträge: 137
Registriert: 03.03.2013 20:50

Re: [Modul] cmCipher : PureAES Ersatz

Beitrag von walbus »

:)
Zuletzt geändert von walbus am 07.02.2015 22:55, insgesamt 5-mal geändert.
Benutzeravatar
Bisonte
Beiträge: 2465
Registriert: 01.04.2007 20:18

Re: [Modul] cmCipher : PureAES Ersatz

Beitrag von Bisonte »

Den Vektor vornedran kann ich also so belassen, wenn ich das richtig verstanden habe...

Den MD5 Fingerprint hab ich nun auf ASCII festgesetzt (PokeS und #PB_ASCII), das sollte nun kein Problem mehr sein.

Das einzige ist natürlich, dass mit einem Unicode Kompilat kein Ascii verschlüsseltes File entschlüsselt werden kann und umgekehrt.
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: [Modul] cmCipher : PureAES Ersatz

Beitrag von STARGÅTE »

Bisonte hat geschrieben:as einzige ist natürlich, dass mit einem Unicode Kompilat kein Ascii verschlüsseltes File entschlüsselt werden kann und umgekehrt.
Das File ist dabei ja egal.
Wichtig ist nur, dass unter Unicode das Passwort den gleichen MD5 bekommt, wie unter Ascii. Dann ist auch das CompilerFormat egal.
Da Passwörter ja u.u. auch Unicodezeichen haben können, würde ich also das Passwort immer in Unicode oder UTF8 umwandeln, dann den MD5 bilden und den dann als Ascii (32 Byte) abspeichern.

Und bitte PokeS aufpassen, das bei 32 Zeichen immer noch das 33. Zeichen (NULL) mit in den Speicher geschrieben wird, du also nicht 32 Byte reservieren musst, sondern 33.

Ohne getestet zu haben:

Code: Alles auswählen

Procedure.i AES_AsciiKey(EncryptionKey.s)
  
  Protected *Unicode = AllocateMemory(StringByteLength(EncryptionKey, #PB_UTF8)+1)
  Protected *Key = AllocateMemory(32+1)
  
  If *Unicode And *Key
    PokeS(*Unicode, EncryptionKey, #PB_Default, #PB_UTF8)
    PokeS(*Key, MD5Fingerprint(*Unicode, StringByteLength(EncryptionKey, #PB_UTF8)), 32, #PB_Ascii)
    FreeMemory(*Unicode)
    ProcedureReturn *Key
  EndIf
  
EndProcedure
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Antworten