QAES AES256 KFB mode special coder for string, binary, text

Share your advanced PureBasic knowledge/code with the community.
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2071
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

QAES AES256 KFB mode special coder for string, binary, text

Post by Andre »

Here is a new code - made by and thanks to Werner Albus - showing secure AES encryption/decryption for all possible items: strings, binary and text files (including 'in-place' en-/decryption):

Note (29th July 2019): for a new and alternative version of this module (which is not 'Key'-compatible) see below!

Code: Select all

DeclareModule QAES_smart_universal_coder_KFB
  Declare QAES_smart_universal_coder_KFB(mode, *buffer_in.word, *buffer_out.word, bytes.q, key$, counter_key.q=0, counter_aes.q=0)
  UseSHA3Fingerprint()
EndDeclareModule

Module QAES_smart_universal_coder_KFB
  EnableExplicit
  
  ;- QAES AES256 KFB mode special coder for all things - binarys - strings - text files -----
  
  ; This coder can handle automatic string termination for any strings - In compiler mode ASCII and UNICODE !
  ; The coder works with all data lengths, also <16 bytes
  
  ; mode=0 - Mode BINARY, you can encrypt binary data, don't use this for on demand string encryption, it break the string termination!
  ; mode=1 - Mode ASCII, you can encrypt mixed data, string and binary - This ignore the encryption of zero bytes, recommended for mixed datea with ASCII strings.
  ; mode=2 - Mode UNICODE, you can encrypt mixed data, ascii strings, unicode strings and binary - This ignore the encryption of zero bytes.
  ; The coder go always forward, an extra decoder isn't necessary, just use exactly the same calling convention for encrypting and decrypting!
  ; You cipher a file blockwise, always set the current block number (consecutive) with the counter - Important, then the result look similar to CBC mode encryption!
  
  ; Author Werner Albus - www.nachtoptik.de
  ; No warranty whatsoever - Use at your own risk
  ; PureBasic
  
  ; counter_key.q   : You cipher a file blockwise, always set the current block number with this counter (consecutive numbering).
  ; counter_aes.q   : This counter will be automatically used by the coder, but you can change the startpoint, this chance same the counter_key the encryption absolutely
  ;                 : The counter_aes you can use as sample for setting a randomized startpoint for using with the file coder addon protection function
  ;                 : With used counters and salt you can personalize the coder, nobody can brute force a password from a unknown personalized coder
  ;                 : You can set the counter as quad, positive and negative
  ; key$            : You can use any strings as key
  ; *buffer_in      : Set the adress to the source data
  ; *buffer_out     : Set the adress to the destination data - Hint : It can also use the same place as the plain data.
  ; mode            : Set mode=0 for binary files - Set mode=1 for ASCII strings - Set mode=2 for UNICODE strings
  
  Procedure QAES_smart_universal_coder_KFB(mode, *buffer_in.word, *buffer_out.word, bytes.q, key$, counter_key.q=0, counter_aes.q=0)
    If Not bytes.q Or key$="" : ProcedureReturn 0  : EndIf
    
    #Salt$="t8690352cj2p1ch7fgw34u&=)?=)/%&§/&)=?(otmq09745$%()=)&%"  ; TODO: Salt, you can change
    Protected.q i, swap_, rounds.q=bytes>>4
    Protected ii, iii, bytes_minus_x, stepp=SizeOf(character)<<1
    Protected *register_asc.ascii, *register.word, *buffer_in_quad.quad, *buffer_out_quad.quad
    Protected remaining=bytes%16, bytes_minus_1=bytes-1
    Protected *buffer_in_asc.ascii, *buffer_out_asc.ascii
    Protected hash$=#Salt$+key$+Str(counter_key)+ReverseString(#Salt$)
    Static fixed_key_string${64}
    Static Dim register.q(3)
    
    fixed_key_string$=Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, 256) ; Create a key
    For ii = 0 To 31 : PokeA(@register(0)+ii, Val("$"+PeekS(@fixed_key_string$+iii, 2))) : iii+stepp : Next
    
    register(1)+counter_aes
    
    Macro go_1 ; Crypter
      If Not AESEncoder(@register(0), @register(0), 32, @register(0), 256, 0, #PB_Cipher_ECB) : ProcedureReturn 0 : EndIf
    EndMacro
    
    If Not mode ; Binary mode
      *buffer_in_quad.quad=*buffer_in.word : *buffer_out_quad.quad=*buffer_out.word
      If bytes<16 ; Less 16 bytes
        *buffer_out_asc=*buffer_out_quad : *buffer_in_asc=*buffer_in_quad : *register_asc=@register(0)
        go_1
        For ii=0 To bytes_minus_1
          *buffer_out_asc\a=*buffer_in_asc\a ! *register_asc\a : *buffer_in_asc+1 : *buffer_out_asc+1 : *register_asc+1
        Next
        ProcedureReturn 1
      EndIf
      While i<rounds ; =>16 bytes
        go_1
        *buffer_out_quad\q=*buffer_in_quad\q ! register(0) : *buffer_in_quad+8 : *buffer_out_quad+8
        *buffer_out_quad\q=*buffer_in_quad\q ! register(1) : *buffer_in_quad+8 : *buffer_out_quad+8 : i+1
      Wend
      If remaining
        *buffer_out_asc=*buffer_out_quad : *buffer_in_asc=*buffer_in_quad : *register_asc=@register(0)
        go_1
        For ii=0 To remaining-1
          *buffer_out_asc\a=*buffer_in_asc\a ! *register_asc\a : *buffer_in_asc+1 : *buffer_out_asc+1 : *register_asc+1
        Next
      EndIf
    ElseIf mode=1
      bytes_minus_x=bytes-2
      *buffer_in_asc=*buffer_in : *buffer_out_asc=*buffer_out
      Repeat
        go_1 : *register_asc=@register(0)
        For ii=0 To 15
          If *buffer_in_asc\a And *buffer_in_asc\a ! *register_asc\a
            *buffer_out_asc\a=*buffer_in_asc\a ! *register_asc\a
          Else
            *buffer_out_asc\a=*buffer_in_asc\a
          EndIf
          If i>bytes_minus_x : Break 2 : EndIf
          *buffer_in_asc+1 : *buffer_out_asc+1 : *register_asc+1 : i+1
        Next ii
      ForEver
    Else ; mode=2
      bytes_minus_x=bytes-3
      Repeat
        go_1 : *register.word=@register(0)
        For ii=0 To 15 Step 2
          If *buffer_in\w And *buffer_in\w ! *register\w
            *buffer_out\w=*buffer_in\w ! *register\w
          Else
            *buffer_out\w=*buffer_in\w
          EndIf
          If i>bytes_minus_x : Break 2 : EndIf
          *buffer_in+2 : *buffer_out+2 : *register+2 : i+2
        Next ii
      ForEver
    EndIf
    ProcedureReturn 1
  EndProcedure
  
EndModule
UseModule QAES_smart_universal_coder_KFB

; ===== File coder addon for the universal AES256 based QAES_smart_universal_coder_KFB =====

DeclareModule QAES_smart_file_coder
  UseModule QAES_smart_universal_coder_KFB
  Declare.s QAES_smart_file_coder(mode, window_ID, progressbar_ID, path_1$, key_1$, file_extender$="", set_counter_protection_mode.q=0)
  Declare QAES_get_cryptextender_length()
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    Declare FixWriteData(file, *adress, length) ; Workaround for Linux PB 560
  CompilerEndIf
EndDeclareModule

Module QAES_smart_file_coder
  ; Smart file crypting addon or the QAES_smart_universal_coder_KFB
  ; Its nice you set a hint in your software for using QAES contents
  
  ; This addon can protect or encrypt and decrypt files using the QAES_smart_universal_coder_KFB module
  ; The encrypted files do not have visible headers or extenders
  ; Works with all file lengths
  ; No separate decrypter necessary
  ; With integrated full automatic working crypt randomized counter
  ; With full automatic file integrity check
  ; Can full automatic check whether a file is encrypted
  ; Various files with the same content are encrypted ever completely differently
  ; Author Werner Albus - www.nachtoptik.de - www.quick-aes-256.de
  ; No warranty whatsoever - Use at your own risk
  
  EnableExplicit
  
  Global cryptextender_length
  
  Procedure QAES_get_cryptextender_length()
    ProcedureReturn cryptextender_length
  EndProcedure
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    Procedure FixWriteData(file, *adress, length) ; Workaround for Linux PB560
      Protected write_data_pointer=Loc(file)
      Protected writen_data=WriteData(file, *adress, length)
      FileSeek(file, write_data_pointer+writen_data)
      ProcedureReturn writen_data
    EndProcedure
    Macro WriteData(File, Buffer, Size)
      FixWriteData(File, Buffer, Size)
    EndMacro
  CompilerEndIf
  
  Procedure.s QAES_smart_file_coder(mode, window_ID, progressbar_ID, path_1$, key_1$, file_extender$="", set_counter_protection_mode.q=0)
    ; mode=0 - Full automatic mode with file selectors
    ; mode=1 - Encrypt or add a file protection
    ; mode=2 - Decrypt or remove a file protection
    ; mode=3 - Check the file integrity
    ; mode=4 - Check if a file is already encrypted or protected
    
    ; set_counter_protection_mode <> 0 - activate the file protection mode
    ; This protect a file, but dont encrypt the file
    ; Mostly files you can normaly use protected
    ; Set on this variable your defined counter_aes from the universal crypter
    
    ; If not window_ID or not progressbar_ID, you get not a progressbar
    ; A empty key (Password) open automatically a string selector
    
    ; CompilerIf #PB_Compiler_Debugger : MessageRequester("Debugger", "Please deactivate firstly the debugger !") : ProcedureReturn "" : CompilerEndIf
    
    #HashLength=256 ; (224, 256, 384, 512) You can use all available hash lengths divisible by 2 and also different hashes
    
    #Salt$="59#ö#3:_,.45ß$/($(/=)?=JjB$§/(&=$?=)((/&)%WE/()T&%z#'" ; Salt - You can change
    
    #EnlargeFIleLengthBytes=128   ; You can change
    #RandomizeFileLengthBytes=256 ; This feature change full automatic and randomized the length from any encrypted files
    
    #Hints="QUICK-AES-256 (QAES) AES256 KFB crypter"+#CRLF$+
           "No warranty whatsoever - Use at your own risk"+#CRLF$+#CRLF$   
    
    restart:
    Protected cryptextender_length=8+8+8+#HashLength>>3
    Protected path$="", hash$, key$, message$, method_0$, method__0$, method___0$
    Protected method_1$, method__1$, method___1$, hash_1$="", key_2$, hash_2$=""
    Protected file, readed, writen=0, check_integrity=0, file_broken=0, block_size, window_event, result
    Protected progressbar_state, encrypted_file_found=0, hash_bytes, i, key_presetted, blocks, remaining, block_counter=0
    Protected file_size.q, fake_length.q, get_fake_length.q, get_counter.q, counter.q, counter_0.q, get_magic.q, magic.q
    Protected crypt_random.c, set_fake_length.q, set_fake_length_1.q, counter_1.q=345645758512426756724 ; Preset startpoint counter 1 - You can change
    Protected Dim hash.q(#HashLength>>3-1)
    Protected *buffer, *fake_content
    
    If set_counter_protection_mode
      counter=set_counter_protection_mode
      magic.q=275390641757985374251 ; Preset protected marker - You can change
      method_0$=" protected " : method__0$=" protect "
      method_1$=" unprotected " : method__1$=" unprotect "
    Else
      If OpenCryptRandom() : crypt_random=1 : CryptRandomData(@counter, 8) : Else : crypt_random=0 : RandomData(@counter, 8) : EndIf
      
      set_fake_length.q=CryptRandom(#RandomizeFileLengthBytes)+#EnlargeFIleLengthBytes
      
      If Not counter
        If Not mode
          MessageRequester("ERROR", "Can not create counter")
        Else
          ProcedureReturn "ERROR ##01QF - Can not create counter !"
        EndIf
        ProcedureReturn ""
      EndIf
      magic.q=415628580943792148170 ; Preset crypt marker - You can change
      method_0$=" encrypted " : method__0$=" encrypt " : : method___0$=" crypting "
      method_1$=" decrypted " : : method__1$=" decrypt "
    EndIf
    
    If *buffer : FreeMemory(*buffer) : *buffer=0 : EndIf
    
    If mode Or path_1$<>"" : path$=path_1$ : path_1$="" : EndIf
    
    If IsWindow(window_ID) : progressbar_state=1 : EndIf
    
    If IsGadget(progressbar_ID)
      SetGadgetState(progressbar_ID, 0) : progressbar_state+1
    EndIf
    
    If Len(Fingerprint(@magic, 8, #PB_Cipher_SHA3, #HashLength))<>#HashLength>>2 ; Test Fingerprint
      If Not mode
        MessageRequester("ERROR", "Fingerprint fails")
      Else
        ProcedureReturn "ERROR ##02QF - Fingerprint fails !"
      EndIf
      ProcedureReturn ""
    EndIf
    
    If key_1$=""
      key_1$=InputRequester("", "Set firstly a password !", "")
      If key_1$="" : ProcedureReturn "" : EndIf
    Else
      key_presetted=1
    EndIf
    
    key$=ReverseString(#Salt$)+key_1$+#Salt$+ReverseString(key_1$) : key_2$=key_1$ : key_1$=""
    
    #KeyStretchingLoops=6e5
    key$+"wo5ncgf37q4r5ü,c4´3qü./T?=M/)TN§!M&E$VBPMPÜÜXMGQZI=P?*;:;IQq´03.r4ct"
    For i=1 To #KeyStretchingLoops ; Itterations
      key$=Fingerprint(@key$, StringByteLength(key$), #PB_Cipher_SHA3, 512)
      If WindowEvent()=#PB_Event_Timer : SetGadgetState(progressbar_ID, 100*i/#KeyStretchingLoops) : EndIf
    Next i
    SetGadgetState(progressbar_ID, 100)
    key$=key$+"45o7p2mpqemc134mcp235ümqhjwlerhömsre&VU/IONMPTNEng6p,+ßh96f5ec"
    key$=Fingerprint(@key$, StringByteLength(key$), #PB_Cipher_SHA3, 512)
    
    QAES_smart_universal_coder_KFB(0, @magic, @magic, 8, #Salt$+ReverseString(key$)+Str(magic)+key$)
    
    If Not mode And path$=""
      select_again:
      path$=OpenFileRequester("Select a file to"+method___0$, "", "*.*", 0)
      If path$="" : ProcedureReturn "" : EndIf
    EndIf
    
    file_size=FileSize(path$)
    If file_size<0
      If Not mode
        MessageRequester("ERROR", "File not found")
        Goto select_again
      Else
        ProcedureReturn "ERROR ##03QF - File not found !"
      EndIf
    ElseIf Not file_size
      If Not mode
        MessageRequester("ERROR", "This is a zero length file"+#CRLF$+#CRLF$+"Can not"+method__0$+"files without a content")
        Goto select_again
      Else
        ProcedureReturn "ERROR ##04QF - This is a zero length file - Can not"+method__0$+"files without a content !"
      EndIf
    EndIf
    
    file=OpenFile(#PB_Any, path$)
    If file
      block_size=4096<<2 : FileBuffersSize(file, block_size ) : *buffer=AllocateMemory(block_size) 
      If file_size<cryptextender_length+1
        If mode>1
          CloseFile(file)
          ProcedureReturn "ERROR ##05QF - This is not a"+method_0$+" file !"
        Else
          Goto encrypt_1
        EndIf
      EndIf
      FileSeek(file, file_size-cryptextender_length)
      ReadData(file, @get_fake_length, 8)
      ReadData(file, @get_counter, 8)
      ReadData(file, @get_magic, 8)
      ReadData(file, @hash(0), #HashLength>>3)
      FileSeek(file, 0)
      QAES_smart_universal_coder_KFB(0, @get_fake_length, @get_fake_length, 8, key$+ReverseString(key$))           ; QAES crypter - Try decrypt fake length
      QAES_smart_universal_coder_KFB(0, @get_counter, @get_counter, 8, ReverseString(key$)+key$+#salt$)            ; QAES crypter - Try decrypt counter
      QAES_smart_universal_coder_KFB(0, @hash(0), @hash(0), #HashLength>>3, key$+ReverseString(key$), get_counter) ; QAES crypter - Try decrypt hash
      QAES_smart_universal_coder_KFB(0, @get_magic, @get_magic, 8, ReverseString(key$)+key$, get_counter)          ; QAES crypter - Try decrypt magic
      
      If get_magic=magic 
        cryptextender_length+get_fake_length 
        If mode=1
          CloseFile(file)
          ProcedureReturn "HINT ##06QF - This is a valid"+method_0$+"file !"
        ElseIf mode=3
          check_integrity=1
        ElseIf mode=4
          CloseFile(file)
          ProcedureReturn "ALLok ##07QF - File checked - This is a valid"+method_0$+"file !"
        ElseIf Not mode
          result=MessageRequester("HINT", #HINTS+"This is a valid"+method_0$+"file !"+#CRLF$+#CRLF$+
                                          "Want to"+method__1$+"the file now ? - Select Yes"+#CRLF$+#CRLF$+
                                          "Just want to check the integrity of the file ? - Select Cancel"+#CRLF$+#CRLF$+
                                          "Want to select another file ? - Select No", #PB_MessageRequester_YesNoCancel)
          If result=#PB_MessageRequester_Cancel
            key_1$=key_2$
            check_integrity=1
          ElseIf result=#PB_MessageRequester_No
            key_1$=key_2$
            CloseFile(file)
            Goto restart
          EndIf
        EndIf
        encrypted_file_found=1 : counter_0=get_counter
        For i = 0 To #HashLength>>3-1 : hash_2$+RSet(Hex(PeekA(@hash(0)+i)), 2, "0") : Next i : hash_2$=LCase(hash_2$)
      Else
        If mode>1
          CloseFile(file)
          ProcedureReturn "HINT ##08QF - File checked - This is not a valid"+method_0$+"file - Or your key is wrong !"
        EndIf
        encrypt_1:
        If Not mode
          message$="This file looks not valid"+method_0$+"!"+#CRLF$+#CRLF$+
                   "It is also possible that your password is wrong"+#CRLF$+#CRLF$+
                   "Or it is possible that it is a corrupted"+method_0$+"file"+#CRLF$+#CRLF$+
                   "Want to"+method__0$+"this file now with your password ? - Select Yes"+#CRLF$+#CRLF$+
                   "Want to select another file ? - Select No"
          If key_presetted
            result=MessageRequester("HINT", #HINTS+message$, #PB_MessageRequester_YesNo)
          Else
            result=MessageRequester("HINT", #HINTS+message$+#CRLF$+#CRLF$+"To change your password - Select Cancel", #PB_MessageRequester_YesNoCancel)
          EndIf
          
          If result=#PB_MessageRequester_No
            key_1$=key_2$
            CloseFile(file) : Goto restart
          ElseIf result=#PB_MessageRequester_Cancel
            CloseFile(file) : key$="" : Goto restart
          EndIf
        EndIf
        QAES_smart_universal_coder_KFB(0, @magic, @magic, 8, ReverseString(key$)+key$, counter) ; QAES crypter - Encrypt magic
        counter_0=counter
      EndIf
      
    Else
      If Not mode
        MessageRequester("ERROR", "Can not open file")
        Goto select_again
      Else
        ProcedureReturn "ERROR ##09QF - Can not open file !"
      EndIf
    EndIf
    
    If IsWindow(window_ID)
      AddWindowTimer(window_ID, window_ID, 30)
    EndIf
    
    If progressbar_state=2
      SetGadgetState(progressbar_ID, 0)
    EndIf
    
    blocks=(file_size-cryptextender_length)/block_size
    
    remaining=file_size-(block_size*blocks)
    
    If encrypted_file_found
      remaining-cryptextender_length
    EndIf
    
    Repeat
      readed=ReadData(file, *buffer, block_size)
      
      If encrypted_file_found
        hash_bytes=readed-cryptextender_length
        If readed=block_size : hash_bytes=readed : EndIf
        If hash_bytes>0
          block_counter+1
          If blocks 
            If block_counter>blocks : hash_bytes=remaining : EndIf
          Else
            hash_bytes=file_size-cryptextender_length
          EndIf
          hash$=Fingerprint(*buffer, hash_bytes, #PB_Cipher_SHA3, #HashLength)
          hash$+key$+hash_1$+Str(counter_0)
          hash$=Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, #HashLength)
          hash_1$=hash$
        EndIf
      EndIf
      
      If Not check_integrity And Not set_counter_protection_mode
        QAES_smart_universal_coder_KFB(0, *buffer, *buffer, block_size, key$, counter_0, counter_1) ; QAES crypter
      EndIf
      
      If Not encrypted_file_found
        If readed>0
          hash$=Fingerprint(*buffer, readed, #PB_Cipher_SHA3, #HashLength)
          hash$+key$+hash_1$+Str(counter_0)
          hash$=Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, #HashLength)
          hash_1$=hash$ 
        EndIf
      EndIf
      
      If check_integrity
        writen+readed
      Else
        FileSeek(file, -readed, #PB_Relative) : writen+WriteData(file, *buffer, readed)
      EndIf 
      
      If progressbar_state
        window_event=WindowEvent()
      EndIf
      If progressbar_state=2 And window_event=#PB_Event_Timer And EventTimer()=window_ID
        SetGadgetState(progressbar_ID, 100*writen/file_size)
      EndIf
      counter_0+1 : counter_1+1
    Until Not readed
    
    If progressbar_state=2
      SetGadgetState(progressbar_ID, 100)
    EndIf
    
    hash$+key$+#Salt$ ; Finishing fingerprint
    hash$=LCase(Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, #HashLength))
    
    If encrypted_file_found And hash$<>hash_2$
      If check_integrity
        CloseFile(file) : FreeMemory(*buffer) : *buffer=0
        If Not mode
          If MessageRequester("WARNING", "File hash broken !"+#CRLF$+#CRLF$+
                                         "Want to use the file coder again ? - Select Yes", 
                              #PB_MessageRequester_YesNo)=#PB_MessageRequester_No
            ProcedureReturn ""
          EndIf
          Goto restart
        Else
          ProcedureReturn "WARNING ##10QF - File hash broken ! - Used counter =>"+Str(get_counter)
        EndIf
        
      Else
        file_broken=1
      EndIf
    EndIf
    
    If check_integrity
      CloseFile(file) : FreeMemory(*buffer) : *buffer=0
      If Not mode
        SetClipboardText(GetFilePart(path$)+#CRLF$+hash_2$)
        If MessageRequester("HINT", #HINTS+"All OK !"+#CRLF$+#CRLF$+"File integrity succesfully checked !"+#CRLF$+#CRLF$+
                                    "I put now the file hash and name in your clipboard"+#CRLF$+#CRLF$+hash_2$+#CRLF$+#CRLF$+
                                    "Want to use the file coder again ? - Select Yes", 
                            #PB_MessageRequester_YesNo)=#PB_MessageRequester_Yes
          Goto restart
        EndIf
      Else
        ProcedureReturn "ALLok ##11QF - File integrity succesfully checked ! - Used counter =>"+Str(get_counter)+" - File hash ==>"+hash_2$
      EndIf
      ProcedureReturn ""
    EndIf
    
    If Not encrypted_file_found
      *fake_content=AllocateMemory(set_fake_length)
      If Not *fake_content : set_fake_length=0 : set_fake_length_1=0 : EndIf
      set_fake_length_1=set_fake_length
      For i=0 To #HashLength>>3-1 : PokeA(@hash(0)+i, Val("$"+PeekS(@hash$+i*SizeOf(character)<<1, 2))) : Next i
      QAES_smart_universal_coder_KFB(0, @set_fake_length_1, @set_fake_length_1, 8, key$+ReverseString(key$))   ; QAES crypter - Crypt fake length
      QAES_smart_universal_coder_KFB(0, @hash(0), @hash(0), #HashLength>>3, key$+ReverseString(key$), counter) ; QAES crypter - Crypt hash
      QAES_smart_universal_coder_KFB(0, @counter, @counter, 8, ReverseString(key$)+key$+#salt$)                ; QAES crypter - Crypt counter
      If Not *fake_content : set_fake_length=0 : set_fake_length_1=0 : EndIf
      If set_fake_length
        If crypt_random
          CryptRandomData(*fake_content, set_fake_length)
        Else
          RandomData(*fake_content, set_fake_length)
        EndIf
        QAES_smart_universal_coder_KFB(0, *fake_content, *fake_content, set_fake_length, key$)
      EndIf
      writen+WriteData(file, *fake_content, set_fake_length)
      If *fake_content : FreeMemory(*fake_content) : EndIf
      writen+WriteData(file, @set_fake_length_1, 8)
      writen+WriteData(file, @counter, 8)
      writen+WriteData(file, @magic, 8)
      writen+WriteData(file, @hash(0), #HashLength>>3)
      If writen<>file_size+cryptextender_length+set_fake_length
        CloseFile(file) : FreeMemory(*buffer)
        If Not mode
          MessageRequester("ERROR", "Writen fails"+#CRLF$+#CRLF$+"Writen Bytes : "+Str(writen))
        Else
          ProcedureReturn "ERROR ##12QF - Writen fails - Writen Bytes : "+Str(writen)+" !"
        EndIf
        ProcedureReturn ""
      EndIf
    EndIf
    
    If encrypted_file_found
      FileSeek(file, -cryptextender_length, #PB_Relative)
      TruncateFile(file)
      If Lof(file)<>file_size-cryptextender_length
        CloseFile(file) : FreeMemory(*buffer)
        If Not mode
          MessageRequester("ERROR", "Truncate file fails")
        Else
          ProcedureReturn "ERROR ##13QF - Truncate file fails !"
        EndIf
        ProcedureReturn ""
      EndIf
    EndIf
    
    CloseFile(file)
    
    If file_extender$<>""
      If encrypted_file_found And Right(path$, Len(file_extender$))=file_extender$
        RenameFile(path$, Left(path$, Len(path$)-Len(file_extender$)))
      Else
        If Not encrypted_file_found
          RenameFile(path$, path$+file_extender$)
        EndIf
      EndIf
    EndIf
    
    If file_broken
      If Not mode
        message$="WARNING - File"+method_1$+"but file hash broken !"
      Else
        message$="WARNING ##14QF - File"+method_1$+"but file hash broken !"
      EndIf
    Else
      If encrypted_file_found
        If Not mode
          message$="All OK - File"+method_1$+"!"+#CRLF$+#CRLF$+
                   "I put now the file hash and name in your clipboard"+#CRLF$+#CRLF$+hash_2$
          SetClipboardText(GetFilePart(path$)+#CRLF$+hash_2$)
        Else
          message$="ALLok ##15QF - File"+method_1$+" ! - Used counter =>"+Str(get_counter)+" - File hash ==>"+hash_2$
        EndIf
      Else
        If Not mode
          message$="ALL OK - File "+method_0$+#CRLF$+#CRLF$+
                   "I put now the file hash and name in your clipboard"+#CRLF$+#CRLF$+hash$
          SetClipboardText(GetFilePart(path$)+#CRLF$+hash$)
        Else
          message$="ALLok ##16QF - File"+method_0$+" ! - File hash ==>"+hash$
        EndIf
      EndIf
    EndIf
    
    If Not mode
      If MessageRequester("HINT", #HINTS+message$+#CRLF$+#CRLF$+
                                  "Want to use the file coder again ?", 
                          #PB_MessageRequester_YesNo)=#PB_MessageRequester_Yes
        key_1$=key_2$
        Goto restart
      EndIf
    EndIf
    
    FreeMemory(*buffer)
    ProcedureReturn message$
    
  EndProcedure
  
EndModule
UseModule QAES_smart_file_coder

; ===================== Using the file crypt Addon ===============================

EnableExplicit
Define mode, window_ID, progressbar_ID , key$, path_0$, path_1$

; mode=0 - Full automatic mode with file selectors
; mode=1 - Encrypt
; mode=2 - Decrypt
; mode=3 - Check the file integrity
; mode=4 - Check if a file is already encrypted
; If not window_ID or not progressbar_ID, you get not a progressbar
; A empty key (Password) open automatically a string selector

#cryptfile_extender$=" [encrypted]" ; You can change how ever you want

; Automatic mode
key$=""
window_ID=OpenWindow(#PB_Any, 0, 0, 280, 50, "",  #PB_Window_ScreenCentered|#PB_Window_BorderLess)
AddWindowTimer(window_ID, 0, 100)
progressbar_ID=ProgressBarGadget(#PB_Any, 10, 10, 260, 30, 0, 100, #PB_ProgressBar_Smooth)
QAES_smart_file_coder(0, window_ID, progressbar_ID, "", key$, #cryptfile_extender$)

; Manual modes
; key$="This is a pre defined test key"
; path_0$=GetTemporaryDirectory()+"TestPic.jpg" ; Create a little picture for test
; path_1$=path_0$+#cryptfile_extender$
; UseJPEGImageEncoder()
; SaveImage(CreateImage(#PB_Any, 10, 10), path_0$, #PB_ImagePlugin_JPEG)
; Debug QAES_smart_file_coder(1, window_ID, progressbar_ID, path_0$, key$, #cryptfile_extender$) ; Encrypt a file
; Debug QAES_smart_file_coder(4, window_ID, progressbar_ID, path_1$, key$, #cryptfile_extender$) ; Check if the file is already valid encrypted
; Debug QAES_smart_file_coder(3, window_ID, progressbar_ID, path_1$, key$, #cryptfile_extender$) ; Check the file integrity
; Debug QAES_smart_file_coder(2, window_ID, progressbar_ID, path_1$, key$, #cryptfile_extender$) ; Decrypt a file
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5353
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by Kwai chang caine »

Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
User avatar
ar-s
Enthusiast
Enthusiast
Posts: 340
Joined: Sat Oct 06, 2007 11:20 pm
Location: France

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by ar-s »

Hi and thanks Andre for sharing that usefull stuff.
How to encrypt text, simply by going through an editorgadget without encrypting a file?

To use something like that.

Code: Select all

String$ = "my text to encode/decode" ; (getgadgettext from an editorgad)
key$ = "secret passphrase"

setclipbordtext( AesStringEncode(String$,key$) )
setclipbordtext( AesStringDecode(String$,key$) )
Thanks by advance.
~Ar-S~
My Image Hoster for PB users
My webSite (french) with PB apps : LDVMULTIMEDIA
PB - 3.x / 5.7x / 6 - W11 x64 - Ryzen 7 3700x / #Rpi4

Code: Select all

r3p347 : 7ry : un71l d0n3 = 1
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2071
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by Andre »

@ar-s:

Here is a demo code by walbus, showing the "in-place" string encryption/decryption (using the module posted above), without the need for a file:

Code: Select all

; String crypting - Use QAES_universal_coder_KFB - In place crypting - With string termination protection

password$="This is my password"+"with salt_345%2343^1"
crypt_checker$="IsCrypted_QAES"
string_source$="Hello World, this is a QAES_smart_universal_coder_KFB encrypted text/string" +crypt_checker$

; Encrypt string
If Right(string_source$, Len(crypt_checker$))=crypt_checker$
  Debug "QAES non encrypted or decrypted string found"
EndIf
QAES_smart_universal_coder_KFB(2, @string_source$, @string_source$, StringByteLength(string_source$), password$)
Debug string_source$
ShowMemoryViewer(@string_source$, StringByteLength(string_source$))
Debug ""

; Decrypt string
; Hint : Created pseudo control characters in the encrypted string can temporarily change the font size or other in the debugger window
QAES_smart_universal_coder_KFB(2, @string_source$, @string_source$, StringByteLength(string_source$), password$)
If Right(string_source$, Len(crypt_checker$))=crypt_checker$
  Debug "QAES encrypted string succesfully decrypted :"
  string_source$=Left(string_source$, Len(string_source$)-Len(crypt_checker$))
  Debug string_source$
Else
  Debug "Can not decrypt this string, or a non encrypted string"
EndIf
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
ar-s
Enthusiast
Enthusiast
Posts: 340
Joined: Sat Oct 06, 2007 11:20 pm
Location: France

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by ar-s »

Hey. I saw a walbus module to encrypt files but un missed that.
Thanks André.
~Ar-S~
My Image Hoster for PB users
My webSite (french) with PB apps : LDVMULTIMEDIA
PB - 3.x / 5.7x / 6 - W11 x64 - Ryzen 7 3700x / #Rpi4

Code: Select all

r3p347 : 7ry : un71l d0n3 = 1
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2071
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by Andre »

New version of this module by Werner Albus.
walbus wrote:The file crypter code is revised, improved and extended
It now allows very fast crypting of several or even many thousands of files.
However, the revised file crypter is not key compatible with the old version above.

Code: Select all

DeclareModule QAES_smart_universal_coder_KFB
  Declare QAES_smart_universal_coder_KFB(mode, *buffer_in.word, *buffer_out.word, bytes.q, key$, counter_key.q=0, counter_aes.q=0)
  
  ; Use ever key stretching - This impeded key brute force quite substantial
  ; You can, but you must not set a window and a progressbar for the key stretching progress
  Declare.s key_stretching(window_ID, progressbar_ID, key$, salt$, key_stretching_loops)
  UseSHA3Fingerprint()
EndDeclareModule

Module QAES_smart_universal_coder_KFB
  EnableExplicit
  
  ;- QAES AES256 KFB mode special coder for all things - binarys - strings - text files -----
  
  ; This coder can handle automatic string termination for any strings - In compiler mode ASCII and UNICODE !
  ; The coder works with all data lengths, also <16 bytes
  
  ; mode=0 - Mode BINARY, you can encrypt binary data, don't use this for on demand string encryption, it break the string termination!
  ; mode=1 - Mode ASCII, you can encrypt mixed data, string and binary - This ignore the encryption of zero bytes, recommended for mixed datea with ASCII strings.
  ; mode=2 - Mode UNICODE, you can encrypt mixed data, ascii strings, unicode strings and binary - This ignore the encryption of zero bytes.
  ; The coder go always forward, an extra decoder isn't necessary, just use exactly the same calling convention for encrypting and decrypting!
  ; You cipher a file blockwise, always set the current block number (consecutive) with the counter - Important, then the result look similar to CBC mode encryption!
  
  ; Author Werner Albus - www.nachtoptik.de
  ; No warranty whatsoever - Use at your own risk
  ; PureBasic
  
  ; counter_key.q   : You cipher a file blockwise, always set the current block number with this counter (consecutive numbering).
  ; counter_aes.q   : This counter will be automatically used by the coder, but you can change the startpoint, this chance same the counter_key the encryption absolutely
  ;                 : The counter_aes you can use as sample for setting a randomized startpoint for using with the file coder addon protection function
  ;                 : With used counters and salt you can personalize the coder, nobody can brute force a password from a unknown personalized coder
  ;                 : You can set the counter as quad, positive and negative
  ; key$            : You can use any strings as key
  ; *buffer_in      : Set the adress to the source data
  ; *buffer_out     : Set the adress to the destination data - Hint : It can also use the same place as the plain data.
  ; mode            : Set mode=0 for binary files - Set mode=1 for ASCII strings - Set mode=2 for UNICODE strings
  
  Procedure QAES_smart_universal_coder_KFB(mode, *buffer_in.word, *buffer_out.word, bytes.q, key$, counter_key.q=0, counter_aes.q=0)
    If Not bytes.q Or key$="" : ProcedureReturn 0  : EndIf
    
    #Salt$="t8690352cj2p1ch7fgw34u&=)?=)/%&§/&)=?(otmq09745$%()=)&%"  ; TODO: Salt, you can change
    Protected.q i, swap_, rounds.q=bytes>>4
    Protected ii, iii, bytes_minus_x, stepp=SizeOf(character)<<1
    Protected *register_asc.ascii, *register.word, *buffer_in_quad.quad, *buffer_out_quad.quad
    Protected remaining=bytes%16, bytes_minus_1=bytes-1
    Protected *buffer_in_asc.ascii, *buffer_out_asc.ascii
    Protected hash$=#Salt$+key$+Str(counter_key)+ReverseString(#Salt$)
    Static fixed_key_string${64}
    Static Dim register.q(3)
    
    fixed_key_string$=Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, 256) ; Create a key
    For ii = 0 To 31 : PokeA(@register(0)+ii, Val("$"+PeekS(@fixed_key_string$+iii, 2))) : iii+stepp : Next
    
    register(1)+counter_aes
    
    Macro go_1 ; Crypter
      If Not AESEncoder(@register(0), @register(0), 32, @register(0), 256, 0, #PB_Cipher_ECB) : ProcedureReturn 0 : EndIf
    EndMacro
    
    If Not mode ; Binary mode
      *buffer_in_quad.quad=*buffer_in.word : *buffer_out_quad.quad=*buffer_out.word
      If bytes<16 ; Less 16 bytes
        *buffer_out_asc=*buffer_out_quad : *buffer_in_asc=*buffer_in_quad : *register_asc=@register(0)
        go_1
        For ii=0 To bytes_minus_1
          *buffer_out_asc\a=*buffer_in_asc\a ! *register_asc\a : *buffer_in_asc+1 : *buffer_out_asc+1 : *register_asc+1
        Next
        ProcedureReturn 1
      EndIf
      While i<rounds ; =>16 bytes
        go_1
        *buffer_out_quad\q=*buffer_in_quad\q ! register(0) : *buffer_in_quad+8 : *buffer_out_quad+8
        *buffer_out_quad\q=*buffer_in_quad\q ! register(1) : *buffer_in_quad+8 : *buffer_out_quad+8 : i+1
      Wend
      If remaining
        *buffer_out_asc=*buffer_out_quad : *buffer_in_asc=*buffer_in_quad : *register_asc=@register(0)
        go_1
        For ii=0 To remaining-1
          *buffer_out_asc\a=*buffer_in_asc\a ! *register_asc\a : *buffer_in_asc+1 : *buffer_out_asc+1 : *register_asc+1
        Next
      EndIf
    ElseIf mode=1
      bytes_minus_x=bytes-2
      *buffer_in_asc=*buffer_in : *buffer_out_asc=*buffer_out
      Repeat
        go_1 : *register_asc=@register(0)
        For ii=0 To 15
          If *buffer_in_asc\a And *buffer_in_asc\a ! *register_asc\a
            *buffer_out_asc\a=*buffer_in_asc\a ! *register_asc\a
          Else
            *buffer_out_asc\a=*buffer_in_asc\a
          EndIf
          If i>bytes_minus_x : Break 2 : EndIf
          *buffer_in_asc+1 : *buffer_out_asc+1 : *register_asc+1 : i+1
        Next ii
      ForEver
    Else ; mode=2
      bytes_minus_x=bytes-3
      Repeat
        go_1 : *register.word=@register(0)
        For ii=0 To 15 Step 2
          If *buffer_in\w And *buffer_in\w ! *register\w
            *buffer_out\w=*buffer_in\w ! *register\w
          Else
            *buffer_out\w=*buffer_in\w
          EndIf
          If i>bytes_minus_x : Break 2 : EndIf
          *buffer_in+2 : *buffer_out+2 : *register+2 : i+2
        Next ii
      ForEver
    EndIf
    ProcedureReturn 1
  EndProcedure
  
  Procedure.s key_stretching(window_ID, progressbar_ID, key$, salt$, key_stretching_loops)
    Protected get_time.q , i
    get_time=ElapsedMilliseconds()
    For i=1 To key_stretching_loops ; Iterations
      key$=Fingerprint(@key$, StringByteLength(key$), #PB_Cipher_SHA3, 512)
      key$=ReverseString(salt$)+key$+salt$+ReverseString(key$)
      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$=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 QAES_smart_universal_coder_KFB

; ===== File coder addon for the universal AES256 based QAES_smart_universal_coder_KFB =====

DeclareModule QAES_smart_file_coder
  UseModule QAES_smart_universal_coder_KFB
  Declare.s QAES_smart_file_coder(mode, window_ID, progressbar_ID, path_1$, key_1$, file_extender$="", set_counter_protection_mode.q=0)
  Declare QAES_get_cryptextender_length()
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    Declare FixWriteData(file, *adress, length) ; Workaround for Linux PB 560
  CompilerEndIf
EndDeclareModule

Module QAES_smart_file_coder
  ; Smart file crypting addon or the QAES_smart_universal_coder_KFB
  ; Its nice you set a hint in your software for using QAES contents
  
  ; This addon can protect or encrypt and decrypt files using the QAES_smart_universal_coder_KFB module
  ; The encrypted files do not have visible headers or extenders
  ; Works with all file lengths
  ; No separate decrypter necessary
  ; With integrated full automatic working crypt randomized counter
  ; With full automatic file integrity check
  ; Can full automatic check whether a file is encrypted
  ; Various files with the same content are encrypted ever completely differently
  ; Author Werner Albus - www.nachtoptik.de - www.quick-aes-256.de
  ; No warranty whatsoever - Use at your own risk
  
  EnableExplicit
  
  Global cryptextender_length
  
  Procedure QAES_get_cryptextender_length()
    ProcedureReturn cryptextender_length
  EndProcedure
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    Procedure FixWriteData(file, *adress, length) ; Workaround for Linux PB560
      Protected write_data_pointer=Loc(file)
      Protected writen_data=WriteData(file, *adress, length)
      FileSeek(file, write_data_pointer+writen_data)
      ProcedureReturn writen_data
    EndProcedure
    Macro WriteData(File, Buffer, Size)
      FixWriteData(File, Buffer, Size)
    EndMacro
  CompilerEndIf
  
  Procedure.s QAES_smart_file_coder(mode, window_ID, progressbar_ID, path_1$, key_1$, file_extender$="", set_counter_protection_mode.q=0)
    ; mode=0 - Full automatic mode with file selectors
    ; mode=1 - Encrypt or add a file protection
    ; mode=2 - Decrypt or remove a file protection
    ; mode=3 - Check the file integrity
    ; mode=4 - Check if a file is already encrypted or protected
    
    ; set_counter_protection_mode <> 0 - activate the file protection mode
    ; This protect a file, but dont encrypt the file
    ; Mostly files you can normaly use protected
    ; Set on this variable your defined counter_aes from the universal crypter
    
    ; If not window_ID or not progressbar_ID, you get not a progressbar
    ; A empty key (Password) open automatically a string selector
    
    ; CompilerIf #PB_Compiler_Debugger : MessageRequester("Debugger", "Please deactivate firstly the debugger !") : ProcedureReturn "" : CompilerEndIf
    
    #HashLength=256 ; (224, 256, 384, 512) You can use all available hash lengths divisible by 2 and also different hashes
    
    #Salt$="59#ö#3:_,.45ß$/($(/=)?=JjB$§/(&=$?=)((/&)%WE/()T&%z#'" ; Salt - You can change
    
    #EnlargeFileLengthBytes=128   ; You can change
    #RandomizeFileLengthBytes=256 ; This feature change full automatic and randomized the length from any encrypted files
    
    #Hints="QUICK-AES-256 (QAES) AES256 KFB crypter"+#CRLF$+
           "No warranty whatsoever - Use at your own risk"+#CRLF$+#CRLF$   
    
    restart:
    Protected cryptextender_length=8+8+8+#HashLength>>3
    Protected path$="", hash$, key$, message$, method_0$, method__0$, method___0$
    Protected method_1$, method__1$, method___1$, hash_1$="", key_2$, hash_2$=""
    Protected file, readed, writen=0, check_integrity=0, file_broken=0, block_size, window_event, result
    Protected progressbar_state, encrypted_file_found=0, hash_bytes, i, key_presetted, blocks, remaining, block_counter=0
    Protected file_size.q, fake_length.q, get_fake_length.q, get_counter.q, counter.q, counter_0.q, get_magic.q, magic.q, timer.q
    Protected crypt_random.c, set_fake_length.q, set_fake_length_1.q, counter_1.q=345645758512426756724 ; Preset startpoint counter 1 - You can change
    Protected Dim hash.q(#HashLength>>3-1)
    Protected *buffer, *fake_content
    
    If set_counter_protection_mode
      counter=set_counter_protection_mode
      magic.q=275390641757985374251 ; Preset protected marker - You can change
      method_0$=" protected " : method__0$=" protect "
      method_1$=" unprotected " : method__1$=" unprotect "
    Else
      If OpenCryptRandom() : crypt_random=1 : CryptRandomData(@counter, 8) : Else : crypt_random=0 : RandomData(@counter, 8) : EndIf
      
      set_fake_length.q=CryptRandom(#RandomizeFileLengthBytes)+#EnlargeFileLengthBytes
      
      If Not counter
        If Not mode
          MessageRequester("ERROR", "Can not create counter")
        Else
          ProcedureReturn "ERROR ##01QF - Can not create counter !"
        EndIf
        ProcedureReturn ""
      EndIf
      magic.q=415628580943792148170 ; Preset crypt marker - You can change
      method_0$=" encrypted " : method__0$=" encrypt " : : method___0$=" crypting "
      method_1$=" decrypted " : : method__1$=" decrypt "
    EndIf
    
    If *buffer : FreeMemory(*buffer) : *buffer=0 : EndIf
    
    If mode Or path_1$<>"" : path$=path_1$ : path_1$="" : EndIf
    
    If IsWindow(window_ID) : progressbar_state=1 : EndIf
    
    If IsGadget(progressbar_ID)
      SetGadgetState(progressbar_ID, 0) : progressbar_state+1
    EndIf
    
    If Len(Fingerprint(@magic, 8, #PB_Cipher_SHA3, #HashLength))<>#HashLength>>2 ; Test Fingerprint
      If Not mode
        MessageRequester("ERROR", "Fingerprint fails")
      Else
        ProcedureReturn "ERROR ##02QF - Fingerprint fails !"
      EndIf
      ProcedureReturn ""
    EndIf
    
    If key_1$=""
      key_1$=InputRequester("", "Set firstly a password !", "")
      If key_1$="" : ProcedureReturn "" : EndIf
    Else
      key_presetted=1
    EndIf
    
    key$=ReverseString(#Salt$)+key_1$+#Salt$+ReverseString(key_1$) : key_2$=key_1$ : key_1$=""
    
    key$=Fingerprint(@key$, StringByteLength(key$), #PB_Cipher_SHA3, 512)
    
    QAES_smart_universal_coder_KFB(0, @magic, @magic, 8, #Salt$+ReverseString(key$)+Str(magic)+key$)
    
    If Not mode And path$=""
      select_again:
      path$=OpenFileRequester("Select a file to"+method___0$, "", "*.*", 0)
      If path$="" : ProcedureReturn "" : EndIf
    EndIf
    
    file_size=FileSize(path$)
    If file_size<0
      If Not mode
        MessageRequester("ERROR", "File not found")
        Goto select_again
      Else
        ProcedureReturn "ERROR ##03QF - File not found !"
      EndIf
    ElseIf Not file_size
      If Not mode
        MessageRequester("ERROR", "This is a zero length file"+#CRLF$+#CRLF$+"Can not"+method__0$+"files without a content")
        Goto select_again
      Else
        ProcedureReturn "ERROR ##04QF - This is a zero length file - Can not"+method__0$+"files without a content !"
      EndIf
    EndIf
    
    file=OpenFile(#PB_Any, path$)
    If file
      block_size=4096<<2 : FileBuffersSize(file, block_size ) : *buffer=AllocateMemory(block_size) 
      If file_size<cryptextender_length+1
        If mode>1
          CloseFile(file)
          ProcedureReturn "ERROR ##05QF - This is not a"+method_0$+" file !"
        Else
          Goto encrypt_1
        EndIf
      EndIf
      FileSeek(file, file_size-cryptextender_length)
      ReadData(file, @get_fake_length, 8)
      ReadData(file, @get_counter, 8)
      ReadData(file, @get_magic, 8)
      ReadData(file, @hash(0), #HashLength>>3)
      FileSeek(file, 0)
      QAES_smart_universal_coder_KFB(0, @get_fake_length, @get_fake_length, 8, key$+ReverseString(key$))           ; QAES crypter - Try decrypt fake length
      QAES_smart_universal_coder_KFB(0, @get_counter, @get_counter, 8, ReverseString(key$)+key$+#salt$)            ; QAES crypter - Try decrypt counter
      QAES_smart_universal_coder_KFB(0, @hash(0), @hash(0), #HashLength>>3, key$+ReverseString(key$), get_counter) ; QAES crypter - Try decrypt hash
      QAES_smart_universal_coder_KFB(0, @get_magic, @get_magic, 8, ReverseString(key$)+key$, get_counter)          ; QAES crypter - Try decrypt magic
      
      If get_magic=magic 
        cryptextender_length+get_fake_length 
        If mode=1
          CloseFile(file)
          ProcedureReturn "HINT ##06QF - This is a valid"+method_0$+"file !"
        ElseIf mode=3
          check_integrity=1
        ElseIf mode=4
          CloseFile(file)
          ProcedureReturn "ALLok ##07QF - File checked - This is a valid"+method_0$+"file !"
        ElseIf Not mode
          result=MessageRequester("HINT", #HINTS+"This is a valid"+method_0$+"file !"+#CRLF$+#CRLF$+
                                          "Want to"+method__1$+"the file now ? - Select Yes"+#CRLF$+#CRLF$+
                                          "Just want to check the integrity of the file ? - Select Cancel"+#CRLF$+#CRLF$+
                                          "Want to select another file ? - Select No", #PB_MessageRequester_YesNoCancel)
          If result=#PB_MessageRequester_Cancel
            key_1$=key_2$
            check_integrity=1
          ElseIf result=#PB_MessageRequester_No
            key_1$=key_2$
            CloseFile(file)
            Goto restart
          EndIf
        EndIf
        encrypted_file_found=1 : counter_0=get_counter
        For i = 0 To #HashLength>>3-1 : hash_2$+RSet(Hex(PeekA(@hash(0)+i)), 2, "0") : Next i : hash_2$=LCase(hash_2$)
      Else
        If mode>1
          CloseFile(file)
          ProcedureReturn "HINT ##08QF - File checked - This is not a valid"+method_0$+"file - Or your key is wrong !"
        EndIf
        encrypt_1:
        If Not mode
          message$="This file looks not valid"+method_0$+"!"+#CRLF$+#CRLF$+
                   "It is also possible that your password is wrong"+#CRLF$+#CRLF$+
                   "Or it is possible that it is a corrupted"+method_0$+"file"+#CRLF$+#CRLF$+
                   "Want to"+method__0$+"this file now with your password ? - Select Yes"+#CRLF$+#CRLF$+
                   "Want to select another file ? - Select No"
          If key_presetted
            result=MessageRequester("HINT", #HINTS+message$, #PB_MessageRequester_YesNo)
          Else
            result=MessageRequester("HINT", #HINTS+message$+#CRLF$+#CRLF$+"To change your password - Select Cancel", #PB_MessageRequester_YesNoCancel)
          EndIf
          
          If result=#PB_MessageRequester_No
            key_1$=key_2$
            CloseFile(file) : Goto restart
          ElseIf result=#PB_MessageRequester_Cancel
            CloseFile(file) : key$="" : Goto restart
          EndIf
        EndIf
        QAES_smart_universal_coder_KFB(0, @magic, @magic, 8, ReverseString(key$)+key$, counter) ; QAES crypter - Encrypt magic
        counter_0=counter
      EndIf
      
    Else
      If Not mode
        MessageRequester("ERROR", "Can not open file")
        Goto select_again
      Else
        ProcedureReturn "ERROR ##09QF - Can not open file !"
      EndIf
    EndIf
    
    If progressbar_state=2
      SetGadgetState(progressbar_ID, 0)
    EndIf
    
    blocks=(file_size-cryptextender_length)/block_size
    
    remaining=file_size-(block_size*blocks)
    
    If encrypted_file_found
      remaining-cryptextender_length
    EndIf
    
    timer=ElapsedMilliseconds()
    Repeat
      readed=ReadData(file, *buffer, block_size)
      
      If encrypted_file_found
        hash_bytes=readed-cryptextender_length
        If readed=block_size : hash_bytes=readed : EndIf
        If hash_bytes>0
          block_counter+1
          If blocks 
            If block_counter>blocks : hash_bytes=remaining : EndIf
          Else
            hash_bytes=file_size-cryptextender_length
          EndIf
          hash$=Fingerprint(*buffer, hash_bytes, #PB_Cipher_SHA3, #HashLength)
          hash$+key$+hash_1$+Str(counter_0)
          hash$=Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, #HashLength)
          hash_1$=hash$
        EndIf
      EndIf
      
      If Not check_integrity And Not set_counter_protection_mode
        QAES_smart_universal_coder_KFB(0, *buffer, *buffer, block_size, key$, counter_0, counter_1) ; QAES crypter
      EndIf
      
      If Not encrypted_file_found
        If readed>0
          hash$=Fingerprint(*buffer, readed, #PB_Cipher_SHA3, #HashLength)
          hash$+key$+hash_1$+Str(counter_0)
          hash$=Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, #HashLength)
          hash_1$=hash$ 
        EndIf
      EndIf
      
      If check_integrity
        writen+readed
      Else
        FileSeek(file, -readed, #PB_Relative) : writen+WriteData(file, *buffer, readed)
      EndIf 
      
      If progressbar_state
        window_event=WindowEvent()
      EndIf
      If progressbar_state=2 And ElapsedMilliseconds()>timer+30
        SetGadgetState(progressbar_ID, 100*writen/file_size)
        timer=ElapsedMilliseconds()
      EndIf
      counter_0+1 : counter_1+1
    Until Not readed
    
    If progressbar_state=2
      SetGadgetState(progressbar_ID, 100)
    EndIf
    
    hash$+key$+#Salt$ ; Finishing fingerprint
    hash$=LCase(Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, #HashLength))
    
    If encrypted_file_found And hash$<>hash_2$
      If check_integrity
        CloseFile(file) : FreeMemory(*buffer) : *buffer=0
        If Not mode
          If MessageRequester("WARNING", "File hash broken !"+#CRLF$+#CRLF$+
                                         "Want to use the file coder again ? - Select Yes", 
                              #PB_MessageRequester_YesNo)=#PB_MessageRequester_No
            ProcedureReturn ""
          EndIf
          Goto restart
        Else
          ProcedureReturn "WARNING ##10QF - File hash broken ! - Used counter =>"+Str(get_counter)
        EndIf
        
      Else
        file_broken=1
      EndIf
    EndIf
    
    If check_integrity
      CloseFile(file) : FreeMemory(*buffer) : *buffer=0
      If Not mode
        SetClipboardText(GetFilePart(path$)+#CRLF$+hash_2$)
        If MessageRequester("HINT", #HINTS+"All OK !"+#CRLF$+#CRLF$+"File integrity succesfully checked !"+#CRLF$+#CRLF$+
                                    "I put now the file hash and name in your clipboard"+#CRLF$+#CRLF$+hash_2$+#CRLF$+#CRLF$+
                                    "Want to use the file coder again ? - Select Yes", 
                            #PB_MessageRequester_YesNo)=#PB_MessageRequester_Yes
          Goto restart
        EndIf
      Else
        ProcedureReturn "ALLok ##11QF - File integrity succesfully checked ! - Used counter =>"+Str(get_counter)+" - File hash ==>"+hash_2$
      EndIf
      ProcedureReturn ""
    EndIf
    
    If Not encrypted_file_found
      *fake_content=AllocateMemory(set_fake_length)
      If Not *fake_content : set_fake_length=0 : set_fake_length_1=0 : EndIf
      set_fake_length_1=set_fake_length
      For i=0 To #HashLength>>3-1 : PokeA(@hash(0)+i, Val("$"+PeekS(@hash$+i*SizeOf(character)<<1, 2))) : Next i
      QAES_smart_universal_coder_KFB(0, @set_fake_length_1, @set_fake_length_1, 8, key$+ReverseString(key$))   ; QAES crypter - Crypt fake length
      QAES_smart_universal_coder_KFB(0, @hash(0), @hash(0), #HashLength>>3, key$+ReverseString(key$), counter) ; QAES crypter - Crypt hash
      QAES_smart_universal_coder_KFB(0, @counter, @counter, 8, ReverseString(key$)+key$+#salt$)                ; QAES crypter - Crypt counter
      If Not *fake_content : set_fake_length=0 : set_fake_length_1=0 : EndIf
      If set_fake_length
        If crypt_random
          CryptRandomData(*fake_content, set_fake_length)
        Else
          RandomData(*fake_content, set_fake_length)
        EndIf
        QAES_smart_universal_coder_KFB(0, *fake_content, *fake_content, set_fake_length, key$)
      EndIf
      writen+WriteData(file, *fake_content, set_fake_length)
      If *fake_content : FreeMemory(*fake_content) : EndIf
      writen+WriteData(file, @set_fake_length_1, 8)
      writen+WriteData(file, @counter, 8)
      writen+WriteData(file, @magic, 8)
      writen+WriteData(file, @hash(0), #HashLength>>3)
      If writen<>file_size+cryptextender_length+set_fake_length
        CloseFile(file) : FreeMemory(*buffer)
        If Not mode
          MessageRequester("ERROR", "Writen fails"+#CRLF$+#CRLF$+"Writen Bytes : "+Str(writen))
        Else
          ProcedureReturn "ERROR ##12QF - Writen fails - Writen Bytes : "+Str(writen)+" !"
        EndIf
        ProcedureReturn ""
      EndIf
    EndIf
    
    If encrypted_file_found
      FileSeek(file, -cryptextender_length, #PB_Relative)
      TruncateFile(file)
      If Lof(file)<>file_size-cryptextender_length
        CloseFile(file) : FreeMemory(*buffer)
        If Not mode
          MessageRequester("ERROR", "Truncate file fails")
        Else
          ProcedureReturn "ERROR ##13QF - Truncate file fails !"
        EndIf
        ProcedureReturn ""
      EndIf
    EndIf
    
    CloseFile(file)
    
    If file_extender$<>""
      If encrypted_file_found And Right(path$, Len(file_extender$))=file_extender$
        RenameFile(path$, Left(path$, Len(path$)-Len(file_extender$)))
      Else
        If Not encrypted_file_found
          RenameFile(path$, path$+file_extender$)
        EndIf
      EndIf
    EndIf
    
    If file_broken
      If Not mode
        message$="WARNING - File"+method_1$+"but file hash broken !"
      Else
        message$="WARNING ##14QF - File"+method_1$+"but file hash broken !"
      EndIf
    Else
      If encrypted_file_found
        If Not mode
          message$="All OK - File"+method_1$+"!"+#CRLF$+#CRLF$+
                   "I put now the file hash and name in your clipboard"+#CRLF$+#CRLF$+hash_2$
          SetClipboardText(GetFilePart(path$)+#CRLF$+hash_2$)
        Else
          message$="ALLok ##15QF - File"+method_1$+" ! - Used counter =>"+Str(get_counter)+" - File hash ==>"+hash_2$
        EndIf
      Else
        If Not mode
          message$="ALL OK - File "+method_0$+#CRLF$+#CRLF$+
                   "I put now the file hash and name in your clipboard"+#CRLF$+#CRLF$+hash$
          SetClipboardText(GetFilePart(path$)+#CRLF$+hash$)
        Else
          message$="ALLok ##16QF - File"+method_0$+" ! - File hash ==>"+hash$
        EndIf
      EndIf
    EndIf
    
    If Not mode
      If MessageRequester("HINT", #HINTS+message$+#CRLF$+#CRLF$+
                                  "Want to use the file coder again ?", 
                          #PB_MessageRequester_YesNo)=#PB_MessageRequester_Yes
        key_1$=key_2$
        Goto restart
      EndIf
    EndIf
    
    FreeMemory(*buffer)
    ProcedureReturn message$
    
  EndProcedure
  
EndModule
UseModule QAES_smart_file_coder

; ===================== Using the file crypt Addon ===============================

EnableExplicit
Define mode, key_stretching_loops, window_ID, progressbar_ID , key$, salt$, path_0$, path_1$

; mode=0 - Full automatic mode with file selectors
; mode=1 - Encrypt
; mode=2 - Decrypt
; mode=3 - Check the file integrity
; mode=4 - Check if a file is already encrypted
; If not window_ID or not progressbar_ID, you get not a progressbar
; A empty key (Password) open automatically a string selector

window_ID=OpenWindow(#PB_Any, 0, 0, 280, 50, "",  #PB_Window_ScreenCentered|#PB_Window_BorderLess)
progressbar_ID=ProgressBarGadget(#PB_Any, 10, 10, 260, 30, 0, 100, #PB_ProgressBar_Smooth)

#cryptfile_extender$=" [encrypted]" ; You can change how ever you want

key$="This is a test key" ; If you do not pass a key for automatic mode, a key requester opens

salt$="41a219&$()(/=/(&(605nnufDTUKKLÖNM65w32ß0c9ß87/=)(" ; Salt - You can change

key_stretching_loops=1e5 ; Key stretching loops

; Use ever key stretching - This impeded key brute force quite substantial
; You can, but you must not set a window and a progressbar for the key stretching progress
key_stretching(window_ID, progressbar_ID, key$, salt$, key_stretching_loops)

; Automatic mode
QAES_smart_file_coder(0, window_ID, progressbar_ID, "", key$, #cryptfile_extender$)

; Manual modes
; path_0$=GetTemporaryDirectory()+"TestPic.jpg" ; Create a little picture for test
; path_1$=path_0$+#cryptfile_extender$
; UseJPEGImageEncoder()
; SaveImage(CreateImage(#PB_Any, 10, 10), path_0$, #PB_ImagePlugin_JPEG)
; Debug QAES_smart_file_coder(1, window_ID, progressbar_ID, path_0$, key$, #cryptfile_extender$) ; Encrypt a file
; Debug QAES_smart_file_coder(4, window_ID, progressbar_ID, path_1$, key$, #cryptfile_extender$) ; Check if the file is already valid encrypted
; Debug QAES_smart_file_coder(3, window_ID, progressbar_ID, path_1$, key$, #cryptfile_extender$) ; Check the file integrity
; Debug QAES_smart_file_coder(2, window_ID, progressbar_ID, path_1$, key$, #cryptfile_extender$) ; Decrypt a file
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
RSBasic
Moderator
Moderator
Posts: 1218
Joined: Thu Dec 31, 2009 11:05 pm
Location: Gernsbach (Germany)
Contact:

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by RSBasic »

Andre wrote:

Code: Select all

[...]
Goto select_again
[...]
select_again:
[...]
Jump markers? :shock:
Couldn't this have been better solved? I'm not a friend of jump marks.
Image
Image
User avatar
Thorsten1867
Addict
Addict
Posts: 1366
Joined: Wed Aug 24, 2005 4:02 pm
Location: Germany

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by Thorsten1867 »

RSBasic wrote:Jump markers? :shock:
Couldn't this have been better solved? I'm not a friend of jump marks.
I tried to make the code more handy and adapted it to my needs:

Code: Select all

;/ =========================
;/ =    qAES_Module.pbi    =
;/ =========================
;/
;/ [ PB V5.7x / 64Bit / All OS]
;/
;/ based on code of Werner Albus - www.nachtoptik.de
;/ 
;/ < No warranty whatsoever - Use at your own risk >
;/
;/ adapted from Thorsten Hoeppner (07/2019) 
;/

; - This coder go always forward, an extra decoder isn't necessary, just use exactly the same calling convention for encrypting and decrypting!
; - This coder can handle automatic string termination for any strings - In compiler mode ASCII and UNICODE !
; - The coder works with all data lengths, also < 16 Byte

; Last Update: 01.08.2019
;
; - Bugfix

;{ _____ qAES - Commands _____

; qAES::KeyStretching()   - use keystretching to make brute force attacks more difficult
; qAES::SetAttribute()    - [#EnlargeBytes/#HashLength/#ProtectedMarker/#CryptMarker]
; qAES::SetSalt()         - define your own salt
; qAES::GetErrorMessage() - returns error message 
; ----- qAES::SmartCoder() -----
; qAES::SmartCoder()      - encrypt / decrypt ascii strings, unicode strings and binary data (#Binary/#Ascii/#Unicode)
; qAES::File()            - File:   encrypt / decrypt only with SmartCoder()
; qAES::String()          - String: encrypt / decrypt only with SmartCoder()
; ----- qAES::SmartFileCoder() -----
; qAES::SmartFileCoder()  - encrypting or decrypting file (high security)
; qAES::CheckIntegrity()  - checks the integrity of a encrypted file           [SmartFileCoder]
; qAES::IsEncrypted()     - checks if a file is already encrypted or protected [SmartFileCoder]

;}


DeclareModule qAES

	;- ===========================================================================
	;-   DeclareModule - Constants
	;- ===========================================================================

  Enumeration
    #Binary  ; Mode BINARY, you can encrypt binary data, don't use this for on demand string encryption, it break the string termination!
    #Ascii   ; Mode ASCII, you can encrypt mixed data, string and binary - This ignore the encryption of zero bytes, recommended for mixed datea with ASCII strings.
    #Unicode ; Mode UNICODE, you can encrypt mixed data, ascii strings, unicode strings and binary - This ignore the encryption of zero bytes.
  EndEnumeration
  
  Enumeration 1
    #CryptMarker     ; preset crypt marker
    #EnlargeBytes    ; enlarge file length bytes
    #HashLength      ; (224, 256, 384, 512)
    #ProtectedMarker ; preset protected marker
  EndEnumeration
  
  Enumeration 1
    #ERROR_CAN_NOT_CREATE_COUNTER
    #ERROR_FINGERPRINT_FAILS
    #ERROR_FILE_NOT_EXIST
    #ERROR_CAN_NOT_OPEN_FILE
    #ERROR_ENCODING_FAILS
  EndEnumeration
  
	;- ===========================================================================
	;-   DeclareModule
  ;- ===========================================================================
  
  Declare.i CheckIntegrity(File.s, Key.s, CryptExtension.s="", ProtectionMode.i=#False)
  Declare.i File(File.s, outFile.s, Key.s, KeyStretching.i=#False)
  Declare.i SmartFileCoder(File.s, Key.s, CryptExtension.s="", ProtectionMode.i=#False)
  Declare.i IsEncrypted(File.s, Key.s, CryptExtension.s="", ProtectionMode.i=#False)
  Declare.s KeyStretching(Key.s, Loops.i, ProgressBarID.i=#PB_Default, WindowID.i=#PB_Default)
  Declare   SetAttribute(Attribute.i, Value.i)
  Declare   SetSalt(String.s)
  Declare.s GetErrorMessage(Error.i)
  Declare.i SmartCoder(Mode.i, *Input.word, *Output.word, Size.q, Key.s, CounterKey.q=0, CounterAES.q=0)
  Declare.s String(String.s, Key.s, KeyStretching.i=#False) 
  
EndDeclareModule

Module qAES

	EnableExplicit
	
	UseSHA3Fingerprint()
	
	;- ============================================================================
	;-   Module - Constants
	;- ============================================================================
	
	#Hints$ = "QUICK-AES-256 (QAES) AES256 KFB crypter" + #LF$ + "No warranty whatsever - Use at your own risk" + #LF$ + #LF$
  #Salt$  = "t8690352cj2p1ch7fgw34u&=)?=)/%&§/&)=?(otmq09745$%()=)&%"
  
	;- ============================================================================
  ;-   Module - Structure
	;- ============================================================================
	
	Structure AES_Structure ;{ qAES\...
	  CryptExtLength.i
	  EnlargeBytes.i
	  HashLength.i
	  ProtectedMarker.q
	  CryptMarker.q
	  Salt.s
	  Error.i
	EndStructure ;}
	Global qAES.AES_Structure

	;- ==========================================================================
	;-   Module - Declared Procedures
	;- ==========================================================================
  
  ;- _____ Tools _____
  
  Procedure.s KeyStretching(Key.s, Loops.i, ProgressBarID.i=#PB_Default, WindowID.i=#PB_Default)
    Define.i i, Time.q, Progress
    
    If ProgressBarID <> #PB_Default And WindowID <> #PB_Default
      Progress = #True
      Time = ElapsedMilliseconds()
    EndIf 
    
    For i=1 To Loops ; Iterations
      
      Key = Fingerprint(@Key, StringByteLength(Key), #PB_Cipher_SHA3, 512)
      Key = ReverseString(qAES\Salt) + Key + qAES\Salt + ReverseString(Key)
      
      If Progress 
        If ElapsedMilliseconds() > Time + 100
          If IsGadget(ProgressBarID) : SetGadgetState(ProgressBarID, 100 * i / Loops) : EndIf
          Time = ElapsedMilliseconds()  
        EndIf
      EndIf
      
    Next
    
    Key = Fingerprint(@Key, StringByteLength(Key), #PB_Cipher_SHA3, 512) ; Finalize
    
    If Progress
      If IsGadget(ProgressBarID) : SetGadgetState(ProgressBarID, 100) : EndIf
      Delay(100)
    EndIf
    
    ProcedureReturn Key
  EndProcedure
  
  Procedure.s GetErrorMessage(Error.i)
    
    Select Error
      Case #ERROR_CAN_NOT_CREATE_COUNTER
        ProcedureReturn "Error: Can't create counter."
      Case #ERROR_FINGERPRINT_FAILS
        ProcedureReturn "Error: Fingerprint not valid."
      Case #ERROR_FILE_NOT_EXIST
        ProcedureReturn "Error: File not found."
      Case #ERROR_CAN_NOT_OPEN_FILE
        ProcedureReturn "Error: Can't open file."
      Case #ERROR_ENCODING_FAILS
        ProcedureReturn "No error found."
    EndSelect
    
    ProcedureReturn "No error found."
  EndProcedure
  
  ;- _____ Settings _____
  
  Procedure   SetAttribute(Attribute.i, Value.i)
    
    Select Attribute
      Case #EnlargeBytes
        qAES\EnlargeBytes = Value
      Case #HashLength
        qAES\HashLength = Value
      Case #ProtectedMarker
        qAES\ProtectedMarker = Value
      Case #CryptMarker
        qAES\CryptMarker = Value
    EndSelect
    
  EndProcedure

  Procedure   SetSalt(String.s)
	  qAES\Salt = String
	EndProcedure
	
	;- _____ SmartCoder _____
	
	Procedure.i SmartCoder(Mode.i, *Input.word, *Output.word, Size.q, Key.s, CounterKey.q=0, CounterAES.q=0)
	  ; Author: Werner Albus - www.nachtoptik.de (No warranty whatsoever - Use at your own risk)
    ; CounterKey: If you cipher a file blockwise, always set the current block number with this counter (consecutive numbering).
    ; CounterAES: This counter will be automatically used by the coder, but you can change the startpoint.
	  Define.i i, ii, iii, cStep
	  Define.q Rounds, Remaining
	  Define.s Hash$
	  Define   *aRegister.ascii, *wRegister.word, *aBufferIn.ascii, *aBufferOut.ascii, *qBufferIn.quad, *qBufferOut.quad
	  Static   FixedKey${64}
	  Static   Dim Register.q(3)
	  
	  If qAES\Salt = "" : qAES\Salt = #Salt$ : EndIf
	  
	  Hash$     = qAES\Salt + Key + Str(CounterKey) + ReverseString(qAES\Salt)
	  FixedKey$ = Fingerprint(@Hash$, StringByteLength(Hash$), #PB_Cipher_SHA3, 256)	  
	  
	  cStep     = SizeOf(character) << 1
	  Rounds    = Size >> 4
	  Remaining = Size % 16
	  
	  For ii = 0 To 31
	    PokeA(@Register(0) + ii, Val("$" + PeekS(@FixedKey$ + iii, 2)))
	    iii + cStep
	  Next
	  
	  Register(1) + CounterAES

	  Select Mode
	    Case #Binary  ;{ Binary content
	      
	      *qBufferIn  = *Input
	      *qBufferOut = *Output
	      
	      If Size < 16 ;{ Size < 16
	        
	        *aBufferOut = *qBufferOut
	        *aBufferIn  = *qBufferIn
	        *aRegister  = @register(0)
	        
	        If Not AESEncoder(@Register(0), @Register(0), 32, @Register(0), 256, 0, #PB_Cipher_ECB)
	          qAES\Error = #ERROR_ENCODING_FAILS
	          ProcedureReturn #False
	        EndIf
	        
          For ii=0 To Size - 1
            *aBufferOut\a = *aBufferIn\a ! *aRegister\a
            *aBufferIn  + 1
            *aBufferOut + 1
            *aRegister  + 1
          Next
          
          ProcedureReturn #True
          ;}
        EndIf
        
        While i < Rounds ;{ >= 16 Byte
          
          If Not AESEncoder(@register(0), @register(0), 32, @register(0), 256, 0, #PB_Cipher_ECB)
            qAES\Error = #ERROR_ENCODING_FAILS
            ProcedureReturn #False
          EndIf
          
          *qBufferOut\q=*qBufferIn\q ! register(0)
          *qBufferIn  + 8
          *qBufferOut + 8
          *qBufferOut\q = *qBufferIn\q ! register(1)
          *qBufferIn  + 8
          *qBufferOut + 8
          
          i + 1
        Wend ;}
        
        If Remaining
          
          *aBufferOut = *qBufferOut
          *aBufferIn  = *qBufferIn
          *aRegister  = @Register(0)
          
          If Not AESEncoder(@register(0), @register(0), 32, @register(0), 256, 0, #PB_Cipher_ECB)
            qAES\Error = #ERROR_ENCODING_FAILS
            ProcedureReturn #False
          EndIf
          
          For ii=0 To Remaining - 1
            *aBufferOut\a = *aBufferIn\a ! *aRegister\a
            *aBufferIn  + 1
            *aBufferOut + 1
            *aRegister  + 1
          Next
          
        EndIf
	      ;}
	    Case #Ascii   ;{ Ascii content
	      
	      *aBufferIn  = *Input
	      *aBufferOut = *Output
	      
	      Repeat
	        
	        If Not AESEncoder(@register(0), @register(0), 32, @register(0), 256, 0, #PB_Cipher_ECB)
	          qAES\Error = #ERROR_ENCODING_FAILS
	          ProcedureReturn #False
	        EndIf
	        
	        *aRegister = @Register(0)
	        
	        For ii=0 To 15
	          
            If *aBufferIn\a And *aBufferIn\a ! *aRegister\a
              *aBufferOut\a = *aBufferIn\a ! *aRegister\a
            Else
              *aBufferOut\a = *aBufferIn\a
            EndIf
            
            If i > Size - 2 : Break 2 : EndIf
            
            *aBufferIn  + 1
            *aBufferOut + 1
            *aRegister  + 1
            
            i + 1
          Next ii
          
        ForEver
  	    ;}
	    Case #Unicode ;{ Unicode content
	      
	      Repeat
	        
	        If Not AESEncoder(@Register(0), @Register(0), 32, @Register(0), 256, 0, #PB_Cipher_ECB)
	          qAES\Error = #ERROR_ENCODING_FAILS
	          ProcedureReturn #False
	        EndIf
	        
	        *wRegister = @Register(0)
          
	        For ii=0 To 15 Step 2
	          
            If *Input\w And *Input\w ! *wRegister\w
              *Output\w = *Input\w ! *wRegister\w
            Else
              *Output\w = *Input\w
            EndIf
            
            If i > Size - 3 : Break 2 : EndIf
            
            *Input + 2
            *Output + 2
            *wRegister + 2
            
            i + 2
          Next ii
          
        ForEver
	      
	      ;}
	  EndSelect
	  
	  ProcedureReturn #True
	EndProcedure

	Procedure.i SmartFileCoder(File.s, Key.s, CryptExtension.s="", ProtectionMode.i=#False)
	  ; Set ProtectionMode <> 0 activates the file protection mode (adds Hash and so on)
	  ; Set on this variable to define the CounterAES from the universal crypter
    ; This protect a file, but dont encrypt the file. Mostly files you can normaly use protected
	  Define.i i, CryptRandom, EncryptedFileFound, HashBytes
	  Define.i FileID, BlockSize, Blocks, BlockCounter, Remaining
	  Define.q Counter, cCounter, spCounter, Magic
	  Define.q FileSize, fCounter, ReadBytes, WritenBytes, fMagic ; File data
	  Define.s Key$, Hash$, cHash$
	  Define   *Buffer
	  
	  If CryptExtension
	    If FileSize(GetFilePart(File, #PB_FileSystem_NoExtension) + CryptExtension + "." + GetExtensionPart(File)) > 0
	      File = GetFilePart(File, #PB_FileSystem_NoExtension) + CryptExtension + "." + GetExtensionPart(File)
	    EndIf
	  EndIf
	  
	  If FileSize(File) <= 0
	    qAES\Error = #ERROR_FILE_NOT_EXIST
	    ProcedureReturn #False
	  EndIf
	  
	  If qAES\CryptMarker     = 0 : qAES\CryptMarker     = 415628580943792148170 : EndIf
	  If qAES\EnlargeBytes    = 0 : qAES\EnlargeBytes    = 128    : EndIf
	  If qAES\HashLength      = 0 : qAES\HashLength      = 256    : EndIf
	  If qAES\ProtectedMarker = 0 : qAES\ProtectedMarker = 275390641757985374251 : EndIf
	  If qAES\Salt = ""           : qAES\Salt            = #Salt$ : EndIf
	  
	  qAES\CryptExtLength = 8 + 8 + qAES\HashLength >> 3
	  Dim Hash.q(qAES\HashLength >> 3 - 1)
	  
	  If ProtectionMode ;{ Counter / Magic
	    
      Counter = ProtectionMode
      Magic   = qAES\ProtectedMarker
      
    Else
      
      If OpenCryptRandom()
        CryptRandom = #True
        CryptRandomData(@Counter, 8)
      Else
        CryptRandom = #False
        RandomData(@Counter, 8)
      EndIf
      
      Magic = qAES\CryptMarker
      
      If Not Counter 
        qAES\Error = #ERROR_CAN_NOT_CREATE_COUNTER
        ProcedureReturn #False
      EndIf
      ;}
    EndIf
    
    If Len(Fingerprint(@Magic, 8, #PB_Cipher_SHA3, qAES\HashLength)) <> qAES\HashLength >> 2 ; Check Fingerprint
      qAES\Error = #ERROR_FINGERPRINT_FAILS
      ProcedureReturn #False
    EndIf
    
    Key$  = ReverseString(qAES\Salt) + Key + qAES\Salt + ReverseString(Key)
    Key$  = Fingerprint(@Key$, StringByteLength(Key$), #PB_Cipher_SHA3, 512)
    
    SmartCoder(#Binary, @Magic, @Magic, 8, qAES\Salt + ReverseString(Key$) + Str(Magic) + Key$)

    FileID = OpenFile(#PB_Any, File)
    If FileID
      
      FileSize = Lof(FileID)
      
      BlockSize = 4096 << 2
      FileBuffersSize(FileID, BlockSize)
      
      *Buffer = AllocateMemory(BlockSize)
      If *Buffer
        
        FileSeek(FileID, FileSize - qAES\CryptExtLength)
        
        ;{ Read file header
        ReadData(FileID, @fCounter, 8)
        ReadData(FileID, @fMagic, 8)
        ReadData(FileID, @Hash(0), qAES\HashLength >> 3)
        FileSeek(FileID, 0)
        ;}
        
        ;{ Decrypt file header
        SmartCoder(#Binary, @fCounter, @fCounter, 8, ReverseString(Key$) + Key$ + qAES\Salt)
        SmartCoder(#Binary, @fMagic, @fMagic, 8, ReverseString(Key$) + Key$, fCounter)
        SmartCoder(#Binary, @Hash(0), @Hash(0), qAES\HashLength >> 3, Key$ + ReverseString(Key$), fCounter)
        ;}
        
        If fMagic = Magic ;{ File encrypted?
        
          cCounter = fCounter
          EncryptedFileFound = #True
          
        Else
  
          SmartCoder(#Binary, @Magic, @Magic, 8, ReverseString(Key$) + Key$, Counter) ; Encrypt magic
          cCounter = Counter
          ;}
        EndIf
        
        Blocks    = (FileSize - qAES\CryptExtLength) / BlockSize
        Remaining = FileSize - (BlockSize * Blocks)
        
        If EncryptedFileFound : Remaining - qAES\CryptExtLength : EndIf
        
        Repeat 
          
          ReadBytes = ReadData(FileID, *Buffer, BlockSize)
      
          If EncryptedFileFound ;{ File encrypted
          
            HashBytes = ReadBytes - qAES\CryptExtLength
        
            If ReadBytes = BlockSize : HashBytes = ReadBytes : EndIf

            If HashBytes > 0
              
              BlockCounter + 1
              
              If Remaining 
                If BlockCounter > Remaining : HashBytes = Remaining : EndIf
              Else
                HashBytes = FileSize - qAES\CryptExtLength
              EndIf
              
              Hash$  = Fingerprint(*buffer, HashBytes, #PB_Cipher_SHA3, qAES\HashLength)
              Hash$ + Key$ + cHash$ + Str(cCounter)
              Hash$  = Fingerprint(@Hash$, StringByteLength(Hash$), #PB_Cipher_SHA3, qAES\HashLength)
              cHash$ = Hash$
              
            EndIf

            If Not ProtectionMode
              SmartCoder(#Binary, *Buffer, *Buffer, BlockSize, Key$, cCounter, spCounter) ; QAES crypter
            EndIf
            ;}
          Else                  ;{ File not encrypted
            
            If Not ProtectionMode
              SmartCoder(#Binary, *Buffer, *Buffer, BlockSize, Key$, cCounter, spCounter) ; QAES crypter
            EndIf
            
            If ReadBytes > 0
              Hash$  = Fingerprint(*Buffer, ReadBytes, #PB_Cipher_SHA3, qAES\HashLength)
              Hash$ + Key$ + cHash$ + Str(cCounter)
              Hash$  = Fingerprint(@Hash$, StringByteLength(Hash$), #PB_Cipher_SHA3, qAES\HashLength)
              cHash$ = Hash$ 
            EndIf
            ;}
          EndIf
          
          FileSeek(FileID, -ReadBytes, #PB_Relative)
          WritenBytes + WriteData(FileID, *Buffer, ReadBytes)
          
          cCounter  + 1
          spCounter + 1
          
        Until ReadBytes = 0
        
        Hash$ + Key$ + qAES\Salt ; Finishing fingerprint
        Hash$ = LCase(Fingerprint(@Hash$, StringByteLength(Hash$), #PB_Cipher_SHA3, qAES\HashLength))
        
        If EncryptedFileFound ;{ File encrypted
          
          FileSeek(FileID, -qAES\CryptExtLength, #PB_Relative)
          TruncateFile(FileID)
          
          ;}
        Else                  ;{ File not encrypted
          
          For i=0 To qAES\HashLength >> 3 - 1
            PokeA(@Hash(0) + i, Val("$" + PeekS(@Hash$ + i *SizeOf(character) << 1, 2)))
          Next
          
          ;{ Crypt file header
          SmartCoder(#Binary, @Hash(0), @Hash(0), qAES\HashLength >> 3, Key$ + ReverseString(Key$), Counter)
          SmartCoder(#Binary, @Counter, @Counter, 8, ReverseString(Key$) + Key$ + qAES\Salt)
          ;}
          
          WritenBytes + WriteData(FileID, @Counter, 8)
          WritenBytes + WriteData(FileID, @Magic, 8)
          WritenBytes + WriteData(FileID, @Hash(0), qAES\HashLength >> 3)
          Debug "FileCoder: " + Hash(0)
          ;}
        EndIf
        
        FreeMemory(*Buffer)
      EndIf
      
      CloseFile(FileID)
      
      If CryptExtension
        
        If EncryptedFileFound
          RenameFile(File, RemoveString(File, CryptExtension))
        Else
          RenameFile(File, GetFilePart(File, #PB_FileSystem_NoExtension) + CryptExtension + "." + GetExtensionPart(File))
        EndIf
        
      Else
        
        If EncryptedFileFound
          RenameFile(File, RemoveString(File, ".aes", #PB_String_NoCase, Len(File) - 4))
        Else
          RenameFile(File, File + ".aes")
        EndIf
        
      EndIf
      
    Else 
      qAES\Error = #ERROR_CAN_NOT_OPEN_FILE
      ProcedureReturn #False
    EndIf
    
	EndProcedure
	
  Procedure.i CheckIntegrity(File.s, Key.s, CryptExtension.s="", ProtectionMode.i=#False)
	  Define.q FileSize, Counter, fCounter, cCounter, spCounter, ReadBytes, WritenBytes, Magic, fMagic
	  Define.i FileID, CryptRandom, EncryptedFileFound, CheckIntegrity, FileBroken
	  Define.i i, Blocks, BlockSize, Remaining, HashBytes, BlockCounter
	  Define.s Key$, Hash$, fHash$, cHash$
	  Define   *Buffer
	  
	  If CryptExtension ;{
	    If FileSize(GetFilePart(File, #PB_FileSystem_NoExtension) + CryptExtension + "." + GetExtensionPart(File)) > 0
	      File = GetFilePart(File, #PB_FileSystem_NoExtension) + CryptExtension + "." + GetExtensionPart(File)
	    EndIf ;}
	  EndIf
	  
	  If FileSize(File) <= 0
	    qAES\Error = #ERROR_FILE_NOT_EXIST
	    ProcedureReturn #False
	  EndIf
	  
	  If qAES\CryptMarker     = 0 : qAES\CryptMarker     = 415628580943792148170 : EndIf
	  If qAES\ProtectedMarker = 0 : qAES\ProtectedMarker = 275390641757985374251 : EndIf
	  If qAES\HashLength      = 0 : qAES\HashLength      = 256    : EndIf
	  If qAES\Salt = "" : qAES\Salt = #Salt$ : EndIf
	  
	  qAES\CryptExtLength = 8 + 8 + qAES\HashLength >> 3
	  Dim Hash.q(qAES\HashLength >> 3 - 1)
	  
	  If ProtectionMode ;{ Counter / Magic
	    
      Counter = ProtectionMode
      Magic   = qAES\ProtectedMarker
      
    Else
      
      If OpenCryptRandom()
        CryptRandom = #True
        CryptRandomData(@Counter, 8)
      Else
        CryptRandom = #False
        RandomData(@Counter, 8)
      EndIf
      
      Magic = qAES\CryptMarker
      
      If Not Counter 
        qAES\Error = #ERROR_CAN_NOT_CREATE_COUNTER
        ProcedureReturn #False
      EndIf
      ;}
    EndIf
    
    If Len(Fingerprint(@Magic, 8, #PB_Cipher_SHA3, qAES\HashLength)) <> qAES\HashLength >> 2
      qAES\Error = #ERROR_FINGERPRINT_FAILS
      ProcedureReturn #False
    EndIf
    
    Key$  = ReverseString(qAES\Salt) + Key + qAES\Salt + ReverseString(Key)
    Key$  = Fingerprint(@Key$, StringByteLength(Key$), #PB_Cipher_SHA3, 512)
    
    SmartCoder(#Binary, @Magic, @Magic, 8, qAES\Salt + ReverseString(Key$) + Str(Magic) + Key$)
    
	  FileID = ReadFile(#PB_Any, File)
	  If FileID
	    
	    FileSize = Lof(FileID)
	    
	    BlockSize = 4096 << 2
      FileBuffersSize(FileID, BlockSize)
      
      *Buffer = AllocateMemory(BlockSize)
      If *Buffer
	    
  	    FileSeek(FileID, FileSize - qAES\CryptExtLength)
  	    
  	    ;{ Read file header
  	    ReadData(FileID, @fCounter, 8)
  	    ReadData(FileID, @fMagic, 8)
  	    ReadData(FileID, @Hash(0), qAES\HashLength >> 3)
        FileSeek(FileID, 0)
        ;}

        ;{ Decrypt file header
  	    SmartCoder(#Binary, @fCounter, @fCounter, 8, ReverseString(Key$) + Key$ + qAES\Salt)
        SmartCoder(#Binary, @fMagic,   @fMagic,   8, ReverseString(Key$) + Key$, fCounter)
        SmartCoder(#Binary, @Hash(0),  @Hash(0), qAES\HashLength >> 3, Key$ + ReverseString(Key$), fCounter)
        ;}
        
        If fMagic = Magic ;{ File encrypted
          
          EncryptedFileFound = #True
          cCounter = fCounter
          
          For i = 0 To qAES\HashLength >> 3 - 1
            fHash$ + RSet(Hex(PeekA(@Hash(0) + i)), 2, "0")
          Next i
          fHash$ = LCase(fHash$)
          ;}
        Else              ;{ File not encrypted
          
          SmartCoder(#Binary, @Magic, @Magic, 8, ReverseString(Key$) + Key$, Counter)
          cCounter = Counter
         
          ;}
        EndIf    
        
        Blocks    = (FileSize - qAES\CryptExtLength) / BlockSize
        Remaining = FileSize - (BlockSize * Blocks)
       
        If EncryptedFileFound : Remaining - qAES\CryptExtLength : EndIf
        
        Repeat 
          
          ReadBytes = ReadData(FileID, *Buffer, BlockSize)
          
          If EncryptedFileFound ;{ File encrypted
            
            HashBytes = ReadBytes - qAES\CryptExtLength
        
            If ReadBytes = BlockSize : HashBytes = ReadBytes : EndIf
            
            If HashBytes > 0
              
              BlockCounter + 1
              
              If Remaining 
                If BlockCounter > Remaining : HashBytes = Remaining : EndIf
              Else
                HashBytes = FileSize - qAES\CryptExtLength
              EndIf
              
              Hash$  = Fingerprint(*Buffer, HashBytes, #PB_Cipher_SHA3, qAES\HashLength)
              Hash$ + Key$ + cHash$ + Str(cCounter)
              Hash$  = Fingerprint(@Hash$, StringByteLength(Hash$), #PB_Cipher_SHA3, qAES\HashLength)
              cHash$ = Hash$

            EndIf
            
            If Not ProtectionMode
              SmartCoder(#Binary, *Buffer, *Buffer, BlockSize, Key$, cCounter, spCounter) ; QAES crypter
            EndIf
            ;}
          Else                  ;{ File not encrypted  
            
            If Not ProtectionMode
              SmartCoder(#Binary, *Buffer, *Buffer, BlockSize, Key$, cCounter, spCounter) ; QAES crypter
            EndIf
            
            If ReadBytes > 0
              Hash$  = Fingerprint(*Buffer, ReadBytes, #PB_Cipher_SHA3, qAES\HashLength)
              Hash$ + Key$ + cHash$ + Str(cCounter)
              Hash$  = Fingerprint(@Hash$, StringByteLength(Hash$), #PB_Cipher_SHA3, qAES\HashLength)
              cHash$ = Hash$ 
            EndIf
            ;}
          EndIf
          
          WritenBytes + ReadBytes
          
          cCounter  + 1
          spCounter + 1
          
        Until ReadBytes = 0
        
        Hash$ + Key$ + qAES\Salt ; Finishing fingerprint
        Hash$ = LCase(Fingerprint(@Hash$, StringByteLength(Hash$), #PB_Cipher_SHA3, qAES\HashLength))
        
        If EncryptedFileFound
          If Hash$ <> fHash$ : FileBroken = #True : EndIf
        EndIf
        
        FreeMemory(*Buffer)
      EndIf
      
      CloseFile(FileID)
    Else 
      qAES\Error = #ERROR_CAN_NOT_OPEN_FILE
      ProcedureReturn #False  
	  EndIf
	  
	  If FileBroken
	    ProcedureReturn #False
	  Else
	    ProcedureReturn #True
	  EndIf
	  
	EndProcedure
	
	Procedure.i IsEncrypted(File.s, Key.s, CryptExtension.s="", ProtectionMode.i=#False)
	  Define.q FileSize, Counter, fCounter, Magic, fMagic
	  Define.i FileID, CryptRandom, EncryptedFileFound
	  Define.s Key$
	  
	  If CryptExtension
	    If FileSize(GetFilePart(File, #PB_FileSystem_NoExtension) + CryptExtension + "." + GetExtensionPart(File)) > 0
	      File = GetFilePart(File, #PB_FileSystem_NoExtension) + CryptExtension + "." + GetExtensionPart(File)
	    EndIf
	  EndIf
	  
	  If FileSize(File) <= 0
	    qAES\Error = #ERROR_FILE_NOT_EXIST
	    ProcedureReturn #False
	  EndIf
	  
	  If qAES\CryptMarker     = 0 : qAES\CryptMarker     = 415628580943792148170 : EndIf
	  If qAES\ProtectedMarker = 0 : qAES\ProtectedMarker = 275390641757985374251 : EndIf
	  If qAES\HashLength      = 0 : qAES\HashLength      = 256    : EndIf
	  If qAES\Salt = "" : qAES\Salt = #Salt$ : EndIf
	  
	  qAES\CryptExtLength = 8 + 8 + qAES\HashLength >> 3
	  
	  If ProtectionMode ;{ Counter / Magic
	    
      Counter = ProtectionMode
      Magic   = qAES\ProtectedMarker
      
    Else
      
      If OpenCryptRandom()
        CryptRandom = #True
        CryptRandomData(@Counter, 8)
      Else
        CryptRandom = #False
        RandomData(@Counter, 8)
      EndIf
      
      Magic = qAES\CryptMarker
      
      If Not Counter 
        qAES\Error = #ERROR_CAN_NOT_CREATE_COUNTER
        ProcedureReturn #False
      EndIf
      ;}
    EndIf
    
    If Len(Fingerprint(@Magic, 8, #PB_Cipher_SHA3, qAES\HashLength)) <> qAES\HashLength >> 2
      qAES\Error = #ERROR_FINGERPRINT_FAILS
      ProcedureReturn #False
    EndIf
    
    Key$  = ReverseString(qAES\Salt) + Key + qAES\Salt + ReverseString(Key)
    Key$  = Fingerprint(@Key$, StringByteLength(Key$), #PB_Cipher_SHA3, 512)
    
    SmartCoder(#Binary, @Magic, @Magic, 8, qAES\Salt + ReverseString(Key$) + Str(Magic) + Key$)
    
	  FileID = ReadFile(#PB_Any, File)
	  If FileID
	    
	    FileSize = Lof(FileID)
	    
	    FileSeek(FileID, FileSize - qAES\CryptExtLength)
	    
	    ReadData(FileID, @fCounter, 8)
	    ReadData(FileID, @fMagic, 8)
	    
	    SmartCoder(#Binary, @fCounter, @fCounter, 8, ReverseString(Key$) + Key$ + qAES\Salt)
      SmartCoder(#Binary, @fMagic,   @fMagic,   8, ReverseString(Key$) + Key$, fCounter)
      
      If fMagic = Magic 
        EncryptedFileFound = #True
      EndIf    
   
      CloseFile(FileID)
    Else 
      qAES\Error = #ERROR_CAN_NOT_OPEN_FILE
      ProcedureReturn #False  
	  EndIf
	  
	  ProcedureReturn EncryptedFileFound
	EndProcedure
	
	;- _____ Encode / Decode only _____
	
  Procedure.s String(String.s, Key.s, KeyStretching.i=#False) 
    ; KeyStretching: number of loops for KeyStretching()
    Define   *Input, *Output
    Define.i StrgSize
    Define.s Output$
    
    If KeyStretching
      Key = KeyStretching(Key, KeyStretching)
    EndIf     
    
    *Input = @String
    If *Input
      CompilerIf #PB_Compiler_Unicode
  
        StrgSize = StringByteLength(String, #PB_Unicode) + 2
        If StrgSize
          *Output = AllocateMemory(StrgSize)
          If *Output
            SmartCoder(#Unicode, *Input, *Output, StrgSize, Key)
            Output$ = PeekS(*Output, StrgSize, #PB_Unicode)
            FreeMemory(*Output)
          EndIf
        EndIf
        
      CompilerElse
        
        StrgSize = StringByteLength(String, #PB_Ascii) + 1
        If StrgSize
          *Output = AllocateMemory(StrgSize)
          If *Output
            SmartCoder(#Ascii, *Input, *Output, StrgSize, Key)
            Output$ = PeekS(*Output, StrgSize, #PB_Ascii)
            FreeMemory(*Output)
          EndIf
        EndIf
        
      CompilerEndIf
    EndIf
    
    ProcedureReturn Output$
  EndProcedure
  
  Procedure.i File(File.s, outFile.s, Key.s, KeyStretching.i=#False) 
    Define   *Input, *Output
    Define.i FileID, FileSize, Result
    
    If KeyStretching
      Key = KeyStretching(Key, KeyStretching)
    EndIf 
    
    FileID = ReadFile(#PB_Any, File)
    If FileID
      
      FileSize = Lof(FileID)
      
      *Input  = AllocateMemory(FileSize)
      If *Input
        
        If ReadData(FileID, *Input, FileSize)
          
          CloseFile(FileID)
          
          *Output = AllocateMemory(FileSize)
          If *Output
            
            SmartCoder(#Binary, *Input, *Output, FileSize, Key)
            
            FileID = CreateFile(#PB_Any, outFile)
            If FileID 
              Result = WriteData(FileID, *Output, FileSize)
              CloseFile(FileID)
            EndIf
            
            FreeMemory(*Output)
          EndIf
          
        EndIf
        
        FreeMemory(*Input)
      EndIf
      
    Else
      qAES\Error = #ERROR_FILE_NOT_EXIST
      ProcedureReturn #False
    EndIf
    
    ProcedureReturn Result
  EndProcedure  

EndModule

;- ========  Module - Example ========

CompilerIf #PB_Compiler_IsMainFile
  
  #Example = 1
  
  ; 1: String
  ; 2: File (only encrypt / decrypt)
  ; 3: SmartFileCoder
  ; 4: SmartFileCoder with CryptExtension
  ; 5: Check integrity
  
  Enumeration 1
    #Window
    #ProgressBar
    #Image
  EndEnumeration

  #CryptExtension$ = " [encrypted]"
  
  Key$  = "18qAES07PW67"
  
  CompilerSelect #Example
    CompilerCase 1 
      
      Text$ = "This is a test text for the qAES-Module."
  
      encText$ = qAES::String(Text$, Key$) 
      Debug encText$
      
      decText$ = qAES::String(encText$, Key$)
      Debug decText$
      
    CompilerCase 2 
      
      qAES::File("PureBasic.jpg", "PureBasic.jpg.aes", Key$) 
      qAES::File("PureBasic.jpg.aes", "Test.jpg", Key$) 
      
    CompilerCase 3
      
      qAES::SmartFileCoder("PureBasic.jpg", Key$)
      ;qAES::SmartFileCoder("PureBasic.jpg.aes", Key$)
      
    CompilerCase 4  
      
      qAES::SmartFileCoder("PureBasic.jpg", Key$, #CryptExtension$)
      If qAES::IsEncrypted("PureBasic.jpg", Key$, #CryptExtension$)
        Debug "File is encrypted"
      Else
        Debug "File is not encrypted"
      EndIf
      
    CompilerCase 5
      
      qAES::SmartFileCoder("PureBasic.jpg", Key$, #CryptExtension$)
      If qAES::CheckIntegrity("PureBasic.jpg", Key$, #CryptExtension$)
        Debug "File integrity succesfully checked"
      Else
        Debug "File hash not valid"
      EndIf 
      
  CompilerEndSelect

CompilerEndIf
Last edited by Thorsten1867 on Thu Aug 01, 2019 1:24 pm, edited 1 time in total.
Translated with http://www.DeepL.com/Translator

Download of PureBasic - Modules
Download of PureBasic - Programs

[Windows 11 x64] [PB V5.7x]
User avatar
RSBasic
Moderator
Moderator
Posts: 1218
Joined: Thu Dec 31, 2009 11:05 pm
Location: Gernsbach (Germany)
Contact:

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by RSBasic »

Yes, your code is much better. Thank you
Image
Image
User avatar
blueb
Addict
Addict
Posts: 1044
Joined: Sat Apr 26, 2003 2:15 pm
Location: Cuernavaca, Mexico

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by blueb »

Quick question..
Can't find qAES::FileCoder()

should it be: qAES::SmartFileCoder() in the example area :?:
- It was too lonely at the top.

System : PB 6.10 LTS (x64) and Win Pro 11 (x64)
Hardware: AMD Ryzen 9 5900X w/64 gigs Ram, AMD RX 6950 XT Graphics w/16gigs Mem
User avatar
Thorsten1867
Addict
Addict
Posts: 1366
Joined: Wed Aug 24, 2005 4:02 pm
Location: Germany

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by Thorsten1867 »

Bug fixed
Translated with http://www.DeepL.com/Translator

Download of PureBasic - Modules
Download of PureBasic - Programs

[Windows 11 x64] [PB V5.7x]
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2071
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by Andre »

Here is another announcement with a bigger update + extension to the available functons.
walbus wrote: When checking the Filecrypter addon, I noticed that the File Protection function, ie the protection of files against changes, did not work. This is fixed now.

At the same time I have added an addon from the GFX_Wizzard_BF to encrypt images, as well as an addon to save strings or any text in a file.

As a hint:
In the forum is also a special Crypter to find, which is aligned to the processing of CSV records. Andre himself uses this very fast special Crypter to protect his GeoWorld datasets.

This new coder with its addons can do the following:

- Encrypt files
- Check if a file is encrypted
- Each encrypted file is unique, different at bit level
- Check encrypted files for integrity
- Automatic checking of files for integrity when decrypting
- Activatable File and Key Requester
- No temporary files are created

- Attach and remove File Protection to unencrypted files or texts. This is a seal that prevents files from being altered unnoticed.
A note on this: File Protection can also be easily used with the String to File and the Image to File addon.

- Encrypt, save and load images on place
- Each encrypted image is unique, different on bit level. No temporary files are created.

- Save strings and texts as a file
- Each encrypted string is unique, different at bit level. No temporary files are created.

- In place string crypter
Encrypt strings on demand in themselves.
With unique, integrated protection against destruction of the string termination. No temporary files are created

The Crypter supports and supports counters and an automatic IV.

You can edit or extend these crypters.
Also create new addons.
Please note and check carefully, if everything you change or rebuild, actually works.
You overlook something very fast or do not notice mistakes.
I therefore recommend not to change the Crypter, but only for further processing.
In new addons to use as they are.
Become familiar with the counters as well.
And btw. you can think about Goto statement what you want (it's still a part of PB and BASIC in general), important is that it works :wink:

I myself would never be able to code such crypting stuff... so I'm happy that I'm able to use the codes of walbus :D

Code: Select all

DeclareModule QAES_smart_universal_coder_KFB
  Declare QAES_smart_universal_coder_KFB(mode, *buffer_in.word, *buffer_out.word, bytes.q, key$, counter_key.q=0, counter_aes.q=0)
  
  ; Use ever key stretching - This impeded key brute force quite substantial
  ; You can, but you must not set a window and a progressbar for the key stretching progress
  Declare.s key_stretching(window_ID, progressbar_ID, key$, salt$, key_stretching_loops)
  UseSHA3Fingerprint()
EndDeclareModule

Module QAES_smart_universal_coder_KFB
  EnableExplicit
  
  ;- QAES AES256 KFB mode special coder for all things - binarys - strings - text files -----
  
  ; This coder can handle automatic string termination for any strings - In compiler mode ASCII and UNICODE !
  ; The coder works with all data lengths, also <16 bytes
  
  ; mode=0 - Mode BINARY, you can encrypt binary data, don't use this for on demand string encryption, it break the string termination!
  ; mode=1 - Mode ASCII, you can encrypt mixed data, string and binary - This ignore the encryption of zero bytes, recommended for mixed datea with ASCII strings.
  ; mode=2 - Mode UNICODE, you can encrypt mixed data, ascii strings, unicode strings and binary - This ignore the encryption of zero bytes.
  ; The coder go always forward, an extra decoder isn't necessary, just use exactly the same calling convention for encrypting and decrypting!
  ; You cipher a file blockwise, always set the current block number (consecutive) with the counter - Important, then the result look similar to CBC mode encryption!
  
  ; Author Werner Albus - www.nachtoptik.de
  ; No warranty whatsoever - Use at your own risk
  ; Its nice you set a hint in your software for using QAES contents
  ; PureBasic x86 / x64
  
  ; counter_key.q   : You cipher a file blockwise, always set the current block number with this counter (consecutive numbering).
  ; counter_aes.q   : This counter will be automatically used by the coder, but you can change the startpoint, this chance same the counter_key the encryption absolutely
  ;                 : The counter_aes you can use as sample for setting a randomized startpoint for using with the file coder addon protection function
  ;                 : With used counters and salt you can personalize the coder, nobody can brute force a password from a unknown personalized coder
  ;                 : You can set the counter as quad, positive and negative
  ; key$            : You can use any strings as key
  ; *buffer_in      : Set the adress to the source data
  ; *buffer_out     : Set the adress to the destination data - Hint : It can also use the same place as the plain data.
  ; mode            : Set mode=0 for binary files - Set mode=1 for ASCII strings - Set mode=2 for UNICODE strings
  
  Procedure QAES_smart_universal_coder_KFB(mode, *buffer_in.word, *buffer_out.word, bytes.q, key$, counter_key.q=0, counter_aes.q=0)
    If Not bytes.q Or key$="" : ProcedureReturn 0  : EndIf
    
    #Salt$="t8690352cj2p1ch7fgw34u&=)?=)/%&§/&)=?(otmq09745$%()=)&%"  ; TODO: Salt, you can change
    Protected.q i, swap_, rounds.q=bytes>>4
    Protected ii, iii, bytes_minus_x, stepp=SizeOf(character)<<1
    Protected *register_asc.ascii, *register.word, *buffer_in_quad.quad, *buffer_out_quad.quad
    Protected remaining=bytes%16, bytes_minus_1=bytes-1
    Protected *buffer_in_asc.ascii, *buffer_out_asc.ascii
    Protected hash$=#Salt$+key$+Str(counter_key)+ReverseString(#Salt$)
    Static fixed_key_string${64}
    Static Dim register.q(3)
    
    fixed_key_string$=Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, 256) ; Create a key
    For ii = 0 To 31 : PokeA(@register(0)+ii, Val("$"+PeekS(@fixed_key_string$+iii, 2))) : iii+stepp : Next
    
    register(1)+counter_aes
    
    Macro go_1 ; Crypter
      If Not AESEncoder(@register(0), @register(0), 32, @register(0), 256, 0, #PB_Cipher_ECB) : ProcedureReturn 0 : EndIf
    EndMacro
    
    If Not mode ; Binary mode
      *buffer_in_quad.quad=*buffer_in.word : *buffer_out_quad.quad=*buffer_out.word
      If bytes<16 ; Less 16 bytes
        *buffer_out_asc=*buffer_out_quad : *buffer_in_asc=*buffer_in_quad : *register_asc=@register(0)
        go_1
        For ii=0 To bytes_minus_1
          *buffer_out_asc\a=*buffer_in_asc\a ! *register_asc\a : *buffer_in_asc+1 : *buffer_out_asc+1 : *register_asc+1
        Next
        ProcedureReturn 1
      EndIf
      While i<rounds ; =>16 bytes
        go_1
        *buffer_out_quad\q=*buffer_in_quad\q ! register(0) : *buffer_in_quad+8 : *buffer_out_quad+8
        *buffer_out_quad\q=*buffer_in_quad\q ! register(1) : *buffer_in_quad+8 : *buffer_out_quad+8 : i+1
      Wend
      If remaining
        *buffer_out_asc=*buffer_out_quad : *buffer_in_asc=*buffer_in_quad : *register_asc=@register(0)
        go_1
        For ii=0 To remaining-1
          *buffer_out_asc\a=*buffer_in_asc\a ! *register_asc\a : *buffer_in_asc+1 : *buffer_out_asc+1 : *register_asc+1
        Next
      EndIf
    ElseIf mode=1
      bytes_minus_x=bytes-2
      *buffer_in_asc=*buffer_in : *buffer_out_asc=*buffer_out
      Repeat
        go_1 : *register_asc=@register(0)
        For ii=0 To 15
          If *buffer_in_asc\a And *buffer_in_asc\a ! *register_asc\a
            *buffer_out_asc\a=*buffer_in_asc\a ! *register_asc\a
          Else
            *buffer_out_asc\a=*buffer_in_asc\a
          EndIf
          If i>bytes_minus_x : Break 2 : EndIf
          *buffer_in_asc+1 : *buffer_out_asc+1 : *register_asc+1 : i+1
        Next ii
      ForEver
    Else ; mode=2
      bytes_minus_x=bytes-3
      Repeat
        go_1 : *register.word=@register(0)
        For ii=0 To 15 Step 2
          If *buffer_in\w And *buffer_in\w ! *register\w
            *buffer_out\w=*buffer_in\w ! *register\w
          Else
            *buffer_out\w=*buffer_in\w
          EndIf
          If i>bytes_minus_x : Break 2 : EndIf
          *buffer_in+2 : *buffer_out+2 : *register+2 : i+2
        Next ii
      ForEver
    EndIf
    ProcedureReturn 1
  EndProcedure
  
  Procedure.s key_stretching(window_ID, progressbar_ID, key$, salt$, key_stretching_loops)
    ; Author Werner Albus - www.nachtoptik.de
    Protected get_time.q , i
    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 QAES_smart_universal_coder_KFB

; String to file crypter module
; Addon for the QAES_smart_universal_coder_KFB
; Autor - Werner Albus www.nachtoptik.de
; Purebasic x86 / x64
DeclareModule QAES_StringToFileCrypter
  UseModule QAES_smart_universal_coder_KFB
  Declare create_encrypted_string_file(string$, destination_path$, key$)
  Declare.s read_encrypted_string_file(destination_path$, key$)
EndDeclareModule

Module QAES_StringToFileCrypter
  EnableExplicit
  
  Procedure create_encrypted_string_file(string$, destination_path$, key$)
    ; Create a encryoted string file
    Protected file=CreateFile(#PB_Any, destination_path$)
    If file
      Protected counter.q
      If OpenCryptRandom()
        CryptRandomData(@counter, 8)
      Else
        RandomData(@counter, 8)
      EndIf
      Protected *buffer=Ascii(string$)
      If Not *buffer : ProcedureReturn 0 : EndIf
      If Not QAES_smart_universal_coder_KFB(0, *buffer, *buffer, MemorySize(*buffer), key$, counter)
        FreeMemory(*buffer) : ProcedureReturn 0
      EndIf
      If WriteData(file, *buffer, MemorySize(*buffer))<>MemorySize(*buffer)
        FreeMemory(*buffer) : ProcedureReturn 0
      EndIf 
      FileSeek(file, Lof(file))
      If WriteQuad(file, counter)<>8 : FreeMemory(*buffer) : ProcedureReturn 0 : EndIf
      CloseFile(file)
      FreeMemory(*buffer)
    Else
      ProcedureReturn 0
    EndIf
    ProcedureReturn 1
  EndProcedure
  
  Procedure.s read_encrypted_string_file(destination_path$, key$)
    ; Read a encrypted string file
    Protected file=ReadFile(#PB_Any, destination_path$)
    If Not file : ProcedureReturn "" : EndIf
    Protected *buffer=AllocateMemory(Lof(file))
    If Not *buffer : ProcedureReturn "" : EndIf
    If file
      Protected counter.q
      FileSeek(file, Lof(file)-8)
      counter=ReadQuad(file)
      FileSeek(file, 0)
      If ReadData(file, *buffer, Lof(file))<>Lof(file) : FreeMemory(*buffer) : EndIf
      FileSeek(file, 0)
      If Not QAES_smart_universal_coder_KFB(0, *buffer, *buffer, MemorySize(*buffer), key$, counter)
        FreeMemory(*buffer) : ProcedureReturn ""
      EndIf
      Protected string$=PeekS(*buffer , -1, #PB_Ascii )
      CloseFile(file)
    Else
      ProcedureReturn ""
    EndIf
    If *buffer : FreeMemory(*buffer) : EndIf
    ProcedureReturn string$
  EndProcedure
  
EndModule
UseModule QAES_StringToFileCrypter

; ===== File coder addon for the universal AES256 based QAES_smart_universal_coder_KFB =====

DeclareModule QAES_smart_file_coder
  UseModule QAES_smart_universal_coder_KFB
  Declare.s QAES_smart_file_coder(mode, window_ID, progressbar_ID, path_1$, key_1$, file_extender$="", set_counter_protection_mode.q=0)
  Declare QAES_get_cryptextender_length()
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    Declare FixWriteData(file, *adress, length) ; Workaround for Linux PB 560
  CompilerEndIf
EndDeclareModule

Module QAES_smart_file_coder
  ; Smart file crypting addon or the QAES_smart_universal_coder_KFB
  ; Its nice you set a hint in your software for using QAES contents
  ; PureBasic x86 / x64
  
  ; This addon can protect or encrypt and decrypt files using the QAES_smart_universal_coder_KFB module
  ; The encrypted files do not have visible headers or extenders
  ; Works with all file lengths
  ; No separate decrypter necessary
  ; With integrated full automatic working crypt randomized counter
  ; With full automatic file integrity check
  ; Can full automatic check whether a file is encrypted
  ; Various files with the same content are encrypted ever completely differently
  ; Author Werner Albus - www.nachtoptik.de - www.quick-aes-256.de
  ; No warranty whatsoever - Use at your own risk
  
  EnableExplicit
  
  Global cryptextender_length
  
  Procedure QAES_get_cryptextender_length()
    ProcedureReturn cryptextender_length
  EndProcedure
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    Procedure FixWriteData(file, *adress, length) ; Workaround for Linux PB560
      Protected write_data_pointer=Loc(file)
      Protected writen_data=WriteData(file, *adress, length)
      FileSeek(file, write_data_pointer+writen_data)
      ProcedureReturn writen_data
    EndProcedure
    Macro WriteData(File, Buffer, Size)
      FixWriteData(File, Buffer, Size)
    EndMacro
  CompilerEndIf
  
  Procedure.s QAES_smart_file_coder(mode, window_ID, progressbar_ID, path_1$, key_1$, file_extender$="", set_counter_protection_mode.q=0)
    ; mode=0 - Full automatic mode with file selectors
    ; mode=1 - Encrypt or add a file protection
    ; mode=2 - Decrypt or remove a file protection
    ; mode=3 - Check the file integrity
    ; mode=4 - Check if a file is already encrypted or protected
    
    ; set_counter_protection_mode <> 0 - activate the file protection mode
    ; This protect a file, but dont encrypt the file
    ; Mostly files you can normaly use protected
    ; Set on this variable your defined counter_aes from the universal crypter
    
    ; If not window_ID or not progressbar_ID, you get not a progressbar
    ; A empty key (Password) open automatically a string selector
    
    ; CompilerIf #PB_Compiler_Debugger : MessageRequester("Debugger", "Please deactivate firstly the debugger !") : ProcedureReturn "" : CompilerEndIf
    
    #HashLength=256 ; (224, 256, 384, 512) You can use all available hash lengths divisible by 2 and also different hashes
    
    #Salt$="59#ö#3:_,.45ß$/($(/=)?=JjB$§/(&=$?=)((/&)%WE/()T&%z#'" ; Salt - You can change
    
    #EnlargeFileLengthBytes=128   ; You can change
    #RandomizeFileLengthBytes=256 ; This feature change full automatic and randomized the length from any encrypted files
    
    #Hints="QUICK-AES-256 (QAES) AES256 KFB crypter"+#CRLF$+
           "No warranty whatsoever - Use at your own risk"+#CRLF$+#CRLF$   
    
    restart:
    Protected cryptextender_length=8+8+8+#HashLength>>3
    Protected path$="", hash$, key$, message$, method_0$, method__0$, method___0$
    Protected method_1$, method__1$, method___1$, hash_1$="", key_2$, hash_2$=""
    Protected file, readed, writen=0, check_integrity=0, file_broken=0, block_size, window_event, result
    Protected progressbar_state, encrypted_file_found=0, hash_bytes, i, key_presetted, blocks, remaining, block_counter=0
    Protected file_size.q, fake_length.q, get_fake_length.q, get_counter.q, counter.q, counter_0.q, get_magic.q, magic.q, timer.q
    Protected crypt_random.c, set_fake_length.q, set_fake_length_1.q, counter_1.q=345645758512426756724 ; Preset startpoint counter 1 - You can change
    Protected Dim hash.q(#HashLength>>3-1)
    Protected *buffer, *fake_content
    
    If set_counter_protection_mode
      counter=set_counter_protection_mode
      magic.q=275390641757985374251 ; Preset protected marker - You can change
      method_0$=" protected " : method__0$=" protect "
      method_1$=" unprotected " : method__1$=" unprotect "
    Else
      If OpenCryptRandom() : crypt_random=1 : CryptRandomData(@counter, 8) : Else : crypt_random=0 : RandomData(@counter, 8) : EndIf
      
      If Not counter
        If Not mode
          MessageRequester("ERROR", "Can not create counter")
        Else
          ProcedureReturn "ERROR ##01QF - Can not create counter !"
        EndIf
        ProcedureReturn ""
      EndIf
      magic.q=415628580943792148170 ; Preset crypt marker - You can change
      method_0$=" encrypted " : method__0$=" encrypt " : : method___0$=" crypting "
      method_1$=" decrypted " : : method__1$=" decrypt "
    EndIf
    
    If *buffer : FreeMemory(*buffer) : *buffer=0 : EndIf
    
    If mode Or path_1$<>"" : path$=path_1$ : path_1$="" : EndIf
    
    If IsWindow(window_ID) : progressbar_state=1 : EndIf
    
    If IsGadget(progressbar_ID)
      SetGadgetState(progressbar_ID, 0) : progressbar_state+1
    EndIf
    
    If Len(Fingerprint(@magic, 8, #PB_Cipher_SHA3, #HashLength))<>#HashLength>>2 ; Test Fingerprint
      If Not mode
        MessageRequester("ERROR", "Fingerprint fails")
      Else
        ProcedureReturn "ERROR ##02QF - Fingerprint fails !"
      EndIf
      ProcedureReturn ""
    EndIf
    
    If key_1$=""
      key_1$=InputRequester("", "Set firstly a password !", "")
      If key_1$="" : ProcedureReturn "" : EndIf
    Else
      key_presetted=1
    EndIf
    
    key$=ReverseString(#Salt$)+key_1$+#Salt$+ReverseString(key_1$) : key_2$=key_1$ : key_1$=""
    
    key$=Fingerprint(@key$, StringByteLength(key$), #PB_Cipher_SHA3, 512)
    
    QAES_smart_universal_coder_KFB(0, @magic, @magic, 8, #Salt$+ReverseString(key$)+Str(magic)+key$)
    
    If Not mode And path$=""
      select_again:
      path$=OpenFileRequester("Select a file to"+method___0$, "", "*.*", 0)
      If path$="" : ProcedureReturn "" : EndIf
    EndIf
    
    file_size=FileSize(path$)
    If file_size<0
      If Not mode
        MessageRequester("ERROR", "File not found")
        Goto select_again
      Else
        ProcedureReturn "ERROR ##03QF - File not found !"
      EndIf
    ElseIf Not file_size
      If Not mode
        MessageRequester("ERROR", "This is a zero length file"+#CRLF$+#CRLF$+"Can not"+method__0$+"files without a content")
        Goto select_again
      Else
        ProcedureReturn "ERROR ##04QF - This is a zero length file - Can not"+method__0$+"files without a content !"
      EndIf
    EndIf
    
    file=OpenFile(#PB_Any, path$)
    If file
      block_size=4096<<2 : FileBuffersSize(file, block_size ) : *buffer=AllocateMemory(block_size) 
      If file_size<cryptextender_length+1
        If mode>1
          CloseFile(file)
          ProcedureReturn "ERROR ##05QF - This is not a"+method_0$+" file !"
        Else
          Goto encrypt_1
        EndIf
      EndIf
      FileSeek(file, file_size-cryptextender_length)
      ReadData(file, @get_fake_length, 8)
      ReadData(file, @get_counter, 8)
      ReadData(file, @get_magic, 8)
      ReadData(file, @hash(0), #HashLength>>3)
      FileSeek(file, 0)
      QAES_smart_universal_coder_KFB(0, @get_fake_length, @get_fake_length, 8, key$+ReverseString(key$))           ; QAES crypter - Try decrypt fake length
      QAES_smart_universal_coder_KFB(0, @get_counter, @get_counter, 8, ReverseString(key$)+key$+#salt$)            ; QAES crypter - Try decrypt counter
      QAES_smart_universal_coder_KFB(0, @hash(0), @hash(0), #HashLength>>3, key$+ReverseString(key$), get_counter) ; QAES crypter - Try decrypt hash
      QAES_smart_universal_coder_KFB(0, @get_magic, @get_magic, 8, ReverseString(key$)+key$, get_counter)          ; QAES crypter - Try decrypt magic
      
      If get_magic=magic 
        cryptextender_length+get_fake_length 
        If mode=1
          CloseFile(file)
          ProcedureReturn "HINT ##06QF - This is a valid"+method_0$+"file !"
        ElseIf mode=3
          check_integrity=1
        ElseIf mode=4
          CloseFile(file)
          ProcedureReturn "ALLok ##07QF - File checked - This is a valid"+method_0$+"file !"
        ElseIf Not mode
          result=MessageRequester("HINT", #HINTS+"This is a valid"+method_0$+"file !"+#CRLF$+#CRLF$+
                                          "Want to"+method__1$+"the file now ? - Select Yes"+#CRLF$+#CRLF$+
                                          "Just want to check the integrity of the file ? - Select Cancel"+#CRLF$+#CRLF$+
                                          "Want to select another file ? - Select No", #PB_MessageRequester_YesNoCancel)
          If result=#PB_MessageRequester_Cancel
            key_1$=key_2$
            check_integrity=1
          ElseIf result=#PB_MessageRequester_No
            key_1$=key_2$
            CloseFile(file)
            Goto restart
          EndIf
        EndIf
        encrypted_file_found=1 : counter_0=get_counter
        For i = 0 To #HashLength>>3-1 : hash_2$+RSet(Hex(PeekA(@hash(0)+i)), 2, "0") : Next i : hash_2$=LCase(hash_2$)
      Else
        If mode>1
          CloseFile(file)
          ProcedureReturn "HINT ##08QF - File checked - This is not a valid"+method_0$+"file - Or your key is wrong !"
        EndIf
        encrypt_1:
        If Not mode
          message$="This file looks not valid"+method_0$+"!"+#CRLF$+#CRLF$+
                   "It is also possible that your password is wrong"+#CRLF$+#CRLF$+
                   "Or it is possible that it is a corrupted"+method_0$+"file"+#CRLF$+#CRLF$+
                   "Want to"+method__0$+"this file now with your password ? - Select Yes"+#CRLF$+#CRLF$+
                   "Want to select another file ? - Select No"
          If key_presetted
            result=MessageRequester("HINT", #HINTS+message$, #PB_MessageRequester_YesNo)
          Else
            result=MessageRequester("HINT", #HINTS+message$+#CRLF$+#CRLF$+"To change your password - Select Cancel", #PB_MessageRequester_YesNoCancel)
          EndIf
          
          If result=#PB_MessageRequester_No
            key_1$=key_2$
            CloseFile(file) : Goto restart
          ElseIf result=#PB_MessageRequester_Cancel
            CloseFile(file) : key$="" : Goto restart
          EndIf
        EndIf
        QAES_smart_universal_coder_KFB(0, @magic, @magic, 8, ReverseString(key$)+key$, counter) ; QAES crypter - Encrypt magic
        counter_0=counter
      EndIf
      
    Else
      If Not mode
        MessageRequester("ERROR", "Can not open file")
        Goto select_again
      Else
        ProcedureReturn "ERROR ##09QF - Can not open file !"
      EndIf
    EndIf
    
    If progressbar_state=2
      SetGadgetState(progressbar_ID, 0)
    EndIf
    
    blocks=(file_size-cryptextender_length)/block_size
    
    remaining=file_size-(block_size*blocks)
    
    If encrypted_file_found
      remaining-cryptextender_length
    EndIf
    
    timer=ElapsedMilliseconds()
    Repeat
      readed=ReadData(file, *buffer, block_size)
      
      If encrypted_file_found
        hash_bytes=readed-cryptextender_length
        If readed=block_size : hash_bytes=readed : EndIf
        If hash_bytes>0
          block_counter+1
          If blocks 
            If block_counter>blocks : hash_bytes=remaining : EndIf
          Else
            hash_bytes=file_size-cryptextender_length
          EndIf
          hash$=Fingerprint(*buffer, hash_bytes, #PB_Cipher_SHA3, #HashLength)
          hash$+key$+hash_1$+Str(counter_0)
          hash$=Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, #HashLength)
          hash_1$=hash$
        EndIf
      EndIf
      
      If Not check_integrity And Not set_counter_protection_mode
        QAES_smart_universal_coder_KFB(0, *buffer, *buffer, block_size, key$, counter_0, counter_1) ; QAES crypter
      EndIf
      
      If Not encrypted_file_found
        If readed>0
          hash$=Fingerprint(*buffer, readed, #PB_Cipher_SHA3, #HashLength)
          hash$+key$+hash_1$+Str(counter_0)
          hash$=Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, #HashLength)
          hash_1$=hash$ 
        EndIf
      EndIf
      
      If check_integrity
        writen+readed
      Else
        FileSeek(file, -readed, #PB_Relative) : writen+WriteData(file, *buffer, readed)
      EndIf 
      
      If progressbar_state
        window_event=WindowEvent()
      EndIf
      If progressbar_state=2 And ElapsedMilliseconds()>timer+30
        SetGadgetState(progressbar_ID, 100*writen/file_size)
        timer=ElapsedMilliseconds()
      EndIf
      counter_0+1 : counter_1+1
    Until Not readed
    
    If progressbar_state=2
      SetGadgetState(progressbar_ID, 100)
    EndIf
    
    hash$+key$+#Salt$ ; Finishing fingerprint
    hash$=LCase(Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, #HashLength))
    
    If encrypted_file_found And hash$<>hash_2$
      If check_integrity
        CloseFile(file) : FreeMemory(*buffer) : *buffer=0
        If Not mode
          If MessageRequester("WARNING", "File hash broken !"+#CRLF$+#CRLF$+
                                         "Want to use the file coder again ? - Select Yes", 
                              #PB_MessageRequester_YesNo)=#PB_MessageRequester_No
            ProcedureReturn ""
          EndIf
          Goto restart
        Else
          ProcedureReturn "WARNING ##10QF - File hash broken ! - Used counter =>"+Str(get_counter)
        EndIf
        
      Else
        file_broken=1
      EndIf
    EndIf
    
    If check_integrity
      CloseFile(file) : FreeMemory(*buffer) : *buffer=0
      If Not mode
        SetClipboardText(GetFilePart(path$)+#CRLF$+hash_2$)
        If MessageRequester("HINT", #HINTS+"All OK !"+#CRLF$+#CRLF$+"File integrity succesfully checked !"+#CRLF$+#CRLF$+
                                    "I put now the file hash and name in your clipboard"+#CRLF$+#CRLF$+hash_2$+#CRLF$+#CRLF$+
                                    "Want to use the file coder again ? - Select Yes", 
                            #PB_MessageRequester_YesNo)=#PB_MessageRequester_Yes
          Goto restart
        EndIf
      Else
        ProcedureReturn "ALLok ##11QF - File integrity succesfully checked ! - Used counter =>"+Str(get_counter)+" - File hash ==>"+hash_2$
      EndIf
      ProcedureReturn ""
    EndIf
    
    If OpenCryptRandom()
      set_fake_length.q=CryptRandom(#RandomizeFileLengthBytes)+#EnlargeFileLengthBytes
      Dim fake_content.a(set_fake_length-1)
      CryptRandomData(@fake_content(0), set_fake_length)
    Else
      set_fake_length.q=Random(#RandomizeFileLengthBytes)+#EnlargeFileLengthBytes
      Dim fake_content.a(set_fake_length-1)
      RandomData(@fake_content(0), set_fake_length)
    EndIf
    
    set_fake_length_1=set_fake_length
    
    If Not encrypted_file_found
      For i=0 To #HashLength>>3-1 : PokeA(@hash(0)+i, Val("$"+PeekS(@hash$+i*SizeOf(character)<<1, 2))) : Next i
      QAES_smart_universal_coder_KFB(0, @set_fake_length_1, @set_fake_length_1, 8, key$+ReverseString(key$))   ; QAES crypter - Crypt fake length
      QAES_smart_universal_coder_KFB(0, @hash(0), @hash(0), #HashLength>>3, key$+ReverseString(key$), counter) ; QAES crypter - Crypt hash
      QAES_smart_universal_coder_KFB(0, @counter, @counter, 8, ReverseString(key$)+key$+#salt$)                ; QAES crypter - Crypt counter
      
      writen+WriteData(file, @fake_content(0), set_fake_length)
      writen+WriteData(file, @set_fake_length_1, 8)
      writen+WriteData(file, @counter, 8)
      writen+WriteData(file, @magic, 8)
      writen+WriteData(file, @hash(0), #HashLength>>3)
      If writen<>file_size+cryptextender_length+set_fake_length
        CloseFile(file)
        If Not mode
          MessageRequester("ERROR", "Writen fails"+#CRLF$+#CRLF$+"Writen Bytes : "+Str(writen))
        Else
          ProcedureReturn "ERROR ##12QF - Writen fails - Writen Bytes : "+Str(writen)+" !"
        EndIf
        ProcedureReturn ""
      EndIf
    EndIf
    
    If encrypted_file_found
      FileSeek(file, -cryptextender_length, #PB_Relative)
      TruncateFile(file)
      If Lof(file)<>file_size-cryptextender_length
        CloseFile(file) : FreeMemory(*buffer)
        If Not mode
          MessageRequester("ERROR", "Truncate file fails")
        Else
          ProcedureReturn "ERROR ##13QF - Truncate file fails !"
        EndIf
        ProcedureReturn ""
      EndIf
    EndIf
    
    CloseFile(file)
    
    If file_extender$<>""
      If encrypted_file_found And Right(path$, Len(file_extender$))=file_extender$
        RenameFile(path$, Left(path$, Len(path$)-Len(file_extender$)))
      Else
        If Not encrypted_file_found
          RenameFile(path$, path$+file_extender$)
        EndIf
      EndIf
    EndIf
    
    If file_broken
      If Not mode
        message$="WARNING - File"+method_1$+"but file hash broken !"
      Else
        message$="WARNING ##14QF - File"+method_1$+"but file hash broken !"
      EndIf
    Else
      If encrypted_file_found
        If Not mode
          message$="All OK - File"+method_1$+"!"+#CRLF$+#CRLF$+
                   "I put now the file hash and name in your clipboard"+#CRLF$+#CRLF$+hash_2$
          SetClipboardText(GetFilePart(path$)+#CRLF$+hash_2$)
        Else
          message$="ALLok ##15QF - File"+method_1$+" ! - Used counter =>"+Str(get_counter)+" - File hash ==>"+hash_2$
        EndIf
      Else
        If Not mode
          message$="ALL OK - File "+method_0$+#CRLF$+#CRLF$+
                   "I put now the file hash and name in your clipboard"+#CRLF$+#CRLF$+hash$
          SetClipboardText(GetFilePart(path$)+#CRLF$+hash$)
        Else
          message$="ALLok ##16QF - File"+method_0$+" ! - File hash ==>"+hash$
        EndIf
      EndIf
    EndIf
    
    If Not mode
      If MessageRequester("HINT", #HINTS+message$+#CRLF$+#CRLF$+
                                  "Want to use the file coder again ?", 
                          #PB_MessageRequester_YesNo)=#PB_MessageRequester_Yes
        key_1$=key_2$
        Goto restart
      EndIf
    EndIf
    
    FreeMemory(*buffer)
    ProcedureReturn message$
    
  EndProcedure
  
EndModule
UseModule QAES_smart_file_coder

; Multi use demo
EnableExplicit

DeclareModule QAES_smart_image_coder
  UseModule QAES_smart_universal_coder_KFB
  Declare LoadImage_Encrypt_and_Save(source_path_image$, destination_path_image$, key$)
  Declare LoadImage_and_Decrypt(destination_path_image$, key$)
EndDeclareModule

Module QAES_smart_image_coder
  ; Image in place encrypting addon for the QAES_smart_universal_coder_KFB
  ; Author Werner Albus - www.nachtoptik.de
  ; Its nice you set a hint in your software for using QAES contents
  ; PureBasic x86 / x64
  Procedure LoadImage_Encrypt_and_Save(source_path_image$, destination_path_image$, key$)
    
    Protected file=ReadFile(#PB_Any, source_path_image$)
    If Not file : ProcedureReturn -21 : EndIf
    Protected counter.q
    If OpenCryptRandom()
      CryptRandomData(@counter, 8)
    Else
      RandomData(@counter, 8)
    EndIf
    Protected length=Lof(file)
    Protected *buffer=AllocateMemory(length+8)
    If Not *buffer : CloseFile(file) : ProcedureReturn -9 : EndIf
    If Not ReadData(file, *buffer, length)
      FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -21
    EndIf
    CloseFile(file)
    PokeQ(*buffer+length, counter)
    If Not QAES_smart_universal_coder_KFB(0, *buffer, *buffer, length, key$, counter)
      FreeMemory(*buffer) : ProcedureReturn -9
    EndIf
    file=OpenFile(#PB_Any, destination_path_image$)
    If Not file : FreeMemory(*buffer) : ProcedureReturn -22
    EndIf
    If WriteData(file, *buffer, length+8)<>length+8
      FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -22
    EndIf
    CloseFile(file)
    If *buffer : FreeMemory(*buffer) : EndIf
    ProcedureReturn 1
  EndProcedure
  
  Procedure LoadImage_and_Decrypt(destination_path_image$, key$)
    Protected file=ReadFile(#PB_Any, destination_path_image$)
    If Not file : ProcedureReturn -21 : EndIf
    Protected length=Lof(file)
    Protected *buffer=AllocateMemory(length)
    If Not *buffer : CloseFile(file) : ProcedureReturn -9 : EndIf
    FileSeek(file, length-8)
    Protected counter.q=ReadQuad(file)
    FileSeek(file, 0)
    If ReadData(file, *buffer, length)<>length
      FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -21
    EndIf
    CloseFile(file)
    If Not QAES_smart_universal_coder_KFB(0, *buffer, *buffer, length, key$, counter)
      FreeMemory(*buffer) : CloseFile(file) : ProcedureReturn -9
    EndIf
    Protected image_ID=CatchImage(#PB_Any, *buffer, length)
    If Not image_ID : FreeMemory(*buffer) : ProcedureReturn -6 : EndIf
    ProcedureReturn image_ID
  EndProcedure
EndModule
UseModule QAES_smart_image_coder

Define mode, key_stretching_loops, window_ID, progressbar_ID , key$, salt$, path_0$, path_1$

; mode=0 - Full automatic mode with file selectors
; mode=1 - Encrypt
; mode=2 - Decrypt
; mode=3 - Check the file integrity
; mode=4 - Check if a file is already encrypted
; If not window_ID or not progressbar_ID, you get not a progressbar
; A empty key (Password) open automatically a string selector

window_ID=OpenWindow(#PB_Any, 0, 0, 280, 50, "",  #PB_Window_ScreenCentered|#PB_Window_BorderLess)
progressbar_ID=ProgressBarGadget(#PB_Any, 10, 10, 260, 30, 0, 100, #PB_ProgressBar_Smooth)

#cryptfile_extender$=" [encrypted]" ; You can change how ever you want

key$="This is a test key" ; If you do not pass a key for automatic mode, a key requester opens

salt$="41a219&$()(/=/(&(605nnufDTUKKLÖNM65w32ß0c9ß87/=)(" ; Salt - You can change

key_stretching_loops=1e5 ; Key stretching loops

; Use ever key stretching - This impeded key brute force quite substantial
; You can, but you must not set a window and a progressbar for the key stretching progress
key_stretching(window_ID, progressbar_ID, key$, salt$, key_stretching_loops)

; Automatic file crypting with requesters - Activate only this one line :
QAES_smart_file_coder(0, window_ID, progressbar_ID, "", key$, #cryptfile_extender$)

; Manual modes
path_0$=GetTemporaryDirectory()+"TestPic_1.jpg" ; Create a little picture for test
path_1$=path_0$+#cryptfile_extender$
DeleteFile(path_1$) ; Remove artifacts
UseJPEGImageEncoder()
SaveImage(CreateImage(#PB_Any, 10, 10), path_0$, #PB_ImagePlugin_JPEG)
Debug "###### File crypter ###"
Debug QAES_smart_file_coder(1, window_ID, progressbar_ID, path_0$, key$, #cryptfile_extender$) ; Encrypt a file
Debug QAES_smart_file_coder(4, window_ID, progressbar_ID, path_1$, key$, #cryptfile_extender$) ; Check if the file is already valid encrypted
Debug QAES_smart_file_coder(3, window_ID, progressbar_ID, path_1$, key$, #cryptfile_extender$) ; Check the file integrity
Debug QAES_smart_file_coder(2, window_ID, progressbar_ID, path_1$, key$, #cryptfile_extender$) ; Decrypt a file
Debug ""

Debug "###### File protection without encrypt a file ###"
SaveImage(CreateImage(#PB_Any, 10, 10), path_0$, #PB_ImagePlugin_JPEG)
Debug QAES_smart_file_coder(1, window_ID, progressbar_ID, path_0$, key$, "", 10) ; Protect a file
Debug QAES_smart_file_coder(3, window_ID, progressbar_ID, path_0$, key$, "", 10) ; Check the file protection - Also for encrypted files
Debug QAES_smart_file_coder(2, window_ID, progressbar_ID, path_0$, key$, "", 10) ; Remove the file protection
Debug ""

Debug "###### In place image crypter with file creating ###"
DeleteFile(path_0$+#cryptfile_extender$) ; Remove artifacts
UseJPEGImageEncoder()
Debug "State - create, encrypt and save a image : "+LoadImage_Encrypt_and_Save(path_0$, path_0$+#cryptfile_extender$, key$)
UseJPEGImageDecoder()
Debug "Load and decrypt a image - Resulted Image ID : "+LoadImage_and_Decrypt(path_0$+#cryptfile_extender$, key$)
Debug ""

Debug "###### In place string and CSV crypter with file creating ###"
Define destination_path$=GetTemporaryDirectory()+"/Testfile"
DeleteFile(destination_path$) ; Remove artifacts
Define string$="The quick brown fox jumps over the lazy dog 0123456789"
; Create a encrypted string file -----------------
create_encrypted_string_file(string$, destination_path$, key$)
; Read a encrypted string file ----------------
Debug read_encrypted_string_file(destination_path$, key$)
Debug ""

; String crypting - In place crypting - With string termination protection
; Hint : Created pseudo control characters in the encrypted string can temporarily change the font size or other in the debugger window
Debug "###### In place string crypter ###"
Define string_source$="Hello World, this is the QAES_smart_universal_coder_KFB"
Debug "Plain string : "+string_source$ ; Plain string
                                       ; Encrypt string
QAES_smart_universal_coder_KFB(SizeOf(character), @string_source$, @string_source$, StringByteLength(string_source$), key$)
Debug "Encrypted string : "+string_source$ ; Encrypted string
                                           ; Decrypt string
QAES_smart_universal_coder_KFB(SizeOf(character), @string_source$, @string_source$, StringByteLength(string_source$), key$)
Debug "Decrypted string : "+string_source$ ; Decrypted string
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
Thorsten1867
Addict
Addict
Posts: 1366
Joined: Wed Aug 24, 2005 4:02 pm
Location: Germany

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by Thorsten1867 »

Updated: qAES_Module.pbi
  • Removed: File()
  • Added: EncodeFile() / DecodeFile()
  • Added: String2File() / File2String()
  • Added: LoadCryptImage() /SaveCryptImage()
  • Added: LoadCryptXML() / SaveCryptXML()
  • Added: LoadCryptJSON() / SaveCryptJSON()
Translated with http://www.DeepL.com/Translator

Download of PureBasic - Modules
Download of PureBasic - Programs

[Windows 11 x64] [PB V5.7x]
User avatar
Caronte3D
Addict
Addict
Posts: 1055
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by Caronte3D »

Hi
I'm going crazy searching a way to send and receive encrypted strings between PB and PHP.
Is there a way to use a standard (like aes256cbc) on both sides?
Every piece of code I test fail on one of the sides :cry:
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: QAES AES256 KFB mode special coder for string, binary, t

Post by #NULL »

Caronte3D wrote:Hi
I'm going crazy searching a way to send and receive encrypted strings between PB and PHP.
Is there a way to use a standard (like aes256cbc) on both sides?
Every piece of code I test fail on one of the sides :cry:
From PB to PHP this one works:
viewtopic.php?f=13&t=74201
Post Reply