Sign in to follow this  
Followers 0
PsaltyDS

Alternative to _StringEncrypt()

8 posts in this topic

#1 ·  Posted (edited)

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



#3 ·  Posted (edited)

@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

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

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

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

#8 ·  Posted (edited)

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  
Followers 0