PB kompatibles AES-Padding

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
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

PB kompatibles AES-Padding

Beitrag von Helle »

Sinn dieses Codes ist es, anstelle der PB-AES-Funktionen (rel. langsam) eigene Routinen verwenden zu können; ich denke da natürlich an AES-NI halbwegs moderner CPUs (schneller!).
Also mit PB erstellte AES-Verschlüsselung mit der eigenen Routine entschlüsseln zu können und umgekehrt.
Ein riesiger Stolperstein ist da üblicherweise ein Input, dessen Byte-Länge kein Vielfaches von 16 ist (AES=16-Byte-Blockcipher). Mittels sog. Padding wird (intern) dieses Auffüllen auf ein Vielfaches von 16 Bytes durchgeführt.
Das von PB verwendete Verfahren wird hier gezeigt; Stichwort ist z.B. Ciphertext Stealing.
In nachfolgendem Code können die PB-Funktionen AESEncoder und AESDecoder dann durch eigene (hoffentlich) schnellere Routinen ersetzt werden. Und zwar in "Rein-Form", also ohne jegliche eigene Padding-Versuche und x-beliebig großem Input. PB kann dann etwas damit anfangen.
Nebenbei zeigt es natürlich auch, wie PB das Padding ausführt (falls jemand neugierig ist).

Code: Alles auswählen

;EBC und CBC, KeySize 128/192/256 Bit; man kann auch ein Menü erstellen...
;Debugger einschalten! Sonst sieht man so wenig...

;Cipher = #PB_Cipher_ECB : Cipher$ = "ECB"   ;ECB in PB: InitializationVector wird ignoriert und ist nur ein Platzhalter!
;oder
Cipher = #PB_Cipher_CBC : Cipher$ = "CBC"
KeySize = 128 ;oder 192 oder 256
              ;in dieser Spalte stehen "nur" Infos/Ergebnisse, für Ausgabe-Strings kann schon mal ein Zero-Byte für ein abruptes Ende sorgen ;-) 
              Debug "E N C R Y P T I O N :"
              TestMode$ = Cipher$ + ", KeySize " + Str(KeySize) + " Bit"
              Debug "TestMode: " + TestMode$
String$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ Hello this is a test for AES 1234567890" ;Input kann sonstwas sein
              Debug "TestString: " + String$
InputLen = Len(String$)
              Debug "Input-Len: " + Str(InputLen)
;If InputLen < 16....  Siehe PB-Hilfe; erweitern mit Leerzeichen

CompilerIf #PB_Compiler_Unicode
  StringA = AllocateMemory(InputLen, #PB_Memory_NoClear)
  j = 0
  For i = 0 To InputLen - 1
    PokeA(StringA + i, PeekA(@String$ + j))
    j + 2
  Next
 CompilerElse
  StringA = @String$
CompilerEndIf

              For i = 0 To InputLen - 1
                InputBytes$ + RSet(Hex(PeekA(StringA + i)), 2, "0") + " "
              Next
              Debug "InputBytes: " + InputBytes$
              Debug "================================================================================"
              Debug "PureBasic:"    ;für Test/Vergleich
              *CipheredStringPB   = AllocateMemory(InputLen + 1)     ;mit 1 Zero_Byte (ASCII)
              *DecipheredStringPB = AllocateMemory(InputLen + 1)     ;mit 1 Zero_Byte (ASCII)
              AESEncoder(StringA, *CipheredStringPB, InputLen, ?Key, KeySize, ?InitializationVector, Cipher)
              For i = 0 To Len(String$) - 1
                StrHexPB$ + RSet(Hex(PeekA(*CipheredStringPB + i)), 2, "0") + " "
              Next
              Debug "Ciphered as Bytes: " + StrHexPB$
              AESDecoder(*CipheredStringPB, *DecipheredStringPB, InputLen, ?Key, KeySize, ?InitializationVector, Cipher)
              Debug "Deciphered: " + PeekS(*DecipheredStringPB, -1, #PB_Ascii)
              Debug "================================================================================"

              Debug "Encryption:"
*CipheredStringEC   = AllocateMemory(InputLen + 1)    ;mit 1 Zero_Byte (ASCII)
*DecipheredStringEC = AllocateMemory(InputLen + 1)    ;mit 1 Zero_Byte (ASCII)
Blocks16 = InputLen >> 4     ;/16
AESEncoder(StringA, *CipheredStringEC, 16 * Blocks16, ?Key, KeySize, ?InitializationVector, Cipher)
LenPad = 16 - (InputLen % 16)

If (LenPad % 16) > 0              ;Padding Encryption
  AddrPad = 16 * (Blocks16 - 1)   ;Adresse der letzten/einzigen 2 Blocks (1x16 Bytes, 1x16-LenPad)
              Debug "Number Blocks16: " + Str(Blocks16)
              Debug "Number Padding Bytes: " + Str(LenPad)
              For i = 0 To LenPad - 1
                PaddingBytesEC$ + RSet(Hex(PeekA(*CipheredStringEC + i + AddrPad + 16 - LenPad)), 2, "0") + " "
              Next
              Debug "Encryption Padding-Bytes: " + PaddingBytesEC$
              Debug "------------------------------------------------------------"
              For i = 0 To (16 * Blocks16) - 1
                StrHexLBM1$ + RSet(Hex(PeekA(*CipheredStringEC + i)), 2, "0") + " "
              Next
              Debug "Ciphered before Last Block: " + StrHexLBM1$
              Debug "------------------------------------------------------------"

  For i = 0 To 15 - LenPad 
    PA.a = PeekA(*CipheredStringEC + i + AddrPad)
    PokeA(*CipheredStringEC + 16 + i + AddrPad, PA)
              HexStrLB$ + RSet(Hex(PA), 2, "0") + " "
  Next
              Debug "Fill Last Block, ready: " + HexStrLB$
              Debug "------------------------------------------------------------"

  If Cipher = #PB_Cipher_CBC
    LastIVEC = AllocateMemory(16)   ;letzter InitializationVector
    CopyMemory(*CipheredStringEC + AddrPad, LastIVEC, 16 - LenPad)
              For i = 0 To 15
                IVLB$ + RSet(Hex(PeekA(LastIVEC + i)), 2, "0") + " "
              Next
              Debug "InitializationVector Last Block: " + IVLB$
              Debug "------------------------------------------------------------"
  EndIf

  BufferEC = AllocateMemory(16)
  CopyMemory(StringA + 16 + AddrPad, BufferEC, 16 - LenPad)
  CopyMemory(*CipheredStringEC + 16 + AddrPad - LenPad, BufferEC + 16 - LenPad, LenPad)
              For i = 0 To 15
                NewLBM1$ + RSet(Hex(PeekA(BufferEC + i)), 2, "0") + " "
              Next
              Debug "New Last Block16 before new encryption: " + NewLBM1$
              Debug "------------------------------------------------------------"
              Debug "Done:"
  AESEncoder(BufferEC, *CipheredStringEC + AddrPad, 16, ?Key, KeySize, LastIVEC, Cipher)     ;für ECB wird LastIVEC ignoriert
EndIf                        ;Padding Encryption

              For i = 0 To InputLen - 1
                StrOutEC$ + RSet(Hex(PeekA(*CipheredStringEC + i)), 2, "0") + " "
              Next
              Debug "Encryption Ciphered as Bytes: " + StrOutEC$
              ;Test
              Debug "PureBasic Ciphered as Bytes: " + StrHexPB$   ;nur für Vergleich
              AESDecoder(*CipheredStringEC, *DecipheredStringEC, InputLen, ?Key, KeySize, ?InitializationVector, Cipher)
              Debug "Test Deciphered Encryption: " + PeekS(*DecipheredStringEC, -1, #PB_Ascii)
              Debug "================================================================================"


              Debug "================================================================================"
              Debug "D E C R Y P T I O N :"
              TestMode$ = Cipher$ + ", KeySize " + Str(KeySize) + " Bit"
              Debug "TestMode: " + TestMode$
;Input, Len: Wird hier von Encryption (oben) übernommen, sonst natürlich neu bestimmen
*CipheredStringDC   = AllocateMemory(InputLen + 1)         ;mit 1 Zero_Byte (ASCII)
*DecipheredStringDC = AllocateMemory(InputLen + 1)         ;mit 1 Zero_Byte (ASCII)
CopyMemory(*CipheredStringEC, *CipheredStringDC, InputLen) ;oder *CipheredStringEC als input z.B. von einem File
              For i = 0 To InputLen - 1
                StringDC$ + RSet(Hex(PeekA(*CipheredStringDC + i)), 2, "0") + " "
              Next
              Debug "Input ciphered Bytes: " + StringDC$
              Debug "Input-Len: " + Str(InputLen)

Blocks16 = InputLen >> 4          ;/16
LenPad = 16 - (InputLen % 16)

If (LenPad % 16) > 0              ;Padding Decryption
  AddrPad = 16 * (Blocks16 - 1)   ;Adresse der letzten/einzigen 2 Blocks (1x16 Bytes, 1x16-LenPad)
              Debug "Number Blocks16: " + Str(Blocks16)
              Debug "Number Padding Bytes: " + Str(LenPad)

  If Cipher = #PB_Cipher_CBC
    AESDecoder(*CipheredStringDC, *DecipheredStringDC, (Blocks16 - 1) << 4, ?Key, KeySize, ?InitializationVector, #PB_Cipher_CBC)
    Last2Blocks = AllocateMemory(32)
    BufferDC = AllocateMemory(32)
    LastBlock16_ECB = AllocateMemory(16)
    CopyMemory(*CipheredStringDC + (Blocks16 << 4), Last2Blocks, 16 - LenPad)
    AESDecoder(*CipheredStringDC + AddrPad, LastBlock16_ECB, 16, ?Key, KeySize, #Null, #PB_Cipher_ECB)
    CopyMemory(LastBlock16_ECB + 16 - LenPad, Last2Blocks + 16 - LenPad, LenPad)
    CopyMemory(*CipheredStringDC + AddrPad, Last2Blocks + 16, 16)
              For i = 16 - LenPad To 15
                PaddingBytesDC$ + RSet(Hex(PeekA(Last2Blocks + i)), 2, "0") + " "
              Next
              Debug "Decryption Padding Bytes: " + PaddingBytesDC$
    If Blocks16 > 1
      LastIVDC = *CipheredStringDC + ((Blocks16 - 2) << 4)
     Else 
      LastIVDC = ?InitializationVector
    EndIf
    AESDecoder(Last2Blocks, BufferDC, 32, ?Key, KeySize, LastIVDC, #PB_Cipher_CBC)
    CopyMemory(BufferDC, *DecipheredStringDC + AddrPad, 32 - LenPad)

   Else ;ElseIf; #PB_Cipher_ECB
    AESDecoder(*CipheredStringDC, *DecipheredStringDC, Blocks16 << 4, ?Key, KeySize, #Null, #PB_Cipher_ECB)
    For i = 0 To 15 - LenPad 
      PA.a = PeekA(*DecipheredStringDC + i + AddrPad)
      PokeA(*DecipheredStringDC + 16 + i + AddrPad, PA)
              HexStrLBDC$ + RSet(Hex(PA), 2, "0") + " "
    Next
              Debug "Fill Last Block, ready: " + HexStrLBDC$
              For i = 0 To LenPad - 1
                StrPadDC$ + RSet(Hex(PeekA(*DecipheredStringDC + i + AddrPad + 16 - LenPad)), 2, "0") + " "
              Next
              Debug "Decryption Padding-Bytes: " + StrPadDC$

    BufferDC = AllocateMemory(16) ;16 - LenPad, aber das spart nicht viel...
    CopyMemory(*CipheredStringDC + 16 + AddrPad, BufferDC, 16 - LenPad)
    CopyMemory(*DecipheredStringDC + 16 + AddrPad - LenPad, BufferDC + 16 - LenPad, LenPad)
    AESDecoder(BufferDC, *DecipheredStringDC + AddrPad, 16, ?Key, KeySize, #Null, #PB_Cipher_ECB)  ;letzten Block16 einfügen
  EndIf
 Else              ;kein Padding
  AESDecoder(*CipheredStringDC, *DecipheredStringDC, InputLen, ?Key, KeySize, ?InitializationVector, Cipher)
EndIf              ;Padding Decryption
              Debug "------------------------------------------------------------"
              Debug "Done:"
              For i = 0 To InputLen - 1
                StrOutDC$ + RSet(Hex(PeekA(*DecipheredStringDC + i)), 2, "0") + " "
              Next
              Debug "Deciphered as Bytes: " + StrOutDC$
              Debug "Deciphered: " + PeekS(*DecipheredStringDC, -1, #PB_Ascii)

DataSection
  Key:
    Data.b $8C, $15, $51, $2C, $0C, $8A, $0A, $D8, $07, $E4, $21, $A2, $8E, $83, $A3, $88     ;128-Bit
    Data.b $8A, $CA, $FB, $E1, $7B, $A3, $6B, $D6, $BC, $F7, $E6 ,$CD, $FE, $B5, $D7, $B3     ;192-Bit, 256-Bit
  InitializationVector:                ;immer 16 Bytes! Ob ich die Richtigstellung in der deutschen Hilfe noch erleben werde... Man wird ja auch nicht jünger...
    Data.b $08, $0C, $96, $48, $33, $51, $35, $80, $0C, $A9, $42, $1E, $11, $E0, $83, $C7
EndDataSection
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Re: PB kompatibles AES-Padding

Beitrag von Helle »

Dies ist natürlich kein triviales Thema, deshalb nachfolgend ein Anwendungs-Beispiel mit dem AES-NI-Instruction-Set.
Kein salzen und sonstigen Schnickschnack :D , Key und Init-Vector sind in der DataSection fest vorgegeben. Kann natürlich jeder ändern/abfragen.
Als Datenquelle kann ein x-beliebiges File ausgewählt werden (Mindest-Länge 16 Bytes). Gezeigt werden soll der Speed-Vorteil.
Also:

Code: Alles auswählen

;EBC/CBC, KeySize 128/192/256 Bit
;Windows 64-Bit, CPU mit AES-NI (NI=New Instructions, wurde von Intel mal so genannt)
;PureBasic 5.73 LTS (x64)
;--------------------- Key_Expansion_Encrypt AES_128 ---------------------
Procedure Make_Roundkey_AES_128()
  !pshufd xmm2,xmm2,255
  !movdqa xmm3,xmm1
  !pslldq xmm3,4
  !pxor xmm1,xmm3
  !pslldq xmm3,4
  !pxor xmm1,xmm3
  !pslldq xmm3,4
  !pxor xmm1,xmm3  
  !pxor xmm1,xmm2  
  !add r11,16
  !movdqa [r11],xmm1
EndProcedure  

Procedure AES_128_Key_Expansion_Encrypt(Userkey, Key_Schedule_E)
  !mov r10,[p.v_Userkey]          ;oder hier rcx/rdx und die Übergabe-Register direkt verwenden. Gilt generell! 
  !mov r11,[p.v_Key_Schedule_E]

  !movdqa xmm1,[r10]
  !movdqa [r11],xmm1
  !aeskeygenassist xmm2,xmm1,1
  Make_Roundkey_AES_128()         ;kann auch als Macro mal getestet werden; generell
  !aeskeygenassist xmm2,xmm1,2    
  Make_Roundkey_AES_128()  
  !aeskeygenassist xmm2,xmm1,4  
  Make_Roundkey_AES_128()
  !aeskeygenassist xmm2,xmm1,8  
  Make_Roundkey_AES_128()  
  !aeskeygenassist xmm2,xmm1,16  
  Make_Roundkey_AES_128()
  !aeskeygenassist xmm2,xmm1,32  
  Make_Roundkey_AES_128()  
  !aeskeygenassist xmm2,xmm1,64  
  Make_Roundkey_AES_128()
  !aeskeygenassist xmm2,xmm1,128  
  Make_Roundkey_AES_128()  
  !aeskeygenassist xmm2,xmm1,27  
  Make_Roundkey_AES_128()
  !aeskeygenassist xmm2,xmm1,54  
  Make_Roundkey_AES_128()  
EndProcedure 
;-------------------------------------------------------------------------

;--------------------- Key_Expansion_Encrypt AES_192 ---------------------
Procedure Make_Roundkey_AES_192_a()
  !pshufd xmm2,xmm2,85
  !movdqa xmm4,xmm1
  !pslldq xmm4,4
  !pxor xmm1,xmm4
  !pslldq xmm4,4
  !pxor xmm1,xmm4
  !pslldq xmm4,4
  !pxor xmm1,xmm4  
  !pxor xmm1,xmm2  
  !pshufd xmm2,xmm1,255
  !movdqa xmm4,xmm3
  !pslldq xmm4,4
  !pxor xmm3,xmm4  
  !pxor xmm3,xmm2 
  !add r11,16
  !shufpd xmm5,xmm1,0
  !movdqa [r11],xmm5
  !movdqa xmm6,xmm1
  !shufpd xmm6,xmm3,1
  !add r11,16
  !movdqa [r11],xmm6
EndProcedure

Procedure Make_Roundkey_AES_192_b()
  !pshufd xmm2,xmm2,85
  !movdqa xmm4,xmm1
  !pslldq xmm4,4
  !pxor xmm1,xmm4
  !pslldq xmm4,4
  !pxor xmm1,xmm4
  !pslldq xmm4,4
  !pxor xmm1,xmm4  
  !pxor xmm1,xmm2  
  !pshufd xmm2,xmm1,255
  !movdqa xmm4,xmm3
  !pslldq xmm4,4
  !pxor xmm3,xmm4  
  !pxor xmm3,xmm2 
  !add r11,16
  !movdqa [r11],xmm1
  !movdqa xmm5,xmm3
EndProcedure

Procedure AES_192_Key_Expansion_Encrypt(Userkey, Key_Schedule_E)
  !mov r10,[p.v_Userkey]
  !mov r11,[p.v_Key_Schedule_E]

  !movdqa xmm1,[r10]
  !movdqa xmm3,[r10+16]  
  !movdqa [r11],xmm1
  !movdqa xmm5,xmm3  
  !aeskeygenassist xmm2,xmm3,1  
  Make_Roundkey_AES_192_a()
  !aeskeygenassist xmm2,xmm3,2 
  Make_Roundkey_AES_192_b()
  !aeskeygenassist xmm2,xmm3,4  
  Make_Roundkey_AES_192_a()
  !aeskeygenassist xmm2,xmm3,8 
  Make_Roundkey_AES_192_b()
  !aeskeygenassist xmm2,xmm3,16 
  Make_Roundkey_AES_192_a()
  !aeskeygenassist xmm2,xmm3,32 
  Make_Roundkey_AES_192_b()
  !aeskeygenassist xmm2,xmm3,64 
  Make_Roundkey_AES_192_a()
  !aeskeygenassist xmm2,xmm3,128
  Make_Roundkey_AES_192_b()
  !movdqa [r11+16],xmm3
EndProcedure
;-------------------------------------------------------------------------

;--------------------- Key_Expansion_Encrypt AES_256 ---------------------
Procedure Make_Roundkey_AES_256_a()
  !pshufd xmm2,xmm2,255
  !movdqa xmm4,xmm1
  !pslldq xmm4,4
  !pxor xmm1,xmm4
  !pslldq xmm4,4
  !pxor xmm1,xmm4
  !pslldq xmm4,4
  !pxor xmm1,xmm4  
  !pxor xmm1,xmm2  
  !add r11,16
  !movdqa [r11],xmm1
EndProcedure

Procedure Make_Roundkey_AES_256_b()
  !pshufd xmm2,xmm2,170
  !movdqa xmm4,xmm3
  !pslldq xmm4,4
  !pxor xmm3,xmm4
  !pslldq xmm4,4
  !pxor xmm3,xmm4
  !pslldq xmm4,4
  !pxor xmm3,xmm4  
  !pxor xmm3,xmm2  
  !add r11,16
  !movdqa [r11],xmm3
EndProcedure

Procedure AES_256_Key_Expansion_Encrypt(Userkey, Key_Schedule_E)
  !mov r10,[p.v_Userkey]
  !mov r11,[p.v_Key_Schedule_E]

  !movdqa xmm1,[r10]
  !movdqa xmm3,[r10+16]  
  !movdqa [r11],xmm1
  !add r11,16
  !movdqa [r11],xmm3
  !aeskeygenassist xmm2,xmm3,1
  Make_Roundkey_AES_256_a()
  !aeskeygenassist xmm2,xmm1,0
  Make_Roundkey_AES_256_b()
  !aeskeygenassist xmm2,xmm3,2
  Make_Roundkey_AES_256_a()
  !aeskeygenassist xmm2,xmm1,0
  Make_Roundkey_AES_256_b()
  !aeskeygenassist xmm2,xmm3,4
  Make_Roundkey_AES_256_a()
  !aeskeygenassist xmm2,xmm1,0
  Make_Roundkey_AES_256_b()
  !aeskeygenassist xmm2,xmm3,8
  Make_Roundkey_AES_256_a()
  !aeskeygenassist xmm2,xmm1,0
  Make_Roundkey_AES_256_b()
  !aeskeygenassist xmm2,xmm3,16
  Make_Roundkey_AES_256_a()
  !aeskeygenassist xmm2,xmm1,0
  Make_Roundkey_AES_256_b()
  !aeskeygenassist xmm2,xmm3,32
  Make_Roundkey_AES_256_a()
  !aeskeygenassist xmm2,xmm1,0
  Make_Roundkey_AES_256_b()
  !aeskeygenassist xmm2,xmm3,64
  Make_Roundkey_AES_256_a()
EndProcedure
;-------------------------------------------------------------------------

;-------------------------------------------------------------------------
Procedure AES_ECB_Encrypt_1Block(Plain, Cipher, Key_Schedule_E, Rounds)
  !mov r8,[p.v_Plain]
  !mov r9,[p.v_Cipher]
  !mov rcx,[p.v_Key_Schedule_E]
  !mov r11,[p.v_Rounds]

  !movdqa xmm1,[r8]
  !movdqa xmm9,[rcx]
  !movdqa xmm10,[rcx+16]
  !movdqa xmm11,[rcx+32]
  !movdqa xmm12,[rcx+48]
  !pxor xmm1,xmm9
  !aesenc xmm1,xmm10   
  !aesenc xmm1,xmm11
  !aesenc xmm1,xmm12
  !movdqa xmm9,[rcx+64]
  !movdqa xmm10,[rcx+80]
  !movdqa xmm11,[rcx+96]
  !movdqa xmm12,[rcx+112]
  !aesenc xmm1,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm1,xmm11
  !aesenc xmm1,xmm12
  !movdqa xmm9,[rcx+128]
  !movdqa xmm10,[rcx+144]
  !movdqa xmm11,[rcx+160]
  !cmp r11,12 
  !aesenc xmm1,xmm9
  !aesenc xmm1,xmm10
 !jb .E_LAST_1_ECB           ;Rounds=10
  !movdqa xmm9,[rcx+160]
  !movdqa xmm10,[rcx+176]
  !movdqa xmm11,[rcx+192]
  !cmp r11,14 
  !aesenc xmm1,xmm9
  !aesenc xmm1,xmm10
 !jb .E_LAST_1_ECB           ;Rounds=12
  !movdqa xmm9,[rcx+192]
  !movdqa xmm10,[rcx+208]
  !movdqa xmm11,[rcx+224]
  !aesenc xmm1,xmm9
  !aesenc xmm1,xmm10
 !.E_LAST_1_ECB:
  !aesenclast xmm1,xmm11
  !movdqa [r9],xmm1
EndProcedure

Procedure AES_ECB_Encrypt_2Blocks(Plain, Cipher, Key_Schedule_E, Rounds)
  !mov r8,[p.v_Plain]
  !mov r9,[p.v_Cipher]
  !mov rcx,[p.v_Key_Schedule_E]
  !mov r11,[p.v_Rounds]

  !movdqa xmm1,[r8]
  !movdqa xmm2,[r8+16]  
  !movdqa xmm9,[rcx]
  !movdqa xmm10,[rcx+16]
  !movdqa xmm11,[rcx+32]
  !movdqa xmm12,[rcx+48]
  !pxor xmm1,xmm9
  !pxor xmm2,xmm9
  !aesenc xmm1,xmm10   
  !aesenc xmm2,xmm10
  !aesenc xmm1,xmm11
  !aesenc xmm2,xmm11
  !aesenc xmm1,xmm12
  !aesenc xmm2,xmm12
  !movdqa xmm9,[rcx+64]
  !movdqa xmm10,[rcx+80]
  !movdqa xmm11,[rcx+96]
  !movdqa xmm12,[rcx+112]
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
  !aesenc xmm1,xmm11
  !aesenc xmm2,xmm11
  !aesenc xmm1,xmm12
  !aesenc xmm2,xmm12
  !movdqa xmm9,[rcx+128]
  !movdqa xmm10,[rcx+144]
  !movdqa xmm11,[rcx+160]
  !cmp r11,12 
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
 !jb .E_LAST_2_ECB           ;Rounds=10
  !movdqa xmm9,[rcx+160]
  !movdqa xmm10,[rcx+176]
  !movdqa xmm11,[rcx+192]
  !cmp r11,14 
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
 !jb .E_LAST_2_ECB           ;Rounds=12
  !movdqa xmm9,[rcx+192]
  !movdqa xmm10,[rcx+208]
  !movdqa xmm11,[rcx+224]
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
 !.E_LAST_2_ECB:
  !aesenclast xmm1,xmm11
  !aesenclast xmm2,xmm11
  !movdqa [r9],xmm1
  !movdqa [r9+16],xmm2
EndProcedure

Procedure AES_ECB_Encrypt_3Blocks(Plain, Cipher, Key_Schedule_E, Rounds)
  !mov r8,[p.v_Plain]
  !mov r9,[p.v_Cipher]
  !mov rcx,[p.v_Key_Schedule_E]
  !mov r11,[p.v_Rounds]

  !movdqa xmm1,[r8]
  !movdqa xmm2,[r8+16]  
  !movdqa xmm3,[r8+32]
  !movdqa xmm9,[rcx]
  !movdqa xmm10,[rcx+16]
  !movdqa xmm11,[rcx+32]
  !movdqa xmm12,[rcx+48]
  !pxor xmm1,xmm9
  !pxor xmm2,xmm9
  !pxor xmm3,xmm9
  !aesenc xmm1,xmm10   
  !aesenc xmm2,xmm10
  !aesenc xmm3,xmm10
  !aesenc xmm1,xmm11
  !aesenc xmm2,xmm11
  !aesenc xmm3,xmm11
  !aesenc xmm1,xmm12
  !aesenc xmm2,xmm12
  !aesenc xmm3,xmm12
  !movdqa xmm9,[rcx+64]
  !movdqa xmm10,[rcx+80]
  !movdqa xmm11,[rcx+96]
  !movdqa xmm12,[rcx+112]
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm3,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
  !aesenc xmm3,xmm10
  !aesenc xmm1,xmm11
  !aesenc xmm2,xmm11
  !aesenc xmm3,xmm11
  !aesenc xmm1,xmm12
  !aesenc xmm2,xmm12
  !aesenc xmm3,xmm12
  !movdqa xmm9,[rcx+128]
  !movdqa xmm10,[rcx+144]
  !movdqa xmm11,[rcx+160]
  !cmp r11,12 
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm3,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
  !aesenc xmm3,xmm10
 !jb .E_LAST_3_ECB           ;Rounds=10
  !movdqa xmm9,[rcx+160]
  !movdqa xmm10,[rcx+176]
  !movdqa xmm11,[rcx+192]
  !cmp r11,14 
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm3,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
  !aesenc xmm3,xmm10
 !jb .E_LAST_3_ECB           ;Rounds=12
  !movdqa xmm9,[rcx+192]
  !movdqa xmm10,[rcx+208]
  !movdqa xmm11,[rcx+224]
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm3,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
  !aesenc xmm3,xmm10
 !.E_LAST_3_ECB:
  !aesenclast xmm1,xmm11
  !aesenclast xmm2,xmm11
  !aesenclast xmm3,xmm11
  !movdqa [r9],xmm1
  !movdqa [r9+16],xmm2
  !movdqa [r9+32],xmm3
EndProcedure

Procedure AES_ECB_Encrypt_4Blocks(Plain, Cipher, Length, Key_Schedule_E, Rounds)
  !mov r8,[p.v_Plain]
  !mov r9,[p.v_Cipher]
  !mov rdx,[p.v_Length]
  !mov rcx,[p.v_Key_Schedule_E]
  !mov r11,[p.v_Rounds]

  !shr rdx,6  ;/64
  !sub r9,64
 !.E_LOOP_4_ECB:
  !movdqa xmm1,[r8]
  !movdqa xmm2,[r8+16]  
  !movdqa xmm3,[r8+32]
  !movdqa xmm4,[r8+48]
  !movdqa xmm9,[rcx]
  !movdqa xmm10,[rcx+16]
  !movdqa xmm11,[rcx+32]
  !movdqa xmm12,[rcx+48]
  !pxor xmm1,xmm9
  !pxor xmm2,xmm9
  !pxor xmm3,xmm9
  !pxor xmm4,xmm9
  !aesenc xmm1,xmm10   
  !aesenc xmm2,xmm10
  !aesenc xmm3,xmm10
  !aesenc xmm4,xmm10
  !aesenc xmm1,xmm11
  !aesenc xmm2,xmm11
  !aesenc xmm3,xmm11
  !aesenc xmm4,xmm11
  !aesenc xmm1,xmm12
  !aesenc xmm2,xmm12
  !aesenc xmm3,xmm12
  !aesenc xmm4,xmm12
  !movdqa xmm9,[rcx+64]
  !movdqa xmm10,[rcx+80]
  !movdqa xmm11,[rcx+96]
  !movdqa xmm12,[rcx+112]
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm3,xmm9
  !aesenc xmm4,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
  !aesenc xmm3,xmm10
  !aesenc xmm4,xmm10
  !aesenc xmm1,xmm11
  !aesenc xmm2,xmm11
  !aesenc xmm3,xmm11
  !aesenc xmm4,xmm11
  !aesenc xmm1,xmm12
  !aesenc xmm2,xmm12
  !aesenc xmm3,xmm12
  !aesenc xmm4,xmm12
  !movdqa xmm9,[rcx+128]
  !movdqa xmm10,[rcx+144]
  !movdqa xmm11,[rcx+160]
  !cmp r11,12 
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm3,xmm9
  !aesenc xmm4,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
  !aesenc xmm3,xmm10
  !aesenc xmm4,xmm10
 !jb .E_LAST_4_ECB
  !movdqa xmm9,[rcx+160]
  !movdqa xmm10,[rcx+176]
  !movdqa xmm11,[rcx+192]
  !cmp r11,14 
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm3,xmm9
  !aesenc xmm4,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
  !aesenc xmm3,xmm10
  !aesenc xmm4,xmm10
 !jb .E_LAST_4_ECB
  !movdqa xmm9,[rcx+192]
  !movdqa xmm10,[rcx+208]
  !movdqa xmm11,[rcx+224]
  !aesenc xmm1,xmm9
  !aesenc xmm2,xmm9
  !aesenc xmm3,xmm9
  !aesenc xmm4,xmm9
  !aesenc xmm1,xmm10
  !aesenc xmm2,xmm10
  !aesenc xmm3,xmm10
  !aesenc xmm4,xmm10
 !.E_LAST_4_ECB:
  !add r8,64
  !add r9,64
  !dec rdx
  !aesenclast xmm1,xmm11
  !aesenclast xmm2,xmm11
  !aesenclast xmm3,xmm11
  !aesenclast xmm4,xmm11
  !movdqa [r9],xmm1
  !movdqa [r9+16],xmm2
  !movdqa [r9+32],xmm3
  !movdqa [r9+48],xmm4
 !jnz .E_LOOP_4_ECB
EndProcedure
;-------------------------------------------------------------------------
;-------------------------------------------------------------------------
Procedure AES_CBC_Encrypt_1Block(Plain, Cipher, Length, IVec, Key_Schedule_E, Rounds)
  !mov r10,[p.v_Plain]
  !mov r11,[p.v_Cipher]
  !mov rcx,[p.v_Length]
  !mov rdx,[p.v_IVec] 
  !mov r8,[p.v_Key_Schedule_E]
  !mov r9,[p.v_Rounds]

  !shr rcx,4
  !sub r11,16
  !movdqa xmm1,[rdx]
 !.E_LOOP_CBC:
  !pxor xmm1,[r10]
  !pxor xmm1,[r8]
  !add r10,16
  !add r11,16
  !cmp r9,12
  !aesenc xmm1,[r8+16]
  !aesenc xmm1,[r8+32]
  !aesenc xmm1,[r8+48]
  !aesenc xmm1,[r8+64]
  !aesenc xmm1,[r8+80]
  !aesenc xmm1,[r8+96]
  !aesenc xmm1,[r8+112]
  !aesenc xmm1,[r8+128]
  !aesenc xmm1,[r8+144]
  !movdqa xmm2,[r8+160]
 !jb .E_LAST_CBC
  !cmp r9,14
  !aesenc xmm1,[r8+160]
  !aesenc xmm1,[r8+176]
  !movdqa xmm2,[r8+192]
 !jb .E_LAST_CBC
  !aesenc xmm1,[r8+192]
  !aesenc xmm1,[r8+208]
  !movdqa xmm2,[r8+224]
 !.E_LAST_CBC:
  !dec rcx
  !aesenclast xmm1,xmm2
  !movdqa [r11],xmm1
 !jnz .E_LOOP_CBC
EndProcedure
;-------------------------------------------------------------------------

;-------------------------------------------------------------------------
Procedure AES_Key_Expansion_Decrypt(Key_Schedule_E, Key_Schedule_D, Rounds)
  !mov r10,[p.v_Key_Schedule_E]
  !mov r11,[p.v_Key_Schedule_D]
  !mov rdx,[p.v_Rounds]

  !mov rax,rdx
  !shl rax,4
  !mov rcx,rax
  !add rcx,r10
  !movdqa xmm0,[rcx] 
  !movdqa [r11],xmm0
  !sub rcx,208
  !cmp rdx,10
  !aesimc xmm1,[rcx+192] 
  !aesimc xmm2,[rcx+176] 
  !aesimc xmm3,[rcx+160] 
  !aesimc xmm4,[rcx+144] 
  !movdqa [r11+16],xmm1
  !movdqa [r11+32],xmm2
  !movdqa [r11+48],xmm3
  !movdqa [r11+64],xmm4
  !aesimc xmm5,[rcx+128]
  !aesimc xmm6,[rcx+112]
  !aesimc xmm7,[rcx+96]
  !aesimc xmm8,[rcx+80]
  !movdqa [r11+80],xmm5
  !movdqa [r11+96],xmm6
  !movdqa [r11+112],xmm7
  !movdqa [r11+128],xmm8
  !aesimc xmm9,[rcx+64]
  !movdqa [r11+144],xmm9
 !jle .END_DEC
  !cmp rdx,12
  !aesimc xmm0,[rcx+48]  
  !aesimc xmm1,[rcx+32]
  !movdqa [r11+160],xmm0
  !movdqa [r11+176],xmm1
 !jle .END_DEC
  !aesimc xmm0,[rcx+16] 
  !aesimc xmm1,[rcx]
  !movdqa [r11+192],xmm0
  !movdqa [r11+208],xmm1
 !.END_DEC:
  !movdqa xmm0,[r10]
  !add r11,rax
  !movdqa [r11],xmm0
EndProcedure

Procedure AES_ECB_Decrypt_1Block(Cipher, Decipher, Key_Schedule_D, Rounds)
  !mov r8,[p.v_Cipher]
  !mov r9,[p.v_Decipher]
  !mov rcx,[p.v_Key_Schedule_D]
  !mov r11,[p.v_Rounds]  

  !movdqa xmm1,[r8]
  !movdqa xmm9,[rcx]
  !movdqa xmm10,[rcx+16]
  !movdqa xmm11,[rcx+32]
  !movdqa xmm12,[rcx+48]
  !pxor xmm1,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm1,xmm12
  !movdqa xmm9,[rcx+64]
  !movdqa xmm10,[rcx+80]
  !movdqa xmm11,[rcx+96]
  !movdqa xmm12,[rcx+112]
  !aesdec xmm1,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm1,xmm12
  !movdqa xmm9,[rcx+128]
  !movdqa xmm10,[rcx+144]
  !movdqa xmm11,[rcx+160]
  !cmp r11,12                          ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm1,xmm10
 !jb .D_LAST_1_ECB
  !movdqa xmm9,[rcx+160]
  !movdqa xmm10,[rcx+176]
  !movdqa xmm11,[rcx+192]
  !cmp r11,14                          ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm1,xmm10
 !jb .D_LAST_1_ECB
  !movdqa xmm9,[rcx+192]
  !movdqa xmm10,[rcx+208]
  !movdqa xmm11,[rcx+224]
  !aesdec xmm1,xmm9
  !aesdec xmm1,xmm10
 !.D_LAST_1_ECB:
  !aesdeclast xmm1,xmm11
  !movdqa [r9],xmm1
EndProcedure

Procedure AES_ECB_Decrypt_2Blocks(Cipher, Decipher, Key_Schedule_D, Rounds)
  !mov r8,[p.v_Cipher]
  !mov r9,[p.v_Decipher]
  !mov rcx,[p.v_Key_Schedule_D]
  !mov r11,[p.v_Rounds]  

  !movdqa xmm1,[r8]
  !movdqa xmm2,[r8+16]
  !movdqa xmm9,[rcx]
  !movdqa xmm10,[rcx+16]
  !movdqa xmm11,[rcx+32]
  !movdqa xmm12,[rcx+48]
  !pxor xmm1,xmm9
  !pxor xmm2,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !movdqa xmm9,[rcx+64]
  !movdqa xmm10,[rcx+80]
  !movdqa xmm11,[rcx+96]
  !movdqa xmm12,[rcx+112]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !movdqa xmm9,[rcx+128]
  !movdqa xmm10,[rcx+144]
  !movdqa xmm11,[rcx+160]
  !cmp r11,12                          ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
 !jb .D_LAST_2_ECB
  !movdqa xmm9,[rcx+160]
  !movdqa xmm10,[rcx+176]
  !movdqa xmm11,[rcx+192]
  !cmp r11,14                          ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
 !jb .D_LAST_2_ECB
  !movdqa xmm9,[rcx+192]
  !movdqa xmm10,[rcx+208]
  !movdqa xmm11,[rcx+224]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
 !.D_LAST_2_ECB:
  !aesdeclast xmm1,xmm11
  !aesdeclast xmm2,xmm11
  !movdqa [r9],xmm1
  !movdqa [r9+16],xmm2
EndProcedure

Procedure AES_ECB_Decrypt_3Blocks(Cipher, Decipher, Key_Schedule_D, Rounds)
  !mov r8,[p.v_Cipher]
  !mov r9,[p.v_Decipher]
  !mov rcx,[p.v_Key_Schedule_D]
  !mov r11,[p.v_Rounds]  

  !movdqa xmm1,[r8]
  !movdqa xmm2,[r8+16]
  !movdqa xmm3,[r8+32]
  !movdqa xmm9,[rcx]
  !movdqa xmm10,[rcx+16]
  !movdqa xmm11,[rcx+32]
  !movdqa xmm12,[rcx+48]
  !pxor xmm1,xmm9
  !pxor xmm2,xmm9
  !pxor xmm3,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm3,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !aesdec xmm3,xmm12
  !movdqa xmm9,[rcx+64]
  !movdqa xmm10,[rcx+80]
  !movdqa xmm11,[rcx+96]
  !movdqa xmm12,[rcx+112]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm3,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !aesdec xmm3,xmm12
  !movdqa xmm9,[rcx+128]
  !movdqa xmm10,[rcx+144]
  !movdqa xmm11,[rcx+160]
  !cmp r11,12                          ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
 !jb .D_LAST_3_ECB
  !movdqa xmm9,[rcx+160]
  !movdqa xmm10,[rcx+176]
  !movdqa xmm11,[rcx+192]
  !cmp r11,14                          ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
 !jb .D_LAST_3_ECB
  !movdqa xmm9,[rcx+192]
  !movdqa xmm10,[rcx+208]
  !movdqa xmm11,[rcx+224]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
 !.D_LAST_3_ECB:
  !aesdeclast xmm1,xmm11
  !aesdeclast xmm2,xmm11
  !aesdeclast xmm3,xmm11
  !movdqa [r9],xmm1
  !movdqa [r9+16],xmm2
  !movdqa [r9+32],xmm3
EndProcedure

Procedure AES_ECB_Decrypt_4Blocks(Cipher, Decipher, Length, Key_Schedule_D, Rounds)
  !mov r8,[p.v_Cipher]
  !mov r9,[p.v_Decipher]
  !mov rdx,[p.v_Length]
  !mov rcx,[p.v_Key_Schedule_D]
  !mov r11,[p.v_Rounds]  

  !shr rdx,6
  !sub r9,64
 !.D_LOOP_4_ECB:
  !movdqa xmm1,[r8]
  !movdqa xmm2,[r8+16]
  !movdqa xmm3,[r8+32]
  !movdqa xmm4,[r8+48]
  !movdqa xmm9,[rcx]
  !movdqa xmm10,[rcx+16]
  !movdqa xmm11,[rcx+32]
  !movdqa xmm12,[rcx+48]
  !pxor xmm1,xmm9
  !pxor xmm2,xmm9
  !pxor xmm3,xmm9
  !pxor xmm4,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm4,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm3,xmm11
  !aesdec xmm4,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !aesdec xmm3,xmm12
  !aesdec xmm4,xmm12
  !movdqa xmm9,[rcx+64]
  !movdqa xmm10,[rcx+80]
  !movdqa xmm11,[rcx+96]
  !movdqa xmm12,[rcx+112]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm4,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm4,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm3,xmm11
  !aesdec xmm4,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !aesdec xmm3,xmm12
  !aesdec xmm4,xmm12
  !movdqa xmm9,[rcx+128]
  !movdqa xmm10,[rcx+144]
  !movdqa xmm11,[rcx+160]
  !cmp r11,12                          ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm4,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm4,xmm10
 !jb .D_LAST_4_ECB
  !movdqa xmm9,[rcx+160]
  !movdqa xmm10,[rcx+176]
  !movdqa xmm11,[rcx+192]
  !cmp r11,14                          ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm4,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm4,xmm10
 !jb .D_LAST_4_ECB
  !movdqa xmm9,[rcx+192]
  !movdqa xmm10,[rcx+208]
  !movdqa xmm11,[rcx+224]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm4,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm4,xmm10
 !.D_LAST_4_ECB:
  !add r8,64
  !add r9,64
  !dec rdx
  !aesdeclast xmm1,xmm11
  !aesdeclast xmm2,xmm11
  !aesdeclast xmm3,xmm11
  !aesdeclast xmm4,xmm11
  !movdqa [r9],xmm1
  !movdqa [r9+16],xmm2
  !movdqa [r9+32],xmm3
  !movdqa [r9+48],xmm4
 !jnz .D_LOOP_4_ECB
EndProcedure
;-------------------------------------------------------------------------

;-------------------------------------------------------------------------
Procedure AES_CBC_Decrypt_1Block(Cipher, Decipher, IVec, Key_Schedule_D, Rounds)
  !mov r10,[p.v_Cipher]
  !mov r11,[p.v_Decipher]
  !mov rdx,[p.v_IVec] 
  !mov r8,[p.v_Key_Schedule_D]
  !mov r9,[p.v_Rounds]

  !movdqa xmm5,[rdx] 
  !movdqa xmm1,[r10]
  !movdqa xmm6,xmm1
  !movdqa xmm9,[r8]
  !movdqa xmm10,[r8+16]
  !movdqa xmm11,[r8+32]
  !movdqa xmm12,[r8+48]
  !pxor xmm1,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm1,xmm12
  !movdqa xmm9,[r8+64]
  !movdqa xmm10,[r8+80]
  !movdqa xmm11,[r8+96]
  !movdqa xmm12,[r8+112]
  !aesdec xmm1,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm1,xmm12
  !movdqa xmm9,[r8+128]
  !movdqa xmm10,[r8+144]
  !movdqa xmm11,[r8+160]
  !cmp r9,12                           ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm1,xmm10
 !jb .D_LAST_1_CBC
  !movdqa xmm9,[r8+160]
  !movdqa xmm10,[r8+176]
  !movdqa xmm11,[r8+192]
  !cmp r9,14                           ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm1,xmm10
 !jb .D_LAST_1_CBC
  !movdqa xmm9,[r8+192]
  !movdqa xmm10,[r8+208]
  !movdqa xmm11,[r8+224]
  !aesdec xmm1,xmm9
  !aesdec xmm1,xmm10
 !.D_LAST_1_CBC:
  !aesdeclast xmm1,xmm11
  !pxor xmm1,xmm5
  !movdqa [r11],xmm1
EndProcedure

Procedure AES_CBC_Decrypt_2Blocks(Cipher, Decipher, IVec, Key_Schedule_D, Rounds)
  !mov r10,[p.v_Cipher]
  !mov r11,[p.v_Decipher]
  !mov rdx,[p.v_IVec] 
  !mov r8,[p.v_Key_Schedule_D]
  !mov r9,[p.v_Rounds]

  !movdqa xmm5,[rdx] 
  !movdqa xmm1,[r10]
  !movdqa xmm2,[r10+16]
  !movdqa xmm6,xmm1
  !movdqa xmm7,xmm2
  !movdqa xmm9,[r8]
  !movdqa xmm10,[r8+16]
  !movdqa xmm11,[r8+32]
  !movdqa xmm12,[r8+48]
  !pxor xmm1,xmm9
  !pxor xmm2,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !movdqa xmm9,[r8+64]
  !movdqa xmm10,[r8+80]
  !movdqa xmm11,[r8+96]
  !movdqa xmm12,[r8+112]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !movdqa xmm9,[r8+128]
  !movdqa xmm10,[r8+144]
  !movdqa xmm11,[r8+160]
  !cmp r9,12                           ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
 !jb .D_LAST_2_CBC
  !movdqa xmm9,[r8+160]
  !movdqa xmm10,[r8+176]
  !movdqa xmm11,[r8+192]
  !cmp r9,14                           ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
 !jb .D_LAST_2_CBC
  !movdqa xmm9,[r8+192]
  !movdqa xmm10,[r8+208]
  !movdqa xmm11,[r8+224]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
 !.D_LAST_2_CBC:
  !aesdeclast xmm1,xmm11
  !aesdeclast xmm2,xmm11
  !pxor xmm1,xmm5
  !pxor xmm2,xmm6
  !movdqa [r11],xmm1
  !movdqa [r11+16],xmm2
EndProcedure

Procedure AES_CBC_Decrypt_3Blocks(Cipher, Decipher, IVec, Key_Schedule_D, Rounds)
  !mov r10,[p.v_Cipher]
  !mov r11,[p.v_Decipher]
  !mov rdx,[p.v_IVec] 
  !mov r8,[p.v_Key_Schedule_D]
  !mov r9,[p.v_Rounds]

  !movdqa xmm5,[rdx] 
  !movdqa xmm1,[r10]
  !movdqa xmm2,[r10+16]
  !movdqa xmm3,[r10+32]
  !movdqa xmm6,xmm1
  !movdqa xmm7,xmm2
  !movdqa xmm8,xmm3
  !movdqa xmm9,[r8]
  !movdqa xmm10,[r8+16]
  !movdqa xmm11,[r8+32]
  !movdqa xmm12,[r8+48]
  !pxor xmm1,xmm9
  !pxor xmm2,xmm9
  !pxor xmm3,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm3,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !aesdec xmm3,xmm12
  !movdqa xmm9,[r8+64]
  !movdqa xmm10,[r8+80]
  !movdqa xmm11,[r8+96]
  !movdqa xmm12,[r8+112]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm3,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !aesdec xmm3,xmm12
  !movdqa xmm9,[r8+128]
  !movdqa xmm10,[r8+144]
  !movdqa xmm11,[r8+160]
  !cmp r9,12                           ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
 !jb .D_LAST_3_CBC
  !movdqa xmm9,[r8+160]
  !movdqa xmm10,[r8+176]
  !movdqa xmm11,[r8+192]
  !cmp r9,14                           ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
 !jb .D_LAST_3_CBC
  !movdqa xmm9,[r8+192]
  !movdqa xmm10,[r8+208]
  !movdqa xmm11,[r8+224]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
 !.D_LAST_3_CBC:
  !aesdeclast xmm1,xmm11
  !aesdeclast xmm2,xmm11
  !aesdeclast xmm3,xmm11
  !pxor xmm1,xmm5
  !pxor xmm2,xmm6
  !pxor xmm3,xmm7
  !movdqa [r11],xmm1
  !movdqa [r11+16],xmm2
  !movdqa [r11+32],xmm3
EndProcedure

Procedure AES_CBC_Decrypt_4Blocks(Cipher, Decipher, IVec, Length, Key_Schedule_D, Rounds)
  !mov r10,[p.v_Cipher]
  !mov r11,[p.v_Decipher]
  !mov rdx,[p.v_IVec] 
  !mov rcx,[p.v_Length]
  !mov r8,[p.v_Key_Schedule_D]
  !mov r9,[p.v_Rounds]

  !shr rcx,6
  !movdqa xmm5,[rdx] 
  !sub r11,64
 !.D_LOOP_4_CBC:
  !movdqa xmm1,[r10]
  !movdqa xmm2,[r10+16]
  !movdqa xmm3,[r10+32]
  !movdqa xmm4,[r10+48]
  !movdqa xmm6,xmm1
  !movdqa xmm7,xmm2
  !movdqa xmm8,xmm3
  !movdqa xmm15,xmm4
  !movdqa xmm9,[r8]
  !movdqa xmm10,[r8+16]
  !movdqa xmm11,[r8+32]
  !movdqa xmm12,[r8+48]
  !pxor xmm1,xmm9
  !pxor xmm2,xmm9
  !pxor xmm3,xmm9
  !pxor xmm4,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm4,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm3,xmm11
  !aesdec xmm4,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !aesdec xmm3,xmm12
  !aesdec xmm4,xmm12
  !movdqa xmm9,[r8+64]
  !movdqa xmm10,[r8+80]
  !movdqa xmm11,[r8+96]
  !movdqa xmm12,[r8+112]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm4,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm4,xmm10
  !aesdec xmm1,xmm11
  !aesdec xmm2,xmm11
  !aesdec xmm3,xmm11
  !aesdec xmm4,xmm11
  !aesdec xmm1,xmm12
  !aesdec xmm2,xmm12
  !aesdec xmm3,xmm12
  !aesdec xmm4,xmm12
  !movdqa xmm9,[r8+128]
  !movdqa xmm10,[r8+144]
  !movdqa xmm11,[r8+160]
  !cmp r9,12                           ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm4,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm4,xmm10
 !jb .D_LAST_4_CBC
  !movdqa xmm9,[r8+160]
  !movdqa xmm10,[r8+176]
  !movdqa xmm11,[r8+192]
  !cmp r9,14                           ;Runden
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm4,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm4,xmm10
 !jb .D_LAST_4_CBC
  !movdqa xmm9,[r8+192]
  !movdqa xmm10,[r8+208]
  !movdqa xmm11,[r8+224]
  !aesdec xmm1,xmm9
  !aesdec xmm2,xmm9
  !aesdec xmm3,xmm9
  !aesdec xmm4,xmm9
  !aesdec xmm1,xmm10
  !aesdec xmm2,xmm10
  !aesdec xmm3,xmm10
  !aesdec xmm4,xmm10
 !.D_LAST_4_CBC:
  !add r10,64
  !add r11,64
  !dec rcx
  !aesdeclast xmm1,xmm11
  !aesdeclast xmm2,xmm11
  !aesdeclast xmm3,xmm11
  !aesdeclast xmm4,xmm11
  !pxor xmm1,xmm5
  !pxor xmm2,xmm6
  !pxor xmm3,xmm7
  !pxor xmm4,xmm8
  !movdqa [r11],xmm1
  !movdqa [r11+16],xmm2
  !movdqa [r11+32],xmm3
  !movdqa [r11+48],xmm4
  !movdqa xmm5,xmm15
  !jnz .D_LOOP_4_CBC
EndProcedure

;Test, ob CPU AES unterstützt, CPUID-Verfügbarkeit wird vorausgesetzt 
!mov eax,1h
!cpuid  
!test ecx,2000000h
!jnz @f  
MessageRequester("Error!", "No AES-NI-CPU!")  
End
!@@:  

;Vorgaben:
Cipher = #PB_Cipher_ECB : Cipher$ = "ECB"   ;ECB in PB: InitializationVector wird ignoriert und ist nur ein Platzhalter!
KeySize = 128
Encryption = 1 : Mode$ = "Encryption, "
Decryption = 0

OpenWindow(0, 0, 0, 400, 400, "AES-NI for File", #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget)
  StickyWindow(0, 1)
  ;LoadFont(0, "Arial Fett", 9)
  LoadFont(0, "Trebuchet MS Fett", 9)
  SetGadgetFont(#PB_Default, FontID(0))

  SelFile$ = OpenFileRequester("Select File:", "", "", 0)
  If SelFile$
    TextGadget(0, 10, 10, 380, 20, "File:")
    EditorGadget(1, 10, 30, 380, 60, #PB_Editor_ReadOnly | #PB_Editor_WordWrap)
    SetGadgetText(1, SelFile$)
   Else
    MessageRequester("Error!", "File?") 
    End
  EndIf
  TextGadget(2, 10, 100, 100, 20, "Mode:")
  OptionGadget(3, 150, 100, 75, 20, "Encrypt")
  OptionGadget(4, 240, 100, 75, 20, "Decrypt")
  SetGadgetState(3, 1)

  TextGadget(5, 10, 125, 100, 20, "Cipher-Mode:")
  OptionGadget(6, 150, 125, 60, 20, "ECB")
  OptionGadget(7, 240, 125, 60, 20, "CBC")
  SetGadgetState(6, 1)

  TextGadget(8, 10,  150, 100, 20, "Key-Size:")
  OptionGadget(9, 150, 150, 60, 20, "128")
  OptionGadget(10, 240, 150, 60, 20, "192")
  OptionGadget(11, 330, 150, 60, 20, "256")
  SetGadgetState(9, 1)

  ButtonGadget(12, 100, 200, 200, 20, "S T A R T")

  Repeat
    Event = WaitWindowEvent()
    If Event = #PB_Event_CloseWindow
      End
    EndIf
    If Event = #PB_Event_Gadget
      Select EventGadget()
        Case 3
          Encryption = 1 : Decryption = 0 : Mode$ = "Encryption, "
        Case 4
          Encryption = 0 : Decryption = 1 : Mode$ = "Decryption, "
        Case 6
          Cipher = #PB_Cipher_ECB : Cipher$ = "ECB"
        Case 7
          Cipher = #PB_Cipher_CBC : Cipher$ = "CBC"
        Case 9
          KeySize = 128
        Case 10
          KeySize = 192
        Case 11
          KeySize = 256
        Case 12
          Break
      EndSelect
    EndIf
  ForEver

  For i = 0 To 12
    FreeGadget(i)
  Next

  TextGadget(0, 10, 10, 100, 20, "I N F O S :")
  TextGadget(1, 10, 30, 380, 20, "File:")
  EditorGadget(2, 10, 50, 380, 60, #PB_Editor_ReadOnly | #PB_Editor_WordWrap)
  SetGadgetText(2, SelFile$)
  While WaitWindowEvent(0) : Wend      ;Time for displaying File

  ReadFile(0, SelFile$)
  InputLen = Lof(0)
  TextGadget(3, 10, 115, 380, 20, "Input-Bytes: " + Str(InputLen))

  TestMode$ = "Mode: " + Mode$ + Cipher$ + ", KeySize " + Str(KeySize) + " Bit"
  TextGadget(4, 10, 135, 380, 20, TestMode$)

  WorkingBuffer = AllocateMemory(InputLen + 1088, #PB_Memory_NoClear)
  WorkingBufferA64 = (WorkingBuffer & $FFFFFFFFFFFFFFC0) + 64
;Memory-Zuweisung, Vielfache von 64 z.B. wegen Cache-Line
;000-063: Key 
;064-127: InitializationVector
;128-383: Key_Schedule_Encrypt         Enc, Dec
;384-639: Key_Schedule_Decrypt         Dec
;640-703: BufferPad                    Enc, Dec
;704-767: LastIV                       Enc
;768-831: Last2Blocks                  Dec
;832-895: LastBlock16                  Dec
;896-...: CipheredOutput, DecipheredOutput
;1024-...: InputBytes

  CopyMemory(?UserKey, WorkingBufferA64, 32)
  Key = WorkingBufferA64
  CopyMemory(?UserInitializationVector, WorkingBufferA64 + 64, 16)
  InitializationVector = WorkingBufferA64 + 64
  Key_Schedule_Encrypt = WorkingBufferA64 + 128
  BufferPad = WorkingBufferA64 + 640
  InputBytes = WorkingBufferA64 + 1024

  Cluster = 1024 * 1024;*1024     ;interessante Größe für PBs Read-Write-Data!
  Chunks = InputLen / Cluster
  RestBytes = InputLen - (Chunks * Cluster)
  TA = ElapsedMilliseconds()
  For i = 0 To Chunks - 1
    BytesCopy = ReadData(0, InputBytes + (i * Cluster), Cluster)
    ;CopyGes + BytesCopy      ;nur für Kontrolle
  Next
  Rest = ReadData(0, InputBytes + (Chunks * Cluster), RestBytes)
  ;Debug "Anzahl der kopierten Bytes: " + StrU(CopyGes + Rest)
  TE = ElapsedMilliseconds() - TA
  TextGadget(5, 10, 155, 380, 20, "Time Copy File HD/SSD -> Memory: " + Str(TE) + " ms")
  CloseFile(0)

  Blocks16 = InputLen >> 4        ;/16
  AddrPad = (Blocks16 - 1) << 4   ;Adresse der letzten/einzigen 2 Blocks (1x16 Bytes, 1x16-LenPad)
  LenPad = (16 - (InputLen % 16)) & %1111   ;liegt zwischen 0 und 15
  TextGadget(6, 10, 175, 380, 20, "Blocks16: " + Str(Blocks16))
  TextGadget(7, 10, 195, 380, 20, "Padding-Bytes: " + Str(LenPad))

;-------------------------------------------------------------------------
If Encryption
  TA = ElapsedMilliseconds()
  Select KeySize
    Case 128
      AES_128_Key_Expansion_Encrypt(Key, Key_Schedule_Encrypt)
      Rounds = 10
    Case 192
      AES_192_Key_Expansion_Encrypt(Key, Key_Schedule_Encrypt)
      Rounds = 12
    Default   ;256
      AES_256_Key_Expansion_Encrypt(Key, Key_Schedule_Encrypt)
      Rounds = 14
  EndSelect

  LastIV = WorkingBufferA64 + 704
  CipheredOutput = WorkingBufferA64 + 896
  If Cipher = #PB_Cipher_ECB
    n = Blocks16 & 3
    Select n 
      Case 0
        AES_ECB_Encrypt_4Blocks(InputBytes, CipheredOutput, Blocks16 << 4, Key_Schedule_Encrypt, Rounds)
      Case 1
        AES_ECB_Encrypt_1Block(InputBytes, CipheredOutput, Key_Schedule_Encrypt, Rounds)
      Case 2
        AES_ECB_Encrypt_2Blocks(InputBytes, CipheredOutput, Key_Schedule_Encrypt, Rounds)
      Case 3
        AES_ECB_Encrypt_3Blocks(InputBytes, CipheredOutput, Key_Schedule_Encrypt, Rounds)
    EndSelect
    If n > 0 And Blocks16 > 3
      AES_ECB_Encrypt_4Blocks(InputBytes + (n << 4), CipheredOutput + (n << 4), (Blocks16 - n) << 4, Key_Schedule_Encrypt, Rounds)
    EndIf

    If LenPad      ;Padding Encryption
      CopyMemory(CipheredOutput + AddrPad, CipheredOutput + 16 + AddrPad, 16 - LenPad)
      CopyMemory(InputBytes + 16 + AddrPad, BufferPad, 16 - LenPad)
      CopyMemory(CipheredOutput + 16 + AddrPad - LenPad, BufferPad + 16 - LenPad, LenPad)
      AES_ECB_Encrypt_1Block(BufferPad, CipheredOutput + AddrPad, Key_Schedule_Encrypt, Rounds)
    EndIf          ;Padding Encryption

   Else            ;#PB_Cipher_CBC, Encrypt-CBC nur seriell!
    AES_CBC_Encrypt_1Block(InputBytes, CipheredOutput, Blocks16 << 4, InitializationVector, Key_Schedule_Encrypt, Rounds)
    If LenPad      ;Padding Encryption
      CopyMemory(CipheredOutput + AddrPad, CipheredOutput + 16 + AddrPad, 16 - LenPad)
      CopyMemory(CipheredOutput + AddrPad, LastIV, 16 - LenPad)
      CopyMemory(InputBytes + 16 + AddrPad, BufferPad, 16 - LenPad)
      CopyMemory(CipheredOutput + 16 + AddrPad - LenPad, BufferPad + 16 - LenPad, LenPad)
      AES_CBC_Encrypt_1Block(BufferPad, CipheredOutput + AddrPad, 16, LastIV, Key_Schedule_Encrypt, Rounds)
    EndIf          ;Padding Encryption
  EndIf

  TE = ElapsedMilliseconds() - TA
  TextGadget(8, 10, 215, 380, 20, "Time Encrypt NI: " + Str(TE) + " ms")

  SaveFile$ = GetFilePart(SelFile$) + ".NIenc"
  Source = CipheredOutput
EndIf              ;Encryption
;-------------------------------------------------------------------------

;-------------------------------------------------------------------------
If Decryption
  TA = ElapsedMilliseconds()
  ;für Decrypt hier nochmal Encrypt nötig!
  Select KeySize
    Case 128
      AES_128_Key_Expansion_Encrypt(Key, Key_Schedule_Encrypt)
      Rounds = 10
    Case 192
      AES_192_Key_Expansion_Encrypt(Key, Key_Schedule_Encrypt)
      Rounds = 12
    Default   ;256
      AES_256_Key_Expansion_Encrypt(Key, Key_Schedule_Encrypt)
      Rounds = 14
  EndSelect

  Key_Schedule_Decrypt = WorkingBufferA64 + 384
  DecipheredOutput = WorkingBufferA64 + 896

  AES_Key_Expansion_Decrypt(Key_Schedule_Encrypt, Key_Schedule_Decrypt, Rounds)

;-------------------------------------------------------------------------
  If Cipher = #PB_Cipher_ECB
    n = Blocks16 & 3
    Select n 
      Case 0
        AES_ECB_Decrypt_4Blocks(InputBytes, DecipheredOutput, Blocks16 << 4, Key_Schedule_Decrypt, Rounds)
      Case 1
        AES_ECB_Decrypt_1Block(InputBytes, DecipheredOutput, Key_Schedule_Decrypt, Rounds)
      Case 2
        AES_ECB_Decrypt_2Blocks(InputBytes, DecipheredOutput, Key_Schedule_Decrypt, Rounds)
      Case 3
        AES_ECB_Decrypt_3Blocks(InputBytes, DecipheredOutput, Key_Schedule_Decrypt, Rounds)
    EndSelect
    If n > 0 And Blocks16 > 3
      AES_ECB_Decrypt_4Blocks(InputBytes + (n << 4), DecipheredOutput + (n << 4), (Blocks16 - n) << 4, Key_Schedule_Decrypt, Rounds)
    EndIf

   Else            ;CBC, hier könnte wohl auch mit einem Block weniger angefangen werden, bringt aber wohl nichts 
    n = Blocks16 & 3
    Select n 
      Case 0
        AES_CBC_Decrypt_4Blocks(InputBytes, DecipheredOutput, InitializationVector, Blocks16 << 4, Key_Schedule_Decrypt, Rounds)
      Case 1
        AES_CBC_Decrypt_1Block(InputBytes, DecipheredOutput, InitializationVector, Key_Schedule_Decrypt, Rounds)
      Case 2
        AES_CBC_Decrypt_2Blocks(InputBytes, DecipheredOutput, InitializationVector, Key_Schedule_Decrypt, Rounds)
      Case 3
        AES_CBC_Decrypt_3Blocks(InputBytes, DecipheredOutput, InitializationVector, Key_Schedule_Decrypt, Rounds)
    EndSelect
    If n > 0 And Blocks16 > 3
      AES_CBC_Decrypt_4Blocks(InputBytes + (n << 4), DecipheredOutput + (n << 4), InputBytes + ((n - 1) << 4), (Blocks16 - n) << 4, Key_Schedule_Decrypt, Rounds)
    EndIf
  EndIf            ;Cipher

  If LenPad        ;Padding Decryption
    If Cipher = #PB_Cipher_CBC
      Last2Blocks = WorkingBufferA64 + 768
      LastBlock16 = WorkingBufferA64 + 832
      CopyMemory(InputBytes + (Blocks16 << 4), Last2Blocks, 16 - LenPad)
      AES_ECB_Decrypt_1Block(InputBytes + AddrPad, LastBlock16, Key_Schedule_Decrypt, Rounds)
      CopyMemory(LastBlock16 + 16 - LenPad, Last2Blocks + 16 - LenPad, LenPad)
      CopyMemory(InputBytes + AddrPad, Last2Blocks + 16, 16)
      If Blocks16 > 1
        LastIV = InputBytes + ((Blocks16 - 2) << 4)
       Else 
        LastIV = InitializationVector
      EndIf
      AES_CBC_Decrypt_2Blocks(Last2Blocks, BufferPad, LastIV, Key_Schedule_Decrypt, Rounds)
      CopyMemory(BufferPad, DecipheredOutput + AddrPad, 32 - LenPad)
     Else     ;ElseIf; #PB_Cipher_ECB
      For i = 0 To 15 - LenPad 
        PA.a = PeekA(DecipheredOutput + i + AddrPad)
        PokeA(DecipheredOutput + 16 + i + AddrPad, PA)
      Next
      CopyMemory(InputBytes + 16 + AddrPad, BufferPad, 16 - LenPad)
      CopyMemory(DecipheredOutput + 16 + AddrPad - LenPad, BufferPad + 16 - LenPad, LenPad)
      AES_ECB_Decrypt_1Block(BufferPad, DecipheredOutput + AddrPad, Key_Schedule_Decrypt, Rounds)
    EndIf
  EndIf            ;Padding Decryption

  TE = ElapsedMilliseconds() - TA
  TextGadget(8, 10, 215, 380, 20, "Time Decrypt NI: " + Str(TE) + " ms")

  SaveFile$ = GetFilePart(SelFile$, #PB_FileSystem_NoExtension) + ".NIdec." + GetExtensionPart(GetFilePart(SelFile$, #PB_FileSystem_NoExtension))
  Source = DecipheredOutput
EndIf         ;Decryption
;-------------------------------------------------------------------------

  TA = ElapsedMilliseconds()
  CreateFile(1, SaveFile$)
  For i = 0 To Chunks - 1
    BytesWrite + WriteData(1, Source + (i * Cluster), Cluster)
  Next
  Rest = WriteData(1, Source + (Chunks * Cluster), RestBytes)
  CloseFile(1) 
  TE = ElapsedMilliseconds() - TA
  TextGadget(9, 10, 235, 380, 20, "Output-Bytes: " + StrU(BytesWrite + Rest))
  TextGadget(10, 10, 255, 380, 20, "Time Copy File Memory -> HD/SSD: " + Str(TE) + " ms")
;-------------------------------------------------------------------------

;-------------------------------------------------------------------------
;Test/Vergleich mit PB:
  TextGadget(11, 10, 290, 380, 20, "Test PB:")
  ReadFile(0, SelFile$)
  InputLen = Lof(0)

  *PB_Eingabe = AllocateMemory(InputLen, #PB_Memory_NoClear)    ;If...  sonst splitten
  *PB_Ausgabe = AllocateMemory(InputLen, #PB_Memory_NoClear)    ;If...

  For i = 0 To Chunks - 1
    ReadData(0, *PB_Eingabe + (i * Cluster), Cluster)
  Next
  ReadData(0, *PB_Eingabe + (Chunks * Cluster), RestBytes)

  Gibi = 1024 * 1024 * 1024
  GibiM64 = Gibi - 64        ;damit vernünftiger Rest bleibt
  LenVar = InputLen
  PoiVar = 0

  TA_PB = ElapsedMilliseconds()
  If Encryption
    Cipher_PB = Cipher | #PB_Cipher_Encode
    NI_Output = CipheredOutput
    Enc_Dec_PB$ = "Time Encrypt PB: "
   Else            ;Decryption
    Cipher_PB = Cipher | #PB_Cipher_Decode
    NI_Output = DecipheredOutput
    Enc_Dec_PB$ = "Time Decrypt PB: "
  EndIf

  StartAESCipher(0, ?UserKey, KeySize, ?UserInitializationVector, Cipher_PB)
  Repeat
    If LenVar > Gibi
      AddCipherBuffer(0, *PB_Eingabe + PoiVar, *PB_Ausgabe + PoiVar, GibiM64)
      PoiVar + GibiM64
     Else
      AddCipherBuffer(0, *PB_Eingabe + PoiVar, *PB_Ausgabe + PoiVar, LenVar)   ;Rest
      Break
    EndIf
    LenVar - GibiM64
  ForEver
  FinishCipher(0)
  TE_PB = ElapsedMilliseconds() - TA
  TextGadget(12, 10, 310, 380, 20, Enc_Dec_PB$ + Str(TE_PB) + " ms")
  TextGadget(13, 10, 330, 380, 20, "Compare Output NI-PB: " + Str(CompareMemory(NI_Output, *PB_Ausgabe, InputLen)))
  ;Für Tests kann auch noch Deciphered mit dem Original verglichen werden 
  FreeMemory(*PB_Eingabe)

  TextGadget(14, 10, 350, 100, 20, "Save PB-File ?")
  ButtonGadget(15, 110, 350, 50, 20, "Yes")
  ButtonGadget(16, 180, 350, 50, 20, "No")
  Repeat
    Event = WaitWindowEvent()
    If Event = #PB_Event_CloseWindow
      End 
    EndIf   
  Until EventGadget() = 15 Or EventGadget() = 16

  If EventGadget() = 15
    If Encryption
      SaveFile$ = GetFilePart(SelFile$) + ".PBenc"
     Else          ;Decryption
      SaveFile$ = GetFilePart(SelFile$, #PB_FileSystem_NoExtension) + ".PBdec." + GetExtensionPart(GetFilePart(SelFile$, #PB_FileSystem_NoExtension))
    EndIf
    CreateFile(1, SaveFile$)
    For i = 0 To Chunks - 1
      WriteData(1, *PB_Ausgabe + (i * Cluster), Cluster)
    Next
    WriteData(1, *PB_Ausgabe + (Chunks * Cluster), RestBytes)
    CloseFile(1) 
  EndIf

  FreeMemory(*PB_Ausgabe)
  CloseFile(0)
;-------------------------------------------------------------------------

TextGadget(20, 10, 380, 100, 20, "D O N E !")

FreeMemory(WorkingBuffer)
;FreeGadget... etc.

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
End
;-------------------------------------------------------------------------
DataSection        ;Werte sind natürlich frei wählbar!
  UserKey:
    Data.b $8C, $15, $51, $2C, $0C, $8A, $0A, $D8, $07, $E4, $21, $A2, $8E, $83, $A3, $88     ;0-15: 128-Bit
    Data.b $8A, $CA, $FB, $E1, $7B, $A3, $6B, $D6, $BC, $F7, $E6 ,$CD, $FE, $B5, $D7, $B3     ;0-23: 192-Bit, 0-31: 256-Bit
  UserInitializationVector:
    Data.b $08, $0C, $96, $48, $33, $51, $35, $80, $0C, $A9, $42, $1E, $11, $E0, $83, $C7
EndDataSection
Viel Spaß!
Helle
Antworten