Windows: Encryption with password using the Windows API

Share your advanced PureBasic knowledge/code with the community.
El_Choni
TailBite Expert
TailBite Expert
Posts: 1007
Joined: Fri Apr 25, 2003 6:09 pm
Location: Spain

Windows: Encryption with password using the Windows API

Post by El_Choni »

Hi,

I've seen other encryption snippets around, but I think none uses teh Windows API to do it. The API allows you to use several encryption algorithm. This example uses RC4.

Code: Select all

Procedure Error(message$)
  wError = GetLastError_()
  If wError
    *ErrorBuffer = AllocateMemory(1024)
    FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, wError, 0, *ErrorBuffer, 1024, 0)
    message$+Chr(10)+PeekS(*ErrorBuffer)
    FreeMemory(*ErrorBuffer)
  EndIf
  MessageRequester("Error", message$)
EndProcedure

#PROV_RSA_FULL = 1
#ALG_SID_MD5 = 3
#ALG_SID_RC4 = 1
#ALG_CLASS_DATA_ENCRYPT = 3<<13
#ALG_CLASS_HASH = 4<<13
#ALG_TYPE_ANY = 0
#ALG_TYPE_STREAM = 4<<9
#CALG_MD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD5
;
; Valid hashing algorithms:
;
; #ALG_SID_HMAC = 9
; #ALG_SID_MAC = 5
; #ALG_SID_MD2 = 1
; #ALG_SID_SHA = 4
; #ALG_SID_SHA1 = 4
; #ALG_SID_SSL3SHAMD5 = 8
; #CALG_HMAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_HMAC
; #CALG_MAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MAC
; #CALG_MD2 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD2
; #CALG_SHA = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA
; #CALG_SHA1 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA1
; #CALG_SSL3_SHAMD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SSL3SHAMD5
#CALG_RC4 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_STREAM|#ALG_SID_RC4
#CRYPT_EXPORTABLE = 1
#CRYPT_NEWKEYSET = 8

Procedure Encrypt(*lpData, DataLength, password$)
  If CryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, 0)=0
    CryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
  EndIf
  If hProv
    ; Hashing algorithms defined in the Windows API (constants commented above):
    ;
    ; #CALG_HMAC HMAC, a keyed hash algorithm 
    ; #CALG_MAC Message Authentication Code 
    ; #CALG_MD2 MD2 
    ; #CALG_MD5 MD5 
    ; #CALG_SHA US DSA Secure Hash Algorithm 
    ; #CALG_SHA1 Same as CALG_SHA 
    ; #CALG_SSL3_SHAMD5 SSL3 client authentication 
    ;
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
    If hHash
      CryptHashData_(hHash, password$, Len(password$), 0)
      ;
      ; For a list of valid encryption algorithms, check:
      ;
      ; http://msdn.microsoft.com/library/en-us/seccrypto/security/alg_id.asp
      ; 
      ; The constant values can be found in the Platform SDK include file: WinCrypt.h
      ;
      ; Here we're using RC4
      ;
      CryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey)
      If hKey
        If CryptEncrypt_(hKey, 0, #TRUE, #NULL, *lpData, @DataLength, DataLength)
          result = #TRUE
        Else
          Error("CryptEncrypt_() failed")
        EndIf
        CryptDestroyKey_(hKey)
      Else
        Error("CryptDeriveKey_() failed")
      EndIf
      CryptDestroyHash_(hHash)
    Else
      Error("CryptCreateHash_() failed")
    EndIf
    CryptReleaseContext_(hProv, 0)
  Else
    Error("CryptAcquireContext_() failed")
  EndIf
  ProcedureReturn result
EndProcedure

Procedure Decrypt(*lpData, DataLength, password$)
  If CryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, 0)=0
    CryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
  EndIf
  If hProv
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
    If hHash
      CryptHashData_(hHash, password$, Len(password$), 0)
      CryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey)
      If hKey
        If CryptDecrypt_(hKey, 0, #TRUE, 0, *lpData, @DataLength)
          result = #TRUE
        Else
          Error("CryptDecrypt_() failed")
        EndIf
        CryptDestroyKey_(hKey)
      Else
        Error("CryptDeriveKey_() failed")
      EndIf
      CryptDestroyHash_(hHash)
    Else
      Error("CryptCreateHash_() failed")
    EndIf
    CryptReleaseContext_(hProv, 0)
  Else
    Error("CryptAcquireContext_() failed")
  EndIf
  ProcedureReturn result
EndProcedure

mydata$ = "This a string to test the encryption/decryption code"
pwd$ = "my password"
If Encrypt(@mydata$, Len(mydata$), pwd$)
  Debug "Encrypted data:"
  Debug mydata$
  If Decrypt(@mydata$, Len(mydata$), pwd$)
    Debug ""
    Debug "Decrypted data:"
    Debug mydata$
  EndIf
EndIf
Regards,
El_Choni
newbie
Enthusiast
Enthusiast
Posts: 296
Joined: Tue Jul 29, 2003 5:47 pm
Location: FRANCE
Contact:

Post by newbie »

Very interesting, thx ! :D
- Registered PB user -

Using PB 4.00
holyfieldstudios
New User
New User
Posts: 4
Joined: Wed May 25, 2005 6:57 pm

Cool

Post by holyfieldstudios »

Seems to work
User avatar
Droopy
Enthusiast
Enthusiast
Posts: 658
Joined: Thu Sep 16, 2004 9:50 pm
Location: France
Contact:

Post by Droopy »

very good :wink:
User avatar
HeX0R
Addict
Addict
Posts: 1188
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Post by HeX0R »

I really love this function, but sometimes the results aren't o.k.

Example ?
o.k, try this with your function:

Code: Select all

mydata$ = "aol30ebpm4"
pwd$    = "uhDZOn"
If Encrypt(@mydata$, Len(mydata$), pwd$)
  Debug "Encrypted data:"
  Debug mydata$
  If Decrypt(@mydata$, Len(mydata$), pwd$)
    Debug "IS:" + mydata$ + " <->ShouldBe:aol30ebpm4"
  EndIf
EndIf
You will see, that the original and the decrypted(encrypted) aren't the same!
Problem is, when encryption contains a zero-byte, then the string will be cut! (i had a real long fight now with this thing, cause it happenes not so often...)

Here is my little change... well o.k. i needed a function which returns the String directly, so i changed this... and i removed the error-function for my needs

Code: Select all

Procedure.s Encrypt(string$, key$)
  ;Crypt-Constants
  #PROV_RSA_FULL = 1 
  #ALG_SID_MD5 = 3 
  #ALG_SID_RC4 = 1 
  #ALG_CLASS_DATA_ENCRYPT = 3<<13 
  #ALG_CLASS_HASH = 4<<13 
  #ALG_TYPE_ANY = 0 
  #ALG_TYPE_STREAM = 4<<9 
  #CALG_MD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD5 
  #CALG_RC4 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_STREAM|#ALG_SID_RC4 
  #CRYPT_EXPORTABLE = 1 
  #CRYPT_NEWKEYSET = 8
  ;Uses the RC4 User lib
  Protected *Buffer12
  *Buffer12 = AllocateMemory(1024)
  DataLength.l = Len(string$)
  PokeS(*Buffer12, string$)
  If CryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, 0) = 0 
    CryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
  EndIf 
  If hProv 
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash) 
    If hHash 
      CryptHashData_(hHash, key$, Len(key$), 0) 
      CryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey) 
      If hKey 
        If CryptEncrypt_(hKey, 0, #TRUE, #NULL, *Buffer12, @DataLength, DataLength)
        EndIf 
        CryptDestroyKey_(hKey) 
      EndIf 
      CryptDestroyHash_(hHash) 
    EndIf 
    CryptReleaseContext_(hProv, 0) 
  EndIf
  Result.s = ""
  For i = 0 To DataLength - 1
    Result + RSet(Hex(PeekB(*Buffer12 + i) & $FF), 2, "0")
  Next i
  FreeMemory(*Buffer12)
  ProcedureReturn Result
EndProcedure

Procedure.s Decrypt(string$, key$)
  ;Uses the RC4 User lib
  Protected *Buffer12
  
  *Buffer12 = AllocateMemory(1024)
  
  hexa.s = "0123456789ABCDEF"
  Result.s = ""
  o.l = 0
  For i = 1 To Len(string$) Step 2
    hi.l = FindString(hexa, Mid(UCase(string$), i, 1), 1) - 1
    lo.l = FindString(hexa, Mid(UCase(string$), i + 1, 1), 1) - 1
    PokeB(*Buffer12 + o, (hi * 16) + lo)
    o + 1
  Next i
  DataLength.l = Len(string$) / 2
  
  If CryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, 0)=0 
    CryptAcquireContext_(@hProv, #NULL, #NULL, #PROV_RSA_FULL, #CRYPT_NEWKEYSET) 
  EndIf 
  If hProv 
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
    If hHash 
      CryptHashData_(hHash, key$, Len(key$), 0) 
      CryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey) 
      If hKey 
        If CryptDecrypt_(hKey, 0, #TRUE, 0, *Buffer12, @DataLength) 
          Result = PeekS(*Buffer12)
        EndIf 
        CryptDestroyKey_(hKey) 
      EndIf 
      CryptDestroyHash_(hHash) 
    EndIf 
    CryptReleaseContext_(hProv, 0) 
  EndIf
  FreeMemory(*Buffer12)
  ProcedureReturn Result
EndProcedure

mydata$ = "aol30ebpm4"
pwd$    = "uhDZOn"
mydata$ = Encrypt(mydata$, pwd$)
Debug "Encrypted data:"
Debug mydata$
mydata$ = Decrypt(mydata$, pwd$)
Debug "IS:" + mydata$ + " <->ShouldBe:aol30ebpm4"
MikeB
Enthusiast
Enthusiast
Posts: 183
Joined: Sun Apr 27, 2003 8:39 pm
Location: Cornwall UK

Post by MikeB »

I think that El_Choni and HeXOR have done a great job and I have saved the resulting code for future use. My only question is, how secure is RC4 encryption?

MikeB
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

> how secure is RC4 encryption?

It's supposed to be VERY secure... here's one such quote:

http://www.rsasecurity.com/rsalabs/node.asp?id=2250

I've read about it before and would have no hesitation in using it.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
HeX0R
Addict
Addict
Posts: 1188
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Post by HeX0R »

Sorry, but i have to reanimate this thread cause otherwise someone else will step into the same trap then me:

I recognized, that your generated encrypted strings didn't return the original string, when decrypting on another os.
This could be irritating for users, if you use it to encrypt passes into inis which the users wants to take with them to another pc for example.

So i found the solution:
Use one of M$'s Cryptographic Service Provider as name instead of a default one.
The function will then look like this:

Code: Select all

;Crypt-Constants
#PROV_RSA_FULL = 1 
#ALG_SID_MD5 = 3 
#ALG_SID_RC4 = 1
#ALG_SID_RC5 = 13
#ALG_CLASS_DATA_ENCRYPT = 3<<13 ;$6000
#ALG_CLASS_HASH = 4<<13 ;$8000
#ALG_TYPE_ANY = 0
#ALG_TYPE_STREAM = 4<<9 
#CALG_MD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD5
#ALG_TYPE_BLOCK = 1536
#CRYPT_OAEP = $40
; Valid hashing algorithms: 
; 
; #ALG_SID_HMAC = 9 
; #ALG_SID_MAC = 5 
; #ALG_SID_MD2 = 1 
; #ALG_SID_SHA = 4 
; #ALG_SID_SHA1 = 4 
; #ALG_SID_SSL3SHAMD5 = 8 
; #CALG_HMAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_HMAC 
; #CALG_MAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MAC 
; #CALG_MD2 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD2 
; #CALG_SHA = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA 
; #CALG_SHA1 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA1 
; #CALG_SSL3_SHAMD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SSL3SHAMD5 
#CALG_RC4 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_STREAM|#ALG_SID_RC4
#CALG_RC5 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_RC5
#CRYPT_CREATE_SALT = 4
#CRYPT_EXPORTABLE = 1 
#CRYPT_NEWKEYSET = 8
#MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0"

Procedure.s EnCrypt(String$, Key$)
  Protected *Buffer
  *Buffer = AllocateMemory(1024)
  DataLength.l = Len(String$)
  PokeS(*Buffer, String$)
  If CryptAcquireContext_(@hProv, #NULL, #MS_DEF_PROV, #PROV_RSA_FULL, 0) = 0
    CryptAcquireContext_(@hProv, #NULL, #MS_DEF_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
  EndIf
  If hProv
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
    If hHash
      CryptHashData_(hHash, @Key$, Len(Key$), 0)
      CryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey)
      If hKey
        If CryptEncrypt_(hKey, 0, #TRUE, #NULL, *Buffer, @DataLength, 1024)
        EndIf
        CryptDestroyKey_(hKey)
      EndIf
      CryptDestroyHash_(hHash)
    EndIf
    CryptReleaseContext_(hProv, 0)
  EndIf

  Result.s = ""
  For i = 0 To DataLength - 1
    Result + RSet(Hex(PeekB(*Buffer + i) & $FF), 2, "0")
  Next i
  FreeMemory(*Buffer)
  ProcedureReturn Result
EndProcedure

Procedure.s Decrypt(String$, Key$)
 
  Protected *Buffer
 
  *Buffer = AllocateMemory(1024)
 
  Result.s = ""
  o.l = 0
  For i = 1 To Len(String$) Step 2
    hi.l = Asc(Mid(String$, i, 1)) - 48
    If hi > 9
      hi - 7
    EndIf
    lo.l = Asc(Mid(String$, i + 1, 1)) - 48
    If lo > 9
      lo - 7
    EndIf
    PokeB(*Buffer + o, (hi * 16) + lo)
    o + 1
  Next i
  DataLength.l = Len(String$) / 2
 
  If CryptAcquireContext_(@hProv, #NULL, #MS_DEF_PROV, #PROV_RSA_FULL, 0) = 0
    CryptAcquireContext_(@hProv, #NULL, #MS_DEF_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
  EndIf
  If hProv
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
    If hHash
      CryptHashData_(hHash, @Key$, Len(Key$), 0)
      CryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey)
      If hKey
        If CryptDecrypt_(hKey, 0, #TRUE, 0, *Buffer, @DataLength)
          Result = PeekS(*Buffer)
        EndIf
        CryptDestroyKey_(hKey)
      EndIf
      CryptDestroyHash_(hHash)
    EndIf
    CryptReleaseContext_(hProv, 0)
  EndIf
  FreeMemory(*Buffer)
  ProcedureReturn Result
EndProcedure
Just in case someone really is using this function ;)
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

HeX0R wrote:
-snip

Just in case someone really is using this function ;)
stumbled across this thread while looking for an easy method to encrypt data for output.

seems to be a handy solution - so yes, there is someone using this function.

Thanks for all the effort "perfecting" it.

cheers
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

This turned up bang on note! Excellent, I was just about to search for just such an encryption routine.

Thanks.
I may look like a mule, but I'm not a complete ass.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Uhm, does this algorithm always produce encrypted strings which are twice as long as the original?

That's not so good for my purposes! :(
I may look like a mule, but I'm not a complete ass.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

srod wrote:Uhm, does this algorithm always produce encrypted strings which are twice as long as the original?

That's not so good for my purposes! :(
From my limited testing, yes - it transforms the bytes to an encrypted hex - thus 2 hex codes per byte.

probably a much better technical explanation will be forthcoming :)

cheers
Phoenix
Enthusiast
Enthusiast
Posts: 141
Joined: Sun Sep 04, 2005 2:25 am

Post by Phoenix »

srod wrote:Uhm, does this algorithm always produce encrypted strings which are twice as long as the original?

That's not so good for my purposes! :(
From what I can see it needs to do that because a string encrypted with RC4 can contain the 0-byte, and you can't store those in a string, so it needs to store it as 2-byte hex strings to work around it. It's not a fault of this code but just the way it is. Even Paul's RC4_Lib does it that way too.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Got you. I didn't think of that.

Thanks.
I may look like a mule, but I'm not a complete ass.
User avatar
HeX0R
Addict
Addict
Posts: 1188
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Post by HeX0R »

Here is another possibility Base64encoded :
(output gets smaller)

Code: Select all

;Crypt-Constants
#PROV_RSA_FULL = 1
#ALG_SID_MD5 = 3
#ALG_SID_RC4 = 1
#ALG_SID_RC5 = 13
#ALG_CLASS_DATA_ENCRYPT = 3<<13 ;$6000
#ALG_CLASS_HASH = 4<<13 ;$8000
#ALG_TYPE_ANY = 0
#ALG_TYPE_STREAM = 4<<9
#CALG_MD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD5
#ALG_TYPE_BLOCK = 1536
#CRYPT_OAEP = $40
; Valid hashing algorithms:
;
; #ALG_SID_HMAC = 9
; #ALG_SID_MAC = 5
; #ALG_SID_MD2 = 1
; #ALG_SID_SHA = 4
; #ALG_SID_SHA1 = 4
; #ALG_SID_SSL3SHAMD5 = 8
; #CALG_HMAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_HMAC
; #CALG_MAC = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MAC
; #CALG_MD2 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_MD2
; #CALG_SHA = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA
; #CALG_SHA1 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SHA1
; #CALG_SSL3_SHAMD5 = #ALG_CLASS_HASH|#ALG_TYPE_ANY|#ALG_SID_SSL3SHAMD5
#CALG_RC4 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_STREAM|#ALG_SID_RC4
#CALG_RC5 = #ALG_CLASS_DATA_ENCRYPT|#ALG_TYPE_BLOCK|#ALG_SID_RC5
#CRYPT_CREATE_SALT = 4
#CRYPT_EXPORTABLE = 1
#CRYPT_NEWKEYSET = 8
#MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0"

Procedure.s EnCrypt(String$, Key$)
  Protected *Buffer
  *Buffer = AllocateMemory(Len(String$) * 2 + 64)
  DataLength.l = Len(String$)
  PokeS(*Buffer, String$)
  If CryptAcquireContext_(@hProv, #Null, #MS_DEF_PROV, #PROV_RSA_FULL, 0) = 0
    CryptAcquireContext_(@hProv, #Null, #MS_DEF_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
  EndIf
  If hProv
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
    If hHash
      CryptHashData_(hHash, @Key$, Len(Key$), 0)
      CryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey)
      If hKey
        If CryptEncrypt_(hKey, 0, #True, #Null, *Buffer, @DataLength, Len(String$) * 2 + 64)
        EndIf
        CryptDestroyKey_(hKey)
      EndIf
      CryptDestroyHash_(hHash)
    EndIf
    CryptReleaseContext_(hProv, 0)
  EndIf
	
	Result.s = Space(DataLength * 2)
  Base64Encoder(*Buffer, DataLength, @Result, DataLength * 2)
  FreeMemory(*Buffer)
  ProcedureReturn Result
EndProcedure

Procedure.s Decrypt(String$, Key$)
 
  Protected *Buffer
 
  *Buffer = AllocateMemory(Len(String$) * 2 + 64)
 	DataLength.l = Base64Decoder(@String$, Len(String$), *Buffer, Len(String$) * 2 + 64)
  
  If CryptAcquireContext_(@hProv, #Null, #MS_DEF_PROV, #PROV_RSA_FULL, 0) = 0
    CryptAcquireContext_(@hProv, #Null, #MS_DEF_PROV, #PROV_RSA_FULL, #CRYPT_NEWKEYSET)
  EndIf
  If hProv
    CryptCreateHash_(hProv, #CALG_MD5, 0, 0, @hHash)
    If hHash
      CryptHashData_(hHash, @Key$, Len(Key$), 0)
      CryptDeriveKey_(hProv, #CALG_RC4, hHash, #CRYPT_EXPORTABLE, @hKey)
      If hKey
        If CryptDecrypt_(hKey, 0, #True, 0, *Buffer, @DataLength)
          Result.s = PeekS(*Buffer)
        EndIf
        CryptDestroyKey_(hKey)
      EndIf
      CryptDestroyHash_(hHash)
    EndIf
    CryptReleaseContext_(hProv, 0)
  EndIf
  FreeMemory(*Buffer)
  ProcedureReturn Result
EndProcedure

test$ = "Now we will check if this all works as expected..."
Debug Len(test$)
a$ = EnCrypt(test$, "081652")
Debug a$
Debug Len(a$)
Debug DeCrypt(a$, "081652")
Post Reply