PB kompatibles AES-Padding
Verfasst: 12.03.2021 18:39
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).
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