Jump to content
Sign in to follow this  
PsaltyDS

Alternative to _StringEncrypt()

Recommended Posts

PsaltyDS

This function came out of my trying to understand a supposed problem with _StringEncrypt(). Only one user reported that problem, and it was never duplicated by anyone else, so it very well may not be a bug, and this is not an attempt to "fix" _StringEncrypt().

The only thing I wanted to achieve was a version of _StringEncrypt() that would output a "standard" result for RC4 encryption, that would match RC4 implementations on web sites and in other languages. The encryption side of that was completely solved by SkinnyWhiteGuy in the topic: equal encrypt function autoit and php

What I did here was match the string-based nature of _StringEncrypt(), vice the binary nature of RC4(), with the multi-pass encryption functionality provided by the $i_EncryptLevel parameter. The result is __StringEncrypt(), with the double-underbar in the name.

Here is the function, within a basic test script:

$sString = "This is a text string"
ConsoleWrite("Debug: $sString = " & $sString & @LF)
$sKey = "Key phrase"
ConsoleWrite("Debug: $sKey = " & $sKey & @LF)
For $z = 1 To 4
    ConsoleWrite("Debug: Encryption level = " & $z & @LF)
    $sEncrypted = __StringEncrypt(1, $sString, $sKey, $z)
    ConsoleWrite("Debug: $sEncrypted = " & $sEncrypted & @LF)
    $sDecrypted = __StringEncrypt(0, $sEncrypted, $sKey, $z)
    ConsoleWrite("Debug: $sDecrypted = " & $sDecrypted & @LF)
Next

;===============================================================================
;
; Function Name:    __StringEncrypt()
; Description:      RC4 Based string encryption/decryption
; Parameter(s):     $i_Encrypt - 1 to encrypt, 0 to decrypt
;                   $s_EncryptText - string to encrypt
;                   $s_EncryptPassword - string to use as an encryption password
;                   $i_EncryptLevel - integer to use as number of times to encrypt string
; Requirement(s):   None
; Return Value(s):  On Success - Returns the encrypted string
;                   On Failure - Returns a blank string and sets @error = 1
; Author(s):        (Original _StringEncrypt) Wes Wolfe-Wolvereness <Weswolf at aol dot com> 
;                   (Modified __StringEncrypt) PsaltyDS at www.autoitscript.com/forum
;                   (RC4 function) SkinnyWhiteGuy at www.autoitscript.com/forum
;===============================================================================
;  1.0.0.0  |  03/08/08  |  First version posted to Example Scripts Forum
;===============================================================================
Func __StringEncrypt($i_Encrypt, $s_EncryptText, $s_EncryptPassword, $i_EncryptLevel = 1)
    Local $RET, $sRET = "", $iBinLen, $iHexWords
   
    ; Sanity check of parameters
    If $i_Encrypt <> 0 And $i_Encrypt <> 1 Then
        SetError(1)
        Return ''
    ElseIf $s_EncryptText = '' Or $s_EncryptPassword = '' Then
        SetError(1)
        Return ''
    EndIf
    If Number($i_EncryptLevel) <= 0 Or Int($i_EncryptLevel) <> $i_EncryptLevel Then $i_EncryptLevel = 1
   
    ; Encrypt/Decrypt
    If $i_Encrypt Then
        ; Encrypt selected
        $RET = $s_EncryptText
        For $n = 1 To $i_EncryptLevel
            If $n > 1 Then $RET = Binary(Random(0, 2 ^ 31 - 1, 1)) & $RET & Binary(Random(0, 2 ^ 31 - 1, 1)) ; prepend/append random 32bits
            $RET = rc4($s_EncryptPassword, $RET) ; returns binary
        Next
       
        ; Convert to hex string
        $iBinLen = BinaryLen($RET)
        $iHexWords = Int($iBinLen / 4)
        If Mod($iBinLen, 4) Then $iHexWords += 1
        For $n = 1 To $iHexWords
            $sRET &= Hex(BinaryMid($RET, 1 + (4 * ($n - 1)), 4))
        Next
        $RET = $sRET
    Else
        ; Decrypt selected
        ; Convert input string to primary binary
        $RET = Binary("0x" & $s_EncryptText) ; Convert string to binary
       
        ; Additional passes, if required
        For $n = 1 To $i_EncryptLevel
            If $n > 1 Then
                $iBinLen = BinaryLen($RET)
                $RET = BinaryMid($RET, 5, $iBinLen - 8) ; strip random 32bits from both ends
            EndIf
            $RET = rc4($s_EncryptPassword, $RET)
        Next
        $RET = BinaryToString($RET)
    EndIf
   
    ; Return result
    Return $RET
EndFunc   ;==>__StringEncrypt

; -------------------------------------------------------
; Function:  rc4
; Purpose:  An encryption/decryption RC4 implementation in AutoIt
; Syntax:  rc4($key, $value)
;   Where:  $key = encrypt/decrypt key
;       $value = value to be encrypted/decrypted
; On success returns encrypted/decrypted version of $value
; Author:  SkinnyWhiteGuy on the AutoIt forums at www.autoitscript.com/forum
; Notes:  The same function encrypts and decrypts $value.
; -------------------------------------------------------
Func rc4($key, $value)
    Local $S[256], $i, $j, $c, $t, $x, $y, $output
    Local $keyLength = BinaryLen($key), $valLength = BinaryLen($value)
    For $i = 0 To 255
        $S[$i] = $i
    Next
    For $i = 0 To 255
        $j = Mod($j + $S[$i] + Dec(StringTrimLeft(BinaryMid($key, Mod($i, $keyLength) + 1, 1), 2)), 256)
        $t = $S[$i]
        $S[$i] = $S[$j]
        $S[$j] = $t
    Next
    For $i = 1 To $valLength
        $x = Mod($x + 1, 256)
        $y = Mod($S[$x] + $y, 256)
        $t = $S[$x]
        $S[$x] = $S[$y]
        $S[$y] = $t
        $j = Mod($S[$x] + $S[$y], 256)
        $c = BitXOR(Dec(StringTrimLeft(BinaryMid($value, $i, 1), 2)), $S[$j])
        $output = Binary($output) & Binary('0x' & Hex($c, 2))
    Next
    Return $output
EndFunc   ;==>rc4

These are the results of two consecutive runs in SciTE:

>Running:(3.2.10.0):C:\Program Files\AutoIt3\autoit3.exe "C:\Program Files\AutoIt3\Scripts\Test_1.au3"  
Debug: $sString = This is a text string
Debug: $sKey = Key phrase
Debug: Encryption level = 1
Debug: $sEncrypted = 13BFA0643B2D2B75A2FA41A98B0B363748DB0EC8C5
Debug: $sDecrypted = This is a text string
Debug: Encryption level = 2
Debug: $sEncrypted = FC92DD7408FBF831F8F71EB9518557EDB7A25191EAB226AEB9CF3776E3
Debug: $sDecrypted = This is a text string
Debug: Encryption level = 3
Debug: $sEncrypted = 553996021B3DCE57CB21CDFD0B8808FD6D2C304B15CB79F796C76BA4680B031A03B2175035
Debug: $sDecrypted = This is a text string
Debug: Encryption level = 4
Debug: $sEncrypted = BCB5DD4D8F19ED1D98BF8285385EDBB937216F5BCF45182D69BE34FD472FE0D6CE404C747C269F35C8F27D790C
Debug: $sDecrypted = This is a text string
+>13:06:59 AutoIT3.exe ended.rc:0

>Running:(3.2.10.0):C:\Program Files\AutoIt3\autoit3.exe "C:\Program Files\AutoIt3\Scripts\Test_1.au3"  
Debug: $sString = This is a text string
Debug: $sKey = Key phrase
Debug: Encryption level = 1
Debug: $sEncrypted = 13BFA0643B2D2B75A2FA41A98B0B363748DB0EC8C5
Debug: $sDecrypted = This is a text string
Debug: Encryption level = 2
Debug: $sEncrypted = 3F83796908FBF831F8F71EB9518557EDB7A25191EAB226AEB9261552D2
Debug: $sDecrypted = This is a text string
Debug: Encryption level = 3
Debug: $sEncrypted = 4FEEF71FB98E811CCB21CDFD0B8808FD6D2C304B15CB79F796C76BA468D39E1676FC9FAA1A
Debug: $sDecrypted = This is a text string
Debug: Encryption level = 4
Debug: $sEncrypted = 600821594D0853343717D6DA385EDBB937216F5BCF45182D69BE34FD472FE0D6CE1CC2B3258B0833861A82BA52
Debug: $sDecrypted = This is a text string
+>13:08:34 AutoIT3.exe ended.rc:0

Note that the encrypted string is the same between the two runs where $i_EncryptLevel = 1, but is different where $i_EncryptLevel > 1. It is useful in some contexts to get different results that can still be decrypted with same key to the same value.

As long as $i_EncryptLevel = 1, this function should be directly compatible with string-based RC4 implementations elsewhere (on web sites or in applications). For example, you'll get the same result if you put the string "This is a text string" and the key "Key phrase" into this web site: http://www.4guysfromrolla.com/

:)

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites
ptrex
PsaltyDS

@PsaltyDS

Very nice !!

regards

ptrex

Thanks. ;)

I'd really love to know if anyone has tested it against other RC4 implementations, like PHP or Java on a web site other than my example. Compatibility with other implementations was the original purpose.

:)

P.S. Tested against one more site (data has to be entered in URL): www.colcyber.com/macro

Result is:

Original Data : This is a text string
Encrypted Data (using Hex Key) : cb628ff60e96ae5f0409598d67e2c1f72a3f24aeac
Decrypted Data (using Hex Key) : This is a text string

Encrypted Data (using Key as is) : 13bfa0643b2d2b75a2fa41a98b0b363748db0ec8c5
Decrypted Data (using Key as is) : This is a text string

I guess "using Hex Key" means the key was converted somehow, making the result different. With "using Key as is" the result matches my function (with $iEncryptLevel = 1).

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites
kurey

this funtion may have something wrong when run with the unicode version.

i use the __StringEncrypt funtion to Encrypt some NON ascii characterS like :

服务器  <------Chinese (means "server")

わたし <------Japanese(means "I")

and run with the unicode version(3.2.10.0) on Windos xp Simplified Chinese verion ,and the result is :

Posted Image

Encrypt:

Posted Image

dcrypt :

Posted Image

#include <guiconstants.au3>
;#include <string.au3>
; GUI and String stuff
$WinMain = GuiCreate('Encryption tool', 400, 400)
; Creates window
$EditText = GuiCtrlCreateEdit('',5,5,380,350)
; Creates main edit
$InputPass = GuiCtrlCreateInput('',5,360,100,20, 0x21)
; Creates the password box with blured/centered input
$InputLevel = GuiCtrlCreateInput(1, 110, 360, 50, 20, 0x2001)
$UpDownLevel = GUICtrlSetLimit(GuiCtrlCreateUpDown($inputlevel),10,1)
; These two make the level input with the Up|Down ability
$EncryptButton = GuiCtrlCreateButton('Encrypt', 170, 360, 105, 35)
; Encryption button
$DecryptButton = GuiCtrlCreateButton('Decrypt', 285, 360, 105, 35)
; Decryption button
GUICtrlCreateLabel('Password', 5, 385)
GuiCtrlCreateLabel('Level',110,385)
; Simple text labels so you know what is what
GuiSetState()
; Shows window

Do
   $Msg = GuiGetMsg()
   If $msg = $EncryptButton Then
      GuiSetState(@SW_DISABLE,$WinMain); Stops you from changing anything
      $string = GuiCtrlRead($EditText); Saves the editbox for later
      GUICtrlSetData($EditText,'Please wait while the text is Encrypted/Decrypted.'); Friendly message
      GuiCtrlSetData($EditText,__StringEncrypt(1,$string,GuiCtrlRead($InputPass),GuiCtrlRead($InputLevel)))
     ; Calls the encryption. Sets the data of editbox with the encrypted string
     ; The encryption starts with 1/0 to tell it to encrypt/decrypt
     ; The encryption then has the string that we saved for later from edit box
     ; It then reads the password box & Reads the level box
      GuiSetState(@SW_ENABLE,$WinMain); This turns the window back on
   EndIf
   If $msg = $DecryptButton Then
      GuiSetState(@SW_DISABLE,$WinMain); Stops you from changing anything
      $string = GuiCtrlRead($EditText); Saves the editbox for later
      GUICtrlSetData($EditText,'Please wait while the text is Encrypted/Decrypted.'); Friendly message
      GuiCtrlSetData($EditText,__StringEncrypt(0,$string,GuiCtrlRead($InputPass),GuiCtrlRead($InputLevel)))
     ; Calls the encryption. Sets the data of editbox with the encrypted string
     ; The encryption starts with 1/0 to tell it to encrypt/decrypt
     ; The encryption then has the string that we saved for later from edit box
     ; It then reads the password box & Reads the level box
      GuiSetState(@SW_ENABLE,$WinMain); This turns the window back on
   EndIf
Until $msg = $GUI_EVENT_CLOSE; Continue loop untill window is closed





;===============================================================================
;
; Function Name:    ___StringEncrypt()
; Description:    RC4 Based string encryption/decryption
; Parameter(s):  $i_Encrypt - 1 to encrypt, 0 to decrypt
;                  $s_EncryptText - string to encrypt
;                  $s_EncryptPassword - string to use as an encryption password
;                  $i_EncryptLevel - integer to use as number of times to encrypt string
; Requirement(s):   None
; Return Value(s):  On Success - Returns the string encrypted (blank) times with (blank) password
;                  On Failure - Returns a blank string and sets @error = 1
; Author(s):        (Original __StringEncrypt) Wes Wolfe-Wolvereness <Weswolf at aol dot com> 
;                  (Modified ___StringEncrypt) PsaltyDS at www.autoitscript.com/forum
;                  (RC4 function) SkinnyWhiteGuy at www.autoitscript.com/forum
;===============================================================================
;  1.0.0.0  |  03/08/08  |  First version posted to Example Scripts Forum
;===============================================================================
Func __StringEncrypt($i_Encrypt, $s_EncryptText, $s_EncryptPassword, $i_EncryptLevel = 1)
    Local $RET, $sRET = "", $iBinLen, $iHexWords
   
   ; Sanity check of parameters
    If $i_Encrypt <> 0 And $i_Encrypt <> 1 Then
        SetError(1)
        Return ''
    ElseIf $s_EncryptText = '' Or $s_EncryptPassword = '' Then
        SetError(1)
        Return ''
    EndIf
    If Number($i_EncryptLevel) <= 0 Or Int($i_EncryptLevel) <> $i_EncryptLevel Then $i_EncryptLevel = 1
   
   ; Encrypt/Decrypt
    If $i_Encrypt Then
       ; Encrypt selected
        $RET = $s_EncryptText
        For $n = 1 To $i_EncryptLevel
            If $n > 1 Then $RET = Binary(Random(0, 2 ^ 31 - 1, 1)) & $RET & Binary(Random(0, 2 ^ 31 - 1, 1)); prepend/append random 32bits
            $RET = rc4($s_EncryptPassword, $RET); returns binary
        Next
       
       ; Convert to hex string
        $iBinLen = BinaryLen($RET)
        $iHexWords = Int($iBinLen / 4)
        If Mod($iBinLen, 4) Then $iHexWords += 1
        For $n = 1 To $iHexWords
            $sRET &= Hex(BinaryMid($RET, 1 + (4 * ($n - 1)), 4))
        Next
        $RET = $sRET
    Else
       ; Decrypt selected
       ; Convert input string to primary binary
        $RET = Binary("0x" & $s_EncryptText); Convert string to binary
       
       ; Additional passes, if required
        For $n = 1 To $i_EncryptLevel
            If $n > 1 Then
                $iBinLen = BinaryLen($RET)
                $RET = BinaryMid($RET, 5, $iBinLen - 8); strip random 32bits from both ends
            EndIf
            $RET = rc4($s_EncryptPassword, $RET)
        Next
        $RET = BinaryToString($RET)
    EndIf
   
   ; Return result
    Return $RET
EndFunc  ;==>___StringEncrypt

; -------------------------------------------------------
; Function:  rc4
; Purpose:  An encryption/decryption RC4 implementation in AutoIt
; Syntax:  rc4($key, $value)
;   Where:  $key = encrypt/decrypt key
;      $value = value to be encrypted/decrypted
; On success returns encrypted/decrypted version of $value
; Author:  SkinnyWhiteGuy on the AutoIt forums at www.autoitscript.com/forum
; Notes:  The same function encrypts and decrypts $value.
; -------------------------------------------------------
Func rc4($key, $value)
    Local $S[256], $i, $j, $c, $t, $x, $y, $output
    Local $keyLength = BinaryLen($key), $valLength = BinaryLen($value)
    For $i = 0 To 255
        $S[$i] = $i
    Next
    For $i = 0 To 255
        $j = Mod($j + $S[$i] + Dec(StringTrimLeft(BinaryMid($key, Mod($i, $keyLength) + 1, 1), 2)), 256)
        $t = $S[$i]
        $S[$i] = $S[$j]
        $S[$j] = $t
    Next
    For $i = 1 To $valLength
        $x = Mod($x + 1, 256)
        $y = Mod($S[$x] + $y, 256)
        $t = $S[$x]
        $S[$x] = $S[$y]
        $S[$y] = $t
        $j = Mod($S[$x] + $S[$y], 256)
        $c = BitXOR(Dec(StringTrimLeft(BinaryMid($value, $i, 1), 2)), $S[$j])
        $output = Binary($output) & Binary('0x' & Hex($c, 2))
    Next
    Return $output
EndFunc  ;==>rc4

Share this post


Link to post
Share on other sites
Andreik

Nice work PsaltyDS! I like RC4 algorithm. It's very easy to use. :)


When the words fail... music speaks

Share this post


Link to post
Share on other sites
PsaltyDS

this funtion may have something wrong when run with the unicode version.

i use the __StringEncrypt funtion to Encrypt some NON ascii characterS like :

服务器  <------Chinese (means "server")

わたし <------Japanese(means "I")

and run with the unicode version(3.2.10.0) on Windos xp Simplified Chinese verion ,and the result is :

Posted Image

Encrypt:

Posted Image

dcrypt :

Posted Image

Hmm... seems the problem is that BinaryToString() requires the coder to identify what the source encoding. The last thing __StringEncrypt() does when decrypting is BinaryToString(). Try modifying your copy with the appropriate flag to see if that gets it:
Func __StringEncrypt($i_Encrypt, $s_EncryptText, $s_EncryptPassword, $i_EncryptLevel = 1)
    Local $RET, $sRET = "", $iBinLen, $iHexWords
   
   ; ...clip

        $RET = BinaryToString($RET, 1); <============= Change encoding type here
    EndIf
   
   ; Return result
    Return $RET
EndFunc  ;==>__StringEncrypt

From the help file:

Parameters

expression = An expression to convert into a string.

flag [optional] = Changes how the binary data is converted:

flag = 1 (default), binary data is taken to be ANSI

flag = 2, binary data is taken to be UTF16 Little Endian

flag = 3, binary data is taken to be UTF16 Big Endian

flag = 4, binary data is taken to be UTF8

UTF16 Little Endian = 2 seems most likely.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites
Ting

Hmm... seems the problem is that BinaryToString() requires the coder to identify what the source encoding. The last thing __StringEncrypt() does when decrypting is BinaryToString(). Try modifying your copy with the appropriate flag to see if that gets it:

Func __StringEncrypt($i_Encrypt, $s_EncryptText, $s_EncryptPassword, $i_EncryptLevel = 1)
    Local $RET, $sRET = "", $iBinLen, $iHexWords
   
 ; ...clip

        $RET = BinaryToString($RET, 1); <============= Change encoding type here
    EndIf
   
 ; Return result
    Return $RET
EndFunc;==>__StringEncrypt

From the help file:

UTF16 Little Endian = 2 seems most likely.

:)

Tried all flags. None of them works for Asian characters on my PC.

Should the stringtobinary function be called somewhere also in the script with the correct encoding?

>>>>

Ha, my guess was correct. We need the stringtobinary function. The encryption/decryption of unicode characters (e.g. Asian lang. ) is perfectly solved and tested here: http://www.autoitscript.com/forum/index.ph...mp;#entry545002

Edited by Ting

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×