encrypt/decrypt strings using AES
Posted: Mon Aug 19, 2013 4:51 am
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