Page 1 of 1

encrypt/decrypt strings using AES

Posted: Mon Aug 19, 2013 4:51 am
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


Re: encrypt/decrypt strings using AES

Posted: Sun Mar 30, 2014 2:58 pm
by amine_t
Thank you Said !
is it possible to avoid Base64 encoding ? because it makes encrypted strings larger

Re: encrypt/decrypt strings using AES

Posted: Sun Mar 30, 2014 4:07 pm
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:

Re: encrypt/decrypt strings using AES

Posted: Sun Mar 30, 2014 8:46 pm
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.

Re: encrypt/decrypt strings using AES

Posted: Mon Mar 31, 2014 7:19 am
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

Re: encrypt/decrypt strings using AES

Posted: Sat Feb 25, 2017 8:57 am
by collectordave
Hi Tried the above code from said and it does not work in PB5.6B3

Regards

cd

Re: encrypt/decrypt strings using AES

Posted: Sat Feb 25, 2017 10:25 am
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

Re: encrypt/decrypt strings using AES

Posted: Sat Feb 25, 2017 11:02 am
by walbus
It is available creating a AES cryter who ignore zero bytes, different available for ascii and unicode and mixed string - binary :wink:

Re: encrypt/decrypt strings using AES

Posted: Sat Feb 25, 2017 11:12 am
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

Re: encrypt/decrypt strings using AES

Posted: Sat Feb 25, 2017 11:19 am
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)?

Re: encrypt/decrypt strings using AES

Posted: Sat Feb 25, 2017 12:46 pm
by walbus