String to encrypted file -high efficient -AES based Module

Share your advanced PureBasic knowledge/code with the community.
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

String to encrypted file -high efficient -AES based Module

Post by walbus »

Andre had asked me for a solution to securely encrypt CSV files internally
The fastest possible solution for large files which doesn't inflate them further
This is how a small crypter was created that works as an addon based on the QAES_universal_smart_coders
The generated files are encrypted similar to CBC mode, with randomized IV
I don't think it has ever been possible with PB to do this so easily and effectively

Well, now it's available ...

There is no problem that cannot be easy solved with QAES_smart_universal_coder :shock:

Code: Select all

;- QAES AES256 OFB mode two stage 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 <!6 bytes

; With mode ASCII you can encrypt mixed data, string and binary - This ignore the encryption from zero bytes

; The coder go ever forward, a extra decoder is unnecessary !
; You cipher a file blockwise, set ever the current block number (consecutive) with the counter - Important !

; Author Werner Albus - www.nachtoptik.de - www.quick-aes-256.de
; No warranty whatsoever - Use at your own risk

DeclareModule QAES_smart_universal_coder
  
  Declare QAES_smart_universal_coder(mode, *buffer_in.word, *buffer_out.word, bytes.q, key$, counter.q=0)
  
EndDeclareModule

Module QAES_smart_universal_coder
  
  EnableExplicit
  
  UseSHA3Fingerprint()
  
  ;- QAES AES256 OFB mode two stage special coder for all things - binarys - strings - text files --------------------
  
  ; This coder can handle automatic string termination for PB strings in compiler mode ASCII and UNICODE
  
  ; The coder works with all data lengths
  
  ; With mode ASCII you can encrypt mixed data, string and binary - This ignore the encryption from zero bytes
  
  ; The coder go ever forward, a extra decoder is unnecessary !
  ; You cipher a file blockwise, set ever the current block number (consecutive) with the counter - Important !
  Procedure QAES_smart_universal_coder(mode, *buffer_in.word, *buffer_out.word, bytes.q, key$, counter.q=0)
    
    If Not bytes.q Or key$="" : ProcedureReturn 0 : EndIf
    
    Protected.q i, swap_
    Protected ii, iii, bytes_minus_x, stepp=SizeOf(character)<<1
    Protected *buffer_in_asc.ascii, *buffer_out_asc.ascii
    Protected hash$=key$+Str(counter)+"t8690352cj2p1ch7fgw34uotmq09745$%()=)&%" ; + Salt, you can change
    Static fixed_key_string${64}
    Static Dim register.q(3)
    
    fixed_key_string$=Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, 256)
    
    If mode=2
      bytes_minus_x=bytes-3
    Else
      bytes_minus_x=bytes-2
      *buffer_in_asc.ascii=*buffer_in
      *buffer_out_asc.ascii=*buffer_out
    EndIf
    
    For ii = 0 To 31 : PokeA(@register(0)+ii, Val("$"+PeekS(@fixed_key_string$+iii, 2))) : iii+stepp : Next ; Create a key
    
    Repeat
      If Not AESEncoder(@register(0), @register(0), 32, @register(0), 256, 0, #PB_Cipher_ECB) : ProcedureReturn 0 : EndIf
      swap_=register(0) : register(0)=register(3) : register(3)=swap_ ; Never use here
      swap_=register(1) : register(1)=register(2) : register(2)=swap_ ; the PB Swap function !
      If Not AESEncoder(@register(0), @register(0), 16, @register(0), 256, 0, #PB_Cipher_ECB) : ProcedureReturn 0 : EndIf
      
      If mode=2
        Protected *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
      ElseIf mode=1
        Protected *register_asc.ascii=@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
      Else
        *register_asc.ascii=@register(0)
        For ii=0 To 15
          *buffer_out_asc\a=*buffer_in_asc\a ! *register_asc\a
          If i>bytes_minus_x : Break 2 : EndIf
          *buffer_in_asc+1 : *buffer_out_asc+1 : *register_asc+1 : i+1
        Next ii
      EndIf
    ForEver
    
    ProcedureReturn 1
  EndProcedure
  
EndModule
UseModule QAES_smart_universal_coder

; =======================================================================

; String to file crypter module
; Addon for the QAES_smart_universal_coder
DeclareModule QAES_StringToFileCrypter
  UseModule QAES_smart_universal_coder
  Declare create_encrypted_string_file(string$, destination_path_csv$, key$)
  Declare.s read_encrypted_string_file(destination_path_csv$, key$)
EndDeclareModule

Module QAES_StringToFileCrypter
  EnableExplicit
  
  Procedure create_encrypted_string_file(string$, destination_path_csv$, key$)
    ; Create a encryoted string file
    Protected file=CreateFile(#PB_Any, destination_path_csv$)
    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(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_csv$, key$)
    ; Read a encrypted string file
    Protected file=ReadFile(#PB_Any, destination_path_csv$)
    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(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

; =======================================================================

EnableExplicit

Define destination_path_csv$=GetUserDirectory(#PB_Directory_Desktop)+"/Testfile"

Define key$= "this is the key"

Define string$="The quick brown fox jumps over the lazy dog 0123456789"

; Create a encrypted string file -----------------
Debug create_encrypted_string_file(string$, destination_path_csv$, key$)

; Read a encrypted string file ----------------
Debug read_encrypted_string_file(destination_path_csv$, key$)
Last edited by walbus on Sun Feb 11, 2018 10:25 pm, edited 1 time in total.
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2071
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: String to encrypted file -high efficient -AES based Mo

Post by Andre »

Works very well. Thank you very much, Werner! :D
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5353
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: String to encrypted file -high efficient -AES based Mo

Post by Kwai chang caine »

Works fine here
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: String to encrypted file -high efficient -AES based Mo

Post by walbus »

Hi, KCC,
yep, its a very usefull crypter

Regards Werner
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2071
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: String to encrypted file -high efficient -AES based Mo

Post by Andre »

With this code and further help of 'walbus' I was able to convert all 29 databases (.csv files) of my project into encrypted versions for public release. Encrypting/decrypting is very very fast, and my databases are now secure. Thank you very much, Werner! :D
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: String to encrypted file -high efficient -AES based Mo

Post by walbus »

Hi Andre,
nice to here you are happy with your QAES crypter

Yeah, it was a little work, but it was worth it.
This resulted in a special crypter for CSV databases, with direct access !

By bypassing all string constructions an enormous working speed is achieved. :wink:
Rinzwind
Enthusiast
Enthusiast
Posts: 638
Joined: Wed Mar 11, 2009 4:06 pm
Location: NL

Re: String to encrypted file -high efficient -AES based Mo

Post by Rinzwind »

It doesn't seem to like unicode characters (try text Begrüßen ภาษาไทย!, a good random check for any string function imho).

It does start to work when changing 1 line Protected *buffer=Ascii(string$) to Protected *buffer=UTF8(string$)

Is this OK?
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2071
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: String to encrypted file -high efficient -AES based Mo

Post by Andre »

@Rinzwind: Werner sent me an update of the complete code, which should also solve your described problem. Have fun!
walbus wrote: 'Mode' parameter description for the multi crypter QAES_smart_universal_coder():

mode=0 : binary crypting
mode=1 : ASCII and binary crypting
mode=2 : Unicode

Code: Select all

;- QAES AES256 OFB mode two stage 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 <!6 bytes

; With mode ASCII you can encrypt mixed data, string and binary - This ignore the encryption from zero bytes

; The coder go ever forward, a extra decoder is unnecessary !
; You cipher a file blockwise, set ever the current block number (consecutive) with the counter - Important !

; Author Werner Albus - www.nachtoptik.de - www.quick-aes-256.de
; No warranty whatsoever - Use at your own risk

DeclareModule QAES_smart_universal_coder
 
  Declare QAES_smart_universal_coder(mode, *buffer_in.word, *buffer_out.word, bytes.q, key$, counter.q=0)
 
EndDeclareModule

Module QAES_smart_universal_coder
 
  EnableExplicit
 
  UseSHA3Fingerprint()
 
  ;- QAES AES256 OFB mode two stage special coder for all things - binarys - strings - text files --------------------
 
  ; This coder can handle automatic string termination for PB strings in compiler mode ASCII and UNICODE
 
  ; The coder works with all data lengths
 
  ; With mode ASCII you can encrypt mixed data, string and binary - This ignore the encryption from zero bytes
 
  ; The coder go ever forward, a extra decoder is unnecessary !
  ; You cipher a file blockwise, set ever the current block number (consecutive) with the counter - Important !
  Procedure QAES_smart_universal_coder(mode, *buffer_in.word, *buffer_out.word, bytes.q, key$, counter.q=0)
   
    If Not bytes.q Or key$="" : ProcedureReturn 0 : EndIf
   
    Protected.q i, swap_
    Protected ii, iii, bytes_minus_x, stepp=SizeOf(character)<<1
    Protected *buffer_in_asc.ascii, *buffer_out_asc.ascii
    Protected hash$=key$+Str(counter)+"t8690352cj2p1ch7fgw34uotmq09745$%()=)&%" ; + Salt, you can change
    Static fixed_key_string${64}
    Static Dim register.q(3)
   
    fixed_key_string$=Fingerprint(@hash$, StringByteLength(hash$), #PB_Cipher_SHA3, 256)
   
    If mode=2
      bytes_minus_x=bytes-3
    Else
      bytes_minus_x=bytes-2
      *buffer_in_asc.ascii=*buffer_in
      *buffer_out_asc.ascii=*buffer_out
    EndIf
   
    For ii = 0 To 31 : PokeA(@register(0)+ii, Val("$"+PeekS(@fixed_key_string$+iii, 2))) : iii+stepp : Next ; Create a key
   
    Repeat
      If Not AESEncoder(@register(0), @register(0), 32, @register(0), 256, 0, #PB_Cipher_ECB) : ProcedureReturn 0 : EndIf
      swap_=register(0) : register(0)=register(3) : register(3)=swap_ ; Never use here
      swap_=register(1) : register(1)=register(2) : register(2)=swap_ ; the PB Swap function !
      If Not AESEncoder(@register(0), @register(0), 16, @register(0), 256, 0, #PB_Cipher_ECB) : ProcedureReturn 0 : EndIf
     
      If mode=2
        Protected *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
      ElseIf mode=1
        Protected *register_asc.ascii=@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
      Else
        *register_asc.ascii=@register(0)
        For ii=0 To 15
          *buffer_out_asc\a=*buffer_in_asc\a ! *register_asc\a
          If i>bytes_minus_x : Break 2 : EndIf
          *buffer_in_asc+1 : *buffer_out_asc+1 : *register_asc+1 : i+1
        Next ii
      EndIf
    ForEver
   
    ProcedureReturn 1
  EndProcedure
 
EndModule
UseModule QAES_smart_universal_coder

; =======================================================================

; String to file crypter module
; Addon for the QAES_smart_universal_coder
DeclareModule QAES_StringToFileCrypter
  UseModule QAES_smart_universal_coder
  Declare create_encrypted_string_file(string$, destination_path_csv$, key$)
  Declare.s read_encrypted_string_file(destination_path_csv$, key$)
EndDeclareModule

Module QAES_StringToFileCrypter
  EnableExplicit
 
  Procedure create_encrypted_string_file(string$, destination_path_csv$, key$)
    ; Create a encryoted string file
    Protected file=CreateFile(#PB_Any, destination_path_csv$)
    If file
      Protected counter.q
      If OpenCryptRandom()
        CryptRandomData(@counter, 8)
      Else
        RandomData(@counter, 8)
      EndIf
      Protected *buffer=UTF8(string$)
      If Not *buffer : ProcedureReturn 0 : EndIf
      If Not QAES_smart_universal_coder(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_csv$, key$)
    ; Read a encrypted string file
    Protected file=ReadFile(#PB_Any, destination_path_csv$)
    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(0, *buffer, *buffer, MemorySize(*buffer), key$, counter)
        FreeMemory(*buffer) : ProcedureReturn ""
      EndIf
      Protected string$=PeekS(*buffer , -1, #PB_UTF8 )
      CloseFile(file)
    Else
      ProcedureReturn ""
    EndIf
    If *buffer : FreeMemory(*buffer) : EndIf
    ProcedureReturn string$
  EndProcedure
 
EndModule
UseModule QAES_StringToFileCrypter

; =======================================================================

EnableExplicit

Define destination_path_csv$=GetUserDirectory(#PB_Directory_Desktop)+"/Testfile"

Define key$= "this is the key"

Define string$="The quick brown fox jumps over the lazy dogภาษาไทย0123456789"

; Create a encrypted string file -----------------
Debug create_encrypted_string_file(string$, destination_path_csv$, key$)

; Read a encrypted string file ----------------
Debug read_encrypted_string_file(destination_path_csv$, key$)     
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
Thorsten1867
Addict
Addict
Posts: 1366
Joined: Wed Aug 24, 2005 4:02 pm
Location: Germany

Re: String to encrypted file -high efficient -AES based Mo

Post by Thorsten1867 »

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

Download of PureBasic - Modules
Download of PureBasic - Programs

[Windows 11 x64] [PB V5.7x]
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5353
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: String to encrypted file -high efficient -AES based Mo

Post by Kwai chang caine »

Thanks 8)
ImageThe happiness is a road...
Not a destination
Post Reply