When using AES on PB, the data size does not have to be divisible by 16, since so-called cipher stealing is used.
Unfortunately, this is only half implemented.
Data smaller than 16 bytes still need this.
So this advantage is cancelled out again.
Binary key and IV cannot be generated simply from strings,
which makes handling more difficult and encourages nasty errors.
The functions of this crypter are fully compatible to the original PB functions and solve this problems.
These new functions extend the original PB functions without changing them
and add easy to use functions for Key and IV generating.
This new Crypter simplifies the AES handling significantly.
With this new enhanced functions you can use AES as usual,
but the annoying problem if files, data or strings are smaller than 16 bytes is eliminated
and there is no more complicated key or IV generation.
Data lengths from zero upwards are now supported.
Included are :
String to binary key generating for AES-128.
String to binary key generating for AES-256.
String to binary IV generating
Randomized IV generating.
Limitless PB AES function compatible AESEncoder().
Limitless PB AES function compatible AESDecoder().
String to hash keystretching function with progressbar support.
Advanced StringCrypter with automatic randomized IV, Fake StringLength feature,
automatic Integrity check feature and Compression feature.
Supports UTF8 and UTF16.
UTF8 string files are about 50% smaller than standard UTF16 files.
UTF16 is very fast.
If you encrypt the exact same string million times,
each encrypted file will be have a different content.
You can also use these new functions to encrypt blockwise with Progressbar.
Just increase the IV by one with each new block.
So primarily mostly you do not need the StartAESCipher() and AddCipherBuffer() functions.
It doesn't matter now if the data or strings to be encrypted are smaller or larger than 16 bytes, no padding is needed anymore.
The only thing that changes is that now everything is as extremely simple as you probably always wanted it to be.
Keys and IV are usually implemented incorrectly, so that it cries out for a simple universally usable solution.
Note that for data smaller than 16 Bytes Encrypter and Decrypter work the same.
Therefore, a double encryption with the same Key and IV causes a decryption.
This may be difficult to understand at first, but it is absolutely OK and all works very fine.
Base Code - full featured
Code: Select all
DeclareModule PB_AES_Enhancer
EnableExplicit
Declare Create_16_Byte_Key(key$, salt$="") ; For AES-128
Declare Create_32_Byte_Key(key$, salt$="") ; For AES-256
Declare Create_IV(iv$) ; Binary IV
Declare Create_RND_IV() ; Binary randomized IV
Declare QAESEncoder(*input.byte, *output.byte, size, *key, bits, *iv, modus=#PB_Cipher_CBC) ; Encoder
Declare QAESDecoder(*input.byte, *output.byte, size, *key, bits, *iv, modus=#PB_Cipher_CBC) ; Decoder
Declare.s QAESKeyStretching(window_ID, progressbar_ID, key$, salt$="", key_stretching_loops=1e4) ; Key-stretching
EndDeclareModule
Module PB_AES_Enhancer
; PB AES Functions compatible Crypter with smaller 16 Bytes Fix - By Saki
; < 16 Bytes Encoder and Decoder works at the same
; KeyStretching impeded key brute force quite substantial
UseMD5Fingerprint() : UseSHA3Fingerprint()
Procedure Create_16_Byte_Key(key$, salt$="")
Protected i, ii, stepp=SizeOf(character)<<1 : Static Dim register.q(1)
key$=StringFingerprint(key$+salt$, #PB_Cipher_MD5, 0, #PB_Unicode)
For i=0 To 15 : PokeB(@register(0)+i, Val("$"+PeekS(@key$+ii, 2))) : ii+stepp : Next
ProcedureReturn @register.q(0)
EndProcedure
Procedure Create_32_Byte_Key(key$, salt$="")
Protected i, ii, stepp=SizeOf(character)<<1 : Static Dim register.q(3)
key$=StringFingerprint(key$+salt$, #PB_Cipher_SHA3, 256, #PB_Unicode)
For i=0 To 31 : PokeB(@register(0)+i, Val("$"+PeekS(@key$+ii, 2))) : ii+stepp : Next
ProcedureReturn @register.q(0)
EndProcedure
Procedure Create_IV(iv$)
Protected i, ii, stepp=SizeOf(character)<<1 : Static Dim iv.q(1)
iv$=StringFingerprint(iv$, #PB_Cipher_MD5, 0, #PB_Unicode)
For i=0 To 15 : PokeB(@iv(0)+i, Val("$"+PeekS(@iv$+ii, 2))) : ii+stepp : Next
ProcedureReturn @iv(0)
EndProcedure
Procedure Create_RND_IV()
Static Dim iv.q(1) : If OpenCryptRandom() : CryptRandomData(@iv.q(0), 16) : ProcedureReturn @iv.q(0) : EndIf
ProcedureReturn 0
EndProcedure
Macro common(coder)
If size<16
Protected i, *ii.byte : Dim buffer.q(1) : If modus=#PB_Cipher_CBC : CopyMemory(*iv, @buffer(0), 16) : EndIf
Protected result=AESEncoder(@buffer(0), @buffer(0), 16, *key, bits, 0, #PB_Cipher_ECB)
If Not result : ProcedureReturn 0 : EndIf
; For i=0 To size-1 : PokeB(*output+i, PeekB(@buffer(0)+i) ! PeekB(*input+i)) : Next : ProcedureReturn size ; simple
*ii=@buffer(0)
For i=1 To size : *output\b=*ii\b ! *input\b : *input+1 : *output+1 : *ii+1 : Next
ProcedureReturn size : Else : ProcedureReturn AES#coder(*input, *output, size, *key, bits, *iv, modus)
EndIf
EndMacro
Procedure QAESEncoder(*input.byte, *output.byte, size, *key, bits, *iv, modus=#PB_Cipher_CBC)
common(Encoder)
EndProcedure
Procedure QAESDecoder(*input.byte, *output.byte, size, *key, bits, *iv, modus=#PB_Cipher_CBC)
common(Decoder)
EndProcedure
Procedure.s QAESKeyStretching(window_ID, progressbar_ID, key$, salt$="", key_stretching_loops=1e4)
Protected get_time.q , i ; by walbus
get_time=ElapsedMilliseconds()
For i=1 To key_stretching_loops ; Iterations
key$=ReverseString(salt$)+key$+salt$+ReverseString(key$)
key$=Fingerprint(@key$, StringByteLength(key$), #PB_Cipher_SHA3, 512)
If IsWindow(window_ID) And IsGadget(progressbar_ID)
If ElapsedMilliseconds()>get_time+100
SetGadgetState(progressbar_ID, 100*i/key_stretching_loops)
get_time.q=ElapsedMilliseconds()
EndIf
EndIf
Next i
key$=ReverseString(key$)+salt$+key$+ReverseString(key$)
key$=Fingerprint(@key$, StringByteLength(key$), #PB_Cipher_SHA3, 512) ; Finalize
If IsGadget(progressbar_ID)
SetGadgetState(progressbar_ID, 100)
EndIf
Delay(100)
ProcedureReturn key$
EndProcedure
EndModule
UseModule PB_AES_Enhancer
; ######################### Use the module ##########################
EnableExplicit
Define source$="ABCDEF"; GHIJKLMNOP" ; GHIJKLMNOPQRSTUVWXYZ0123456789" ; You can change how ever you want
Define destination$=Space(Len(source$))
Define password$="Hello Password"
Define iv$="123456"
; With KeyStretching - 1e4 Loops
Define key$=QAESKeyStretching(0, 0, Password$, iv$, 1e4)
Debug "KeyStretching Sample : "+key$
Debug ""
Debug "Bytes encrypted : "+QAESEncoder(@source$, @destination$, StringByteLength(source$), Create_32_Byte_Key(key$), 256, Create_IV(iv$))
Debug destination$
Debug " "
Debug "Bytes decrypted : "+QAESDecoder(@destination$, @source$, StringByteLength(source$), Create_32_Byte_Key(key$), 256, Create_IV(iv$))
Debug source$
Debug ""
; Without KeyStretching
Debug "Bytes encrypted : "+QAESEncoder(@source$, @destination$, StringByteLength(source$), Create_32_Byte_Key(Password$), 256, Create_IV(iv$))
Debug destination$
Debug " "
Debug "Bytes decrypted : "+QAESDecoder(@destination$, @source$, StringByteLength(source$), Create_32_Byte_Key(Password$), 256, Create_IV(iv$))
Debug source$
Code: Select all
DeclareModule PB_AES_Enhancer
EnableExplicit
Declare Create_16_Byte_Key(key$, salt$="") ; For AES-128
Declare Create_32_Byte_Key(key$, salt$="") ; For AES-256
Declare Create_IV(iv$) ; Binary IV
Declare Create_RND_IV() ; Binary randomized IV
Declare QAESEncoder(*input.byte, *output.byte, size, *key, bits, *iv, modus=#PB_Cipher_CBC) ; Encoder
Declare QAESDecoder(*input.byte, *output.byte, size, *key, bits, *iv, modus=#PB_Cipher_CBC) ; Decoder
Declare.s QAESKeyStretching(window_ID, progressbar_ID, key$, salt$="", key_stretching_loops=1e4) ; Key-stretching
; String crypter with automatically randomized IV, fake length, intergrity check and compression - UTF8 and UTF16
; UTF16 mode=0 / UTF8 mode=1 - UTF8 files are ~50% smaller - UTF16 is very fast
; ..._fake_length - Blur the real string length
Declare QAES_Write_encrypted_string_file(string$, destination_path$, key$, mode=0, min_fake_length=0, max_fake_length=0, check=0, compressing=0) ; WriteFile fail = -1
Declare.s QAES_Read_encrypted_string_file(destination_path$, key$, mode=0, check=0, compressing=0)
Declare QAESCheckIntegrity() ; Check the integrity of the string after decrypting a string file
Declare QAESCheckDecrypter() ; Check the string decrypter state after decrypting a string file - ReadFile fail = -1
Declare QAESGetCompressedDataPercent() ; Get the compressed size as percent
Declare QAESUseHash(Hash_length_=32) ; You can set a integrity check hash from 4 to 32Bytes length (Preset=32)
Declare.s QAESGetUsedPath() ; Get the used path
EndDeclareModule
Module PB_AES_Enhancer
; PB AES Functions compatible Crypter with smaller 16 Bytes Fix - By Saki
; With advanced string crypter
; < 16 Bytes Encoder and Decoder works at the same
; KeyStretching impeded key brute force quite substantial
UseCRC32Fingerprint() : UseMD5Fingerprint() : UseSHA3Fingerprint() : UseLZMAPacker()
Global QAESCheckIntegrity, QAESCheckDecrypter
Global QAESGetCompressedDataPercent, Hash_length=32, QAESGetUsedPath$
Procedure.s GetCheckHash(string$)
If Hash_length>16
ProcedureReturn StringFingerprint(string$, #PB_Cipher_SHA3, 256, #PB_Unicode)
ElseIf Hash_length>4
ProcedureReturn StringFingerprint(string$, #PB_Cipher_MD5, 0, #PB_Unicode)
EndIf
ProcedureReturn StringFingerprint(string$, #PB_Cipher_CRC32, 0, #PB_Unicode)
EndProcedure
Procedure Create_16_Byte_Key(key$, salt$="")
Protected i, ii, stepp=SizeOf(character)<<1 : Static Dim register.q(1)
key$=StringFingerprint(key$+salt$, #PB_Cipher_MD5, 0, #PB_Unicode)
For i=0 To 15 : PokeB(@register(0)+i, Val("$"+PeekS(@key$+ii, 2))) : ii+stepp : Next
ProcedureReturn @register.q(0)
EndProcedure
Procedure Create_32_Byte_Key(key$, salt$="")
Protected i, ii, stepp=SizeOf(character)<<1 : Static Dim register.q(3)
key$=StringFingerprint(key$+salt$, #PB_Cipher_SHA3, 256, #PB_Unicode)
For i=0 To 31 : PokeB(@register(0)+i, Val("$"+PeekS(@key$+ii, 2))) : ii+stepp : Next
ProcedureReturn @register.q(0)
EndProcedure
Procedure Create_IV(iv$)
Protected i, ii, stepp=SizeOf(character)<<1 : Static Dim iv.q(1)
iv$=StringFingerprint(iv$, #PB_Cipher_MD5, 0, #PB_Unicode)
For i=0 To 15 : PokeB(@iv(0)+i, Val("$"+PeekS(@iv$+ii, 2))) : ii+stepp : Next
ProcedureReturn @iv(0)
EndProcedure
Procedure Create_RND_IV()
Static Dim iv.q(1) : If OpenCryptRandom() : CryptRandomData(@iv.q(0), 16) : ProcedureReturn @iv.q(0) : EndIf
ProcedureReturn 0
EndProcedure
Macro common(coder)
If size<16
Protected i, *ii.byte : Dim buffer.q(1)
Protected result=AESEncoder(@buffer(0), @buffer(0), 16, *key, bits, *iv, #PB_Cipher_CBC)
If Not result : ProcedureReturn 0 : EndIf
; For i=0 To size-1 : PokeB(*output+i, PeekB(@buffer(0)+i) ! PeekB(*input+i)) : Next : ProcedureReturn size ; simple
*ii=@buffer(0) : For i=1 To size : *output\b=*ii\b ! *input\b : *input+1 : *output+1 : *ii+1 : Next
ProcedureReturn size : Else : ProcedureReturn AES#coder(*input, *output, size, *key, bits, *iv, modus)
EndIf
EndMacro
Procedure QAESEncoder(*input.byte, *output.byte, size, *key, bits, *iv, modus=#PB_Cipher_CBC)
common(Encoder)
EndProcedure
Procedure QAESDecoder(*input.byte, *output.byte, size, *key, bits, *iv, modus=#PB_Cipher_CBC)
common(Decoder)
EndProcedure
Procedure.s QAESKeyStretching(window_ID, progressbar_ID, key$, salt$="", key_stretching_loops=1e4)
Protected get_time.q , i ; by walbus
get_time=ElapsedMilliseconds()
For i=1 To key_stretching_loops ; Iterations
key$=ReverseString(salt$)+key$+salt$+ReverseString(key$)
key$=Fingerprint(@key$, StringByteLength(key$), #PB_Cipher_SHA3, 512)
If IsWindow(window_ID) And IsGadget(progressbar_ID)
If ElapsedMilliseconds()>get_time+100
SetGadgetState(progressbar_ID, 100*i/key_stretching_loops)
get_time.q=ElapsedMilliseconds()
EndIf
EndIf
Next i
key$=ReverseString(key$)+salt$+key$+ReverseString(key$)
key$=Fingerprint(@key$, StringByteLength(key$), #PB_Cipher_SHA3, 512) ; Finalize
If IsGadget(progressbar_ID)
SetGadgetState(progressbar_ID, 100)
EndIf
Delay(100)
ProcedureReturn key$
EndProcedure
Procedure QAES_Write_encrypted_string_file(string$, destination_path$, key$, mode=0, min_fake_length=0, max_fake_length=0, check=0, compressing=0)
QAESGetCompressedDataPercent=0
QAESGetUsedPath$=destination_path$
Protected QAESGetCompressedSize, QAESGetUncompressedSize
Protected file=CreateFile(#PB_Any, destination_path$), *buffer, *buffer_1, *buffer_2, i, ii, stepp=SizeOf(character)<<1
If Not file : ProcedureReturn -1 : EndIf
If min_fake_length<0 : min_fake_length=0 : EndIf
If max_fake_length<0 : max_fake_length=0 : EndIf
Protected Dim iv.q(1), seed.q
If OpenCryptRandom()
If min_fake_length>0 Or max_fake_length>0
CryptRandomData(@seed, 8)
EndIf
CryptRandomData(@iv(0), 16)
Else
If min_fake_length>0 Or max_fake_length>0
RandomData(@seed, 8)
EndIf
RandomData(@iv(0), 16)
EndIf
Protected *iv=@iv(0), *key=Create_32_Byte_Key(key$)
RandomSeed(seed)
If mode=1
*buffer=UTF8(string$)
If Not *buffer : ProcedureReturn -2 : EndIf
If seed
If min_fake_length>max_fake_length : max_fake_length=min_fake_length : EndIf
Protected rnd_fake_length=Random(max_fake_length, min_fake_length)
*buffer_1=AllocateMemory(MemorySize(*buffer)+rnd_fake_length)
If rnd_fake_length>0
RandomData(*buffer_1+MemorySize(*buffer_1)-rnd_fake_length, rnd_fake_length)
EndIf
If Not *buffer_1 : FreeMemory(*buffer) : ProcedureReturn -3 : EndIf
CopyMemory(*buffer, *buffer_1, MemorySize(*buffer))
Swap *buffer, *buffer_1
FreeMemory(*buffer_1)
EndIf
Else
If seed
If min_fake_length>max_fake_length : max_fake_length=min_fake_length : EndIf
Protected StringByteLength_=StringByteLength(string$)
*buffer=AllocateMemory(StringByteLength_+1+rnd_fake_length)
If rnd_fake_length>0
RandomData(*buffer+StringByteLength_+1-rnd_fake_length, rnd_fake_length)
EndIf
Else
*buffer=AllocateMemory(StringByteLength(string$)+1)
EndIf
If Not *buffer : ProcedureReturn -4 : EndIf
EndIf
If Not mode
CopyMemory(@string$, *buffer, MemorySize(*buffer)-1)
EndIf
*buffer_2=AllocateMemory(MemorySize(*buffer))
If Not *buffer_2 : FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -5 : EndIf
Protected Dim compressed.q(1)
QAESGetUncompressedSize=MemorySize(*buffer)-1
If compressing
compressed(0)=CompressMemory(*buffer, MemorySize(*buffer), *buffer_2, MemorySize(*buffer))
QAESGetCompressedSize=compressed(0)
EndIf
If Not compressed(0) : CopyMemory(*buffer, *buffer_2, MemorySize(*buffer)) : EndIf
If QAESGetUncompressedSize>0
If QAESGetCompressedSize>QAESGetUncompressedSize
QAESGetCompressedDataPercent=-1
Else
QAESGetCompressedDataPercent=100/QAESGetUncompressedSize*QAESGetCompressedSize
EndIf
EndIf
If compressed(0)
compressed(1)=MemorySize(*buffer)
If Not QAESEncoder(*buffer_2, *buffer, compressed(0), *key, 256, *iv, #PB_Cipher_CBC)
FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -6
EndIf
If WriteData(file, *buffer, compressed(0))<>compressed(0)
FreeMemory(*buffer) : FreeMemory(*buffer_2) : CloseFile(file) : ProcedureReturn -7
EndIf
Else
If Not QAESEncoder(*buffer, *buffer_2, MemorySize(*buffer), *key, 256, *iv, #PB_Cipher_CBC)
FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -8
EndIf
If WriteData(file, *buffer_2, MemorySize(*buffer))<>MemorySize(*buffer)
FreeMemory(*buffer) : FreeMemory(*buffer_2) : CloseFile(file) : ProcedureReturn -9
EndIf
EndIf
FreeMemory(*buffer_2)
If WriteData(file, @iv(0), 16)<>16 : FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -10 : EndIf
FreeMemory(*buffer)
If check
Protected hash$=GetCheckHash(string$)
*buffer=AllocateMemory(Hash_length)
If Not *buffer : CloseFile(file) : ProcedureReturn -11 : EndIf
For i=0 To Hash_length-1 : PokeB(*buffer+i, Val("$"+PeekS(@hash$+ii, 2))) : ii+stepp : Next
If Hash_length>16
If Not QAESEncoder(*buffer, *buffer, 16, *key, 256, *iv, #PB_Cipher_CBC)
FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -12
EndIf
If Not QAESEncoder(*buffer+16, *buffer+16, Hash_length-16, *key, 256, *iv, #PB_Cipher_CBC)
FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -13
EndIf
Else
If Not QAESEncoder(*buffer, *buffer, Hash_length, *key, 256, *iv, #PB_Cipher_CBC)
FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -14
EndIf
EndIf
If WriteData(file, *buffer, Hash_length)<>Hash_length : FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -15 : EndIf
FreeMemory(*buffer)
EndIf
If compressing
If Not QAESEncoder(@compressed(0), @compressed(0), 16, *key, 256, *iv, #PB_Cipher_CBC)
CloseFile(file) : ProcedureReturn -16
EndIf
If WriteData(file, @compressed(0), 16)<>16 : CloseFile(file) : ProcedureReturn -17 : EndIf ; ###############
EndIf
CloseFile(file)
Create_32_Byte_Key(" ") ; Clear from ram after processing
ProcedureReturn 1
EndProcedure
Procedure.s QAES_Read_encrypted_string_file(destination_path$, key$, mode=0, check=0, compressing=0)
QAESGetCompressedDataPercent=0
QAESGetUsedPath$=destination_path$
Protected QAESGetCompressedSize, QAESGetUncompressedSize
Protected compress_offset, *buffer, *buffer_1, *buffer_2, i, ii, stepp=SizeOf(character)<<1
If compressing : compress_offset=16 : EndIf
Macro FreeMem
If *buffer : FreeMemory(*buffer) : EndIf
If *buffer_1 : FreeMemory(*buffer_1) : EndIf
EndMacro
Protected file=ReadFile(#PB_Any, destination_path$)
If Not file : QAESCheckDecrypter=-1 : ProcedureReturn "" : EndIf
If file
If Not Lof(file)=>16+check+compress_offset : QAESCheckDecrypter=-2 : ProcedureReturn "" : EndIf
If check : check=Hash_length : EndIf
Protected Dim compressed.q(1), Dim iv.q(1)
FileSeek(file, Lof(file)-16-check-compress_offset)
If ReadData(file, @iv(0), 16)<>16 : QAESCheckDecrypter=-3 : CloseFile(file) : ProcedureReturn "" : EndIf
Protected *iv=@iv(0), *key=Create_32_Byte_Key(key$)
If compressing
FileSeek(file, Lof(file)-compress_offset)
If ReadData(file, @compressed(0), 16)<>16 : QAESCheckDecrypter=-4 : CloseFile(file) : ProcedureReturn "" : EndIf
If Not QAESDecoder(@compressed(0), @compressed(0), 16, *key, 256, *iv, #PB_Cipher_CBC)
QAESCheckDecrypter=-5 : ProcedureReturn ""
EndIf
If PeekW(@compressed(0)+6) Or PeekW(@compressed(1)+6)
CloseFile(file) : QAESCheckDecrypter=-6 : ProcedureReturn ""
EndIf
EndIf
If check
*buffer_1=AllocateMemory(Hash_length)
If Not *buffer_1 : CloseFile(file) : QAESCheckDecrypter=-7 : ProcedureReturn "" : EndIf
FileSeek(file, Lof(file)-check-compress_offset)
If ReadData(file, *buffer_1, Hash_length)<>Hash_length : FreeMem : QAESCheckDecrypter=-8 : CloseFile(file) : ProcedureReturn "" : EndIf
EndIf
If compressed(0)
*buffer=AllocateMemory(compressed(0))
Else
*buffer=AllocateMemory(Lof(file)-16-check-compress_offset)
EndIf
If Not *buffer : FreeMem : QAESCheckDecrypter=-9 : ProcedureReturn "" : EndIf
FileSeek(file, 0)
If ReadData(file, *buffer, Lof(file)-16-check-compress_offset)<>Lof(file)-16-check-compress_offset
QAESCheckDecrypter=-10 : FreeMem : CloseFile(file) : ProcedureReturn ""
EndIf
If compressed(0)
*buffer_2=AllocateMemory(compressed(1))
Else
*buffer_2=AllocateMemory(MemorySize(*buffer))
EndIf
If Not *buffer_2 : FreeMem : QAESCheckDecrypter=-11 : CloseFile(file) : ProcedureReturn "" : EndIf
If Not QAESDecoder(*buffer, *buffer_2, MemorySize(*buffer), *key, 256, *iv, #PB_Cipher_CBC)
FreeMem : QAESCheckDecrypter=-12 : FreeMemory(*buffer_2) : CloseFile(file): ProcedureReturn ""
EndIf
QAESGetUncompressedSize=compressed(1)
If compressed(0)
FreeMemory(*buffer)
*buffer=AllocateMemory(compressed(1))
QAESGetCompressedSize=UncompressMemory(*buffer_2, compressed(0), *buffer, compressed(1))
If QAESGetCompressedSize<1
QAESGetCompressedSize=0 : FreeMem : QAESCheckDecrypter=-13 : FreeMemory(*buffer_2) : CloseFile(file) : ProcedureReturn ""
EndIf
EndIf
If QAESGetUncompressedSize>0
If QAESGetCompressedSize>QAESGetUncompressedSize
QAESGetCompressedDataPercent=-1
Else
QAESGetCompressedDataPercent=100/QAESGetUncompressedSize*QAESGetCompressedSize
EndIf
EndIf
If mode=1
If compressed(0)
Protected string$=PeekS(*buffer, -1, #PB_UTF8)
Else
string$=PeekS(*buffer_2, -1, #PB_UTF8)
EndIf
Else
If compressed(0)
string$=Space(compressed(1))
CopyMemory(*buffer, @string$, compressed(1))
Else
string$=Space(MemorySize(*buffer_2))
CopyMemory(*buffer_2, @string$, MemorySize(*buffer))
EndIf
EndIf
FreeMemory(*buffer)
FreeMemory(*buffer_2)
CloseFile(file)
If check
Protected hash$=GetCheckHash(string$)
*buffer=AllocateMemory(Hash_length)
If Not *buffer : QAESCheckDecrypter=-14 : FreeMem : ProcedureReturn "" : EndIf
For i=0 To Hash_length-1 : PokeB(*buffer+i, Val("$"+PeekS(@hash$+ii, 2))) : ii+stepp : Next
If Hash_length>16
If Not QAESDEcoder(*buffer_1, *buffer_1, 16, *key, 256, *iv, #PB_Cipher_CBC)
FreeMem : QAESCheckDecrypter=-15 : ProcedureReturn ""
EndIf
If Not QAESDecoder(*buffer_1+16, *buffer_1+16, Hash_length-16, *key, 256, *iv, #PB_Cipher_CBC)
FreeMem : QAESCheckDecrypter=-16 : ProcedureReturn ""
EndIf
Else
If Not QAESDEcoder(*buffer_1, *buffer_1, Hash_length, *key, 256, *iv, #PB_Cipher_CBC)
FreeMem : QAESCheckDecrypter=-17 : ProcedureReturn ""
EndIf
EndIf
QAESCheckIntegrity=CompareMemory(*buffer, *buffer_1, MemorySize(*buffer))
FreeMemory(*buffer)
EndIf
Create_32_Byte_Key(" ") ; Clear from ram after processing
EndIf
QAESCheckDecrypter=1
ProcedureReturn string$
EndProcedure
Procedure QAESCheckIntegrity()
ProcedureReturn QAESCheckIntegrity
EndProcedure
Procedure QAESCheckDecrypter()
ProcedureReturn QAESCheckDecrypter
EndProcedure
Procedure QAESGetCompressedDataPercent()
ProcedureReturn QAESGetCompressedDataPercent
EndProcedure
Procedure QAESUseHash(Hash_length_=32)
If Hash_length_>3 And Hash_length_<33
Hash_length=Hash_length_
ProcedureReturn Hash_length
Else
MessageRequester(" QAESUseHash", "Set 4 > 32")
End
EndIf
EndProcedure
Procedure.s QAESGetUsedPath()
ProcedureReturn QAESGetUsedPath$
EndProcedure
EndModule
UseModule PB_AES_Enhancer
; ######################### Use the module ##########################
EnableExplicit
QAESUseHash(16) ; You can set a integrity check hash from 4 to 32Bytes length (Preset=32)
Define source$="ABCDEFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaX"; GHIJKLMNOP" ; GHIJKLMNOPQRSTUVWXYZ0123456789" ; You can change how ever you want
Define destination$=Space(Len(source$))
Define password$="Hello Password"
Define iv$="123456"
; With KeyStretching - 1e4 Loops
Define key$=QAESKeyStretching(0, 0, Password$, iv$, 1e4)
Debug "KeyStretching Sample : "+key$
Debug ""
Debug "Bytes encrypted : "+QAESEncoder(@source$, @destination$, StringByteLength(source$), Create_32_Byte_Key(key$), 256, Create_IV(iv$))
Debug destination$
Debug " "
Debug "Bytes decrypted : "+QAESDecoder(@destination$, @source$, StringByteLength(source$), Create_32_Byte_Key(key$), 256, Create_IV(iv$))
Debug source$
Debug ""
; Without KeyStretching
Debug "Bytes encrypted : "+QAESEncoder(@source$, @destination$, StringByteLength(source$), Create_32_Byte_Key(Password$), 256, Create_IV(iv$))
Debug destination$
Debug " "
Debug "Bytes decrypted : "+QAESDecoder(@destination$, @source$, StringByteLength(source$), Create_32_Byte_Key(Password$), 256, Create_IV(iv$))
Debug source$
Debug ""
; String to file crypting
Define mode=1 ; 0=UTF16 - 1=UTF8
Define compressing=1 ; Use compression
Define path$=GetUserDirectory(#PB_Directory_Desktop)+"Encrypted_String"
Debug "String encrypt State : "+QAES_Write_encrypted_string_file(source$, path$, password$, mode, 0, 0, 0, compressing)
Debug QAESGetUsedPath() ; Get the used path
Debug "Compressed data size as percent "+QAESGetCompressedDataPercent() ; Get the compressed size as percent
Debug QAES_Read_encrypted_string_file(path$, password$, mode, 0, compressing)
Debug " "
; String to file crypting - Randomized length
Define min_fake_length=5
Define max_fake_length=30
Define mode=0 ; 0=UTF16 - 1=UTF8
Define path$=GetUserDirectory(#PB_Directory_Desktop)+"Encrypted_String_Randomized_length"
Debug "String encrypt State : "+QAES_Write_encrypted_string_file(source$, path$, password$, mode, min_fake_length, max_fake_length, 0, compressing)
Debug QAESGetUsedPath() ; Get the used path
Debug "Compressed data size as percent "+QAESGetCompressedDataPercent() ; Get the compressed size as percent
Debug "String decrypted : "
Debug QAES_Read_encrypted_string_file(path$, password$, mode, 0, compressing)
Debug " "
; String to file crypting - Randomized length - String Check
Define check=1
Define mode=1 ; 0=UTF16 - 1=UTF8
Define path$=GetUserDirectory(#PB_Directory_Desktop)+"Encrypted_String_Randomized_length_and_Check"
Debug "String encrypt State : "+QAES_Write_encrypted_string_file(source$, path$, password$, mode, min_fake_length, max_fake_length, check, compressing)
Debug QAESGetUsedPath() ; Get the used path
Debug "Compressed data size as percent "+QAESGetCompressedDataPercent() ; Get the compressed size as percent
Debug "String decrypted : "
Debug QAES_Read_encrypted_string_file(path$, password$, mode, check, compressing)
Debug "State Decrypter after decrypting : "+QAESCheckDecrypter() ; Check the string decrypter state after decrypting a string file
Debug "State decrypted String integrity check : "+QAESCheckIntegrity() ; Check the integrity of the string after decrypting a string file