encrypt/decrypt strings using AES

Share your advanced PureBasic knowledge/code with the community.
said
Enthusiast
Enthusiast
Posts: 342
Joined: Thu Apr 14, 2011 6:07 pm

encrypt/decrypt strings using AES

Post by said »

I assume this has been approached many times, here is my version (combines the power of AES with Base64)!

Code: Select all

; Encrypt/Decrypt any string using AES256-CBC + Base64
; Base64 is used to hide zero-bytes '\0' that could be generated by AES
; Ascii/Unicode
; Said - Aug 2013

EnableExplicit

; some random generated data uisng CryptRandom()
; size of Key = 32 (AES-256Bits)
; size of InitVect = 16 (CBC)
; PaddingB64 is a random 64-char string needed for padding short strings used with Base64Encoding and AES
DataSection
ENC_Key:
    Data.b  $5B,$2C,$CE,$6E,$4E,$D9,$9D,$0B,$08,$AE,$24,$2C,$D6,$49,$CF,$BB,$A8,$CE,$DC,$9C,$C9,$09,$CF,$E6,$88,$CC,$07,$14,$11,$AA,$6B,$60
ENC_InitVect:
    Data.b  $8C,$0D,$4E,$ED,$67,$96,$FB,$F0,$D3,$72,$87,$35,$3E,$BE,$42,$A2
ENC_PaddingB64:
    Data.s  "c1e39477b19d95223577a457960959be693060b0c683ec7aaf127d87807c6e02"
EndDataSection

Procedure.i _EncBuffer(*Input, *Output)
    
    If (MemorySize(*Input) >= 16) And (MemorySize(*Input) = MemorySize(*Output))
        If AESEncoder(*Input, *Output, MemorySize(*Input), ?ENC_Key, 256, ?ENC_InitVect, #PB_Cipher_CBC)
            ProcedureReturn #True
        EndIf
    EndIf
    ProcedureReturn #False   ; AES cant encrypt a memory block with size < 16
    
EndProcedure
Procedure.i _DecBuffer(*Input, *Output)
    
    If (MemorySize(*Input) >= 16) And (MemorySize(*Input) = MemorySize(*Output))
        If AESDecoder(*Input, *Output, MemorySize(*Input), ?ENC_Key, 256, ?ENC_InitVect, #PB_Cipher_CBC)
            ProcedureReturn #True
        EndIf
    EndIf
    ProcedureReturn #False   ; AES cant encrypt a memory block with size < 16
    
EndProcedure

Procedure.s EncString(in.s)
    Protected paddStr.s, wrd.s, out.s, *p, *mb0, *mb1, *mb2, n0, n1, n2
    
    If in = "" : ProcedureReturn "" : EndIf
    
    Restore ENC_PaddingB64
    Read.s paddStr
    
    ; we always padd as input could be too short
    n0      = StringByteLength(paddStr) + StringByteLength(in) + SizeOf(Character)
    *mb0    = AllocateMemory(n0) : *p = *mb0
    CopyMemoryString(@paddStr, @*p)
    CopyMemoryString(@in)
    
    ; encrypting using AES
    n1      = n0
    *mb1    = AllocateMemory(n1)
    _EncBuffer(*mb0, *mb1)
    
    ; encoding encrypted buffer using Base64 to mask \0 if any (needed for PeekS())
    n2      = n1 * 1.4
    *mb2    = AllocateMemory(n2)
    Base64Encoder(*mb1, n1, *mb2, n2)
    
    ; encrypted buffer is now ready for PeekS()
    out    = PeekS(*mb2)
    
    FreeMemory(*mb0)
    FreeMemory(*mb1)
    FreeMemory(*mb2)
    
    ProcedureReturn out
    
EndProcedure
Procedure.s DecString(in.s)
    ; decrypts a string encrypted with EncString()
    Protected paddStr.s, wrd.s, out.s, *mb1, *mb2, n0, n1, n2
    
    If in = "" : ProcedureReturn "" : EndIf
    
    ; decode encrypted string using Base64 --> encrypted-buffer
    n0      = StringByteLength(in)
    *mb1    = AllocateMemory(n0)
    n1      = Base64Decoder(@in, n0, *mb1, n0)
    *mb1    = ReAllocateMemory(*mb1, n1)        ; adjust size fo encrypted-buffer! 
    
    n2      = n1
    *mb2    = AllocateMemory(n2)
    _DecBuffer(*mb1, *mb2)
    wrd     = PeekS(*mb2)
    
    Restore ENC_PaddingB64
    Read.s paddStr
    
    If Mid(wrd, 1, Len(paddStr)) = paddStr
        out = Mid(wrd, Len(paddStr)+1)
    EndIf
    
    FreeMemory(*mb1)
    FreeMemory(*mb2)
    
    ProcedureReturn out
    
EndProcedure

; test
CompilerIf #PB_Compiler_IsMainFile

    Global i, n, *mb, org.s, enc.s, dec.s
    
    ; test short string
    org = "string"
    enc = EncString(org)
    dec = DecString(enc)
    
    ; random tests
    n = 10000
    *mb = AllocateMemory(n+2) 
    For i = 1 To 1000
        RandomData(*mb, n)
        org = PeekS(*mb)
        enc = EncString(org)
        dec = DecString(enc)
        If dec = org
            ;Debug "ok L = " + Str(Len(org))
        Else
            Debug ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> failed L = " + Str(Len(org))
        EndIf
    Next
    FreeMemory(*mb)
CompilerEndIf

amine_t
New User
New User
Posts: 2
Joined: Fri Feb 21, 2014 6:58 pm

Re: encrypt/decrypt strings using AES

Post by amine_t »

Thank you Said !
is it possible to avoid Base64 encoding ? because it makes encrypted strings larger
User avatar
skywalk
Addict
Addict
Posts: 4211
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: encrypt/decrypt strings using AES

Post by skywalk »

said wrote:; Base64 is used to hide zero-bytes '\0' that could be generated by AES
You cannot encrypt a string and make it smaller. You are thinking of compression. :wink:
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: encrypt/decrypt strings using AES

Post by rsts »

amine_t wrote:Thank you Said !
is it possible to avoid Base64 encoding ? because it makes encrypted strings larger
Yes, it is possible to avoid base-64 encoding using AES. But stay away from string operations. e.g. peeks.

I believe there have been other aes routines posted which did not utilize base-64 encoding. Try a search.
said
Enthusiast
Enthusiast
Posts: 342
Joined: Thu Apr 14, 2011 6:07 pm

Re: encrypt/decrypt strings using AES

Post by said »

amine_t wrote:Thank you Said !
is it possible to avoid Base64 encoding ? because it makes encrypted strings larger
You are welcome!

The answer to your questions is definitely yes but one would need to use some nasty tricks (one option could be to replace any \0 with a very special sequence of bytes that's not available in the encrypted buffer ... and do all the handling of inserting/removing properly ... this is somehow a headache)
Using Base64, even though it does make strings larger :( ... it is still much easier to handle with readily available routines in PB, so no wonder you will mostly find in the forums routines that make use of Base64 PB functions when dealing with encrypting/decrypting.
The length of ENC_PaddingB64 above is made 64 because Base64 needs to work with at least 64 bytes buffer, this is a safe needed length when the program is compiled in ascii (otherwise it can be reduced to 32 characters if the program is compiled in unicode)

And last, if you are planning to use those routines in your application, better replace the bytes in ENC_Key, ENC_InitVect with your own random values
collectordave
Addict
Addict
Posts: 1310
Joined: Fri Aug 28, 2015 6:10 pm
Location: Portugal

Re: encrypt/decrypt strings using AES

Post by collectordave »

Hi Tried the above code from said and it does not work in PB5.6B3

Regards

cd
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.
firace
Addict
Addict
Posts: 946
Joined: Wed Nov 09, 2011 8:58 am

Re: encrypt/decrypt strings using AES

Post by firace »

x86 or x64?
What do you mean by "does not work"? Any error messages?
It seems to work fine for me under PB5.51 x86 + Win 10 x64
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: encrypt/decrypt strings using AES

Post by walbus »

It is available creating a AES cryter who ignore zero bytes, different available for ascii and unicode and mixed string - binary :wink:
collectordave
Addict
Addict
Posts: 1310
Joined: Fri Aug 28, 2015 6:10 pm
Location: Portugal

Re: encrypt/decrypt strings using AES

Post by collectordave »

BASE64Encoder() changed to BASE64EncoderBuffer()

Check this post
http://www.purebasic.fr/english/viewtop ... =4&t=67492

I did not note the change when PB was updated.

Thanks to all

cd
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.
User avatar
Michael Vogel
Addict
Addict
Posts: 2797
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: encrypt/decrypt strings using AES

Post by Michael Vogel »

"Not work" in Beta 3 could mean, that Base64Encoder needs other parameters in the beta...

Another point, wouldn't it be enough to define a 32 byte puffer instead of 64 for the padding (to make the encoded strings smaller)?
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: encrypt/decrypt strings using AES

Post by walbus »

Post Reply