It is currently Wed Dec 02, 2020 1:31 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: QAES AES256 KFB mode special coder for string, binary, text
PostPosted: Sun Sep 30, 2018 7:20 pm 
Offline
PureBasic Team
PureBasic Team
User avatar

Joined: Fri Apr 25, 2003 6:14 pm
Posts: 1870
Location: Germany (Saxony, Deutscheinsiedel)
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:
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)


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Sun Sep 30, 2018 7:34 pm 
Offline
Addict
Addict
User avatar

Joined: Sun Nov 05, 2006 11:42 pm
Posts: 4801
Location: Lyon - France
Thanks for sharing 8)

_________________
ImageThe happiness is a road...
Not a destination


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Mon Jul 22, 2019 10:49 am 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Oct 06, 2007 11:20 pm
Posts: 292
Location: France
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:
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 webSite (french) with PB apps : LDVMULTIMEDIA
PB - 5.4x LTS / 5.7x - W10 x64 - Ryzen 7 3700x
Repeat : try : until done = 1


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Mon Jul 22, 2019 11:01 pm 
Offline
PureBasic Team
PureBasic Team
User avatar

Joined: Fri Apr 25, 2003 6:14 pm
Posts: 1870
Location: Germany (Saxony, Deutscheinsiedel)
@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:
; 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)


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Tue Jul 23, 2019 2:49 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Sat Oct 06, 2007 11:20 pm
Posts: 292
Location: France
Hey. I saw a walbus module to encrypt files but un missed that.
Thanks André.

_________________
~Ar-S~

My webSite (french) with PB apps : LDVMULTIMEDIA
PB - 5.4x LTS / 5.7x - W10 x64 - Ryzen 7 3700x
Repeat : try : until done = 1


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Mon Jul 29, 2019 9:17 pm 
Offline
PureBasic Team
PureBasic Team
User avatar

Joined: Fri Apr 25, 2003 6:14 pm
Posts: 1870
Location: Germany (Saxony, Deutscheinsiedel)
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:
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)


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Tue Jul 30, 2019 7:18 am 
Offline
Moderator
Moderator

Joined: Thu Dec 31, 2009 11:05 pm
Posts: 1113
Location: Gernsbach (Germany)
Andre wrote:
Code:
[...]
Goto select_again
[...]
select_again:
[...]

Jump markers? :shock:
Couldn't this have been better solved? I'm not a friend of jump marks.

_________________
ImageImageImageImage Image


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Wed Jul 31, 2019 9:20 pm 
Offline
Addict
Addict
User avatar

Joined: Wed Aug 24, 2005 4:02 pm
Posts: 1265
Location: Germany
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:
;/ =========================
;/ =    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

_________________
Translated with http://www.DeepL.com/Translator

Download of PureBasic - Modules
Download of PureBasic - Programs

[Windows 10 x64] [PB V5.7x]


Last edited by Thorsten1867 on Thu Aug 01, 2019 1:24 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Thu Aug 01, 2019 8:27 am 
Offline
Moderator
Moderator

Joined: Thu Dec 31, 2009 11:05 pm
Posts: 1113
Location: Gernsbach (Germany)
Yes, your code is much better. Thank you

_________________
ImageImageImageImage Image


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Thu Aug 01, 2019 11:18 am 
Offline
Addict
Addict
User avatar

Joined: Sat Apr 26, 2003 2:15 pm
Posts: 897
Location: Cuernavaca, Mexico
Quick question..
Can't find qAES::FileCoder()

should it be: qAES::SmartFileCoder() in the example area :?:

_________________
- It was too lonely at the top.

Current Machine: Win 10 Pro 64-bit, Dual Xeon E5-2670, 64 gigs ram, Geforce GTX 1660 Ti w/6 gigs ram


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Thu Aug 01, 2019 1:13 pm 
Offline
Addict
Addict
User avatar

Joined: Wed Aug 24, 2005 4:02 pm
Posts: 1265
Location: Germany
Bug fixed

_________________
Translated with http://www.DeepL.com/Translator

Download of PureBasic - Modules
Download of PureBasic - Programs

[Windows 10 x64] [PB V5.7x]


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Fri Aug 02, 2019 10:25 pm 
Offline
PureBasic Team
PureBasic Team
User avatar

Joined: Fri Apr 25, 2003 6:14 pm
Posts: 1870
Location: Germany (Saxony, Deutscheinsiedel)
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:
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)


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Sat Aug 03, 2019 2:20 pm 
Offline
Addict
Addict
User avatar

Joined: Wed Aug 24, 2005 4:02 pm
Posts: 1265
Location: Germany
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 10 x64] [PB V5.7x]


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Wed Dec 11, 2019 7:26 pm 
Offline
Enthusiast
Enthusiast
User avatar

Joined: Fri Jan 22, 2016 5:33 pm
Posts: 134
Location: Spain
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:


Top
 Profile  
Reply with quote  
 Post subject: Re: QAES AES256 KFB mode special coder for string, binary, t
PostPosted: Sat Dec 14, 2019 1:55 pm 
Offline
Addict
Addict

Joined: Thu Aug 30, 2007 11:54 pm
Posts: 1278
Location: right here
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:
https://www.purebasic.fr/english/viewtopic.php?f=13&t=74201


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next

All times are UTC + 1 hour


Who is online

Users browsing this forum: DK_PETER and 16 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye