AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

RC4 encryption to hex stream
Goto page 1, 2  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Fri Dec 09, 2005 12:11 am    Post subject: RC4 encryption to hex stream Reply with quote

There are problems with RC4 in binary mode, as Rajat posted: the encrypted text can contain non-printable characters. If you write it in a file and read back, different characters could map to the same one, others just get lost. An occasional NUL character is treated as a string terminator. You have to convert the ciphertext, for example, to a stream of hex digits and convert it back to binary before decryption. Still there are difficulties, like the length of a binary buffer has to be kept in a separate variable. To make life easier, here are a couple of variants of Rajat's RC4 script. RC4txt2hex takes a text string, encrypts it with a pass phrase and returns the result as a stream of hex digits. RC4hex2txt does the opposite, allowing the decryption of a hex stream created beforehand. The hex string can be freely manipulated with the standard functions of AHK or written to a text file or edit with any text editor, there are no problems with special characters.

Of course you can use TEA, the Tiny Encryption Algorithm, instead: this, or that. It is considered more secure, but for personal use there should be no security concerns with either of them.
Code:
Process Priority,,High                 ; Run faster
SetBatchLines -1

RC4Pass = Version 1.0.40.09`nwww.autohotkey.com`nŠ2003-2005 Chris Mallett, portions ŠAutoIt Team

RC4Data = AutoHotkey unleashes the full potential of your keyboard, joystick, and mouse. For example, in addition to the typical Control, Alt, and Shift modifiers, you can use the Windows key and the Capslock key as modifiers.

RC4Enc := RC4txt2hex(RC4Data,RC4Pass)
RC4Dec := RC4hex2txt(RC4Enc,RC4Pass)
MsgBox %RC4Data%`n`nEncrypted with pass:`n`n%RC4Pass%`n`nto`n`n%RC4Enc%`n`nDecypted to`n`n%RC4Dec%

ExitApp

RC4txt2hex(Data,Pass)
{
   Format = %A_FormatInteger%
   SetFormat Integer, Hex
   Loop 256
   {
      a := A_Index - 1
      StringMid C, Pass, Mod(a,StrLen(Pass))+1, 1
      Key%a% := Asc(C)
      sBox%a% = %a%
   }
   b = 0
   Loop 256
   {
      a := A_Index - 1
      b := b + sBox%a% + Key%a%  & 255
      T := sBox%a%
      sBox%a% := sBox%b%
      sBox%b% = %T%
   }
   i = 0
   j = 0
   Loop Parse, Data
   {
      i := i + 1  & 255
      j := sBox%i% + j  & 255
      k := sBox%i% + sBox%j%  & 255
      C := (Asc(A_LoopField) ^ sBox%k%)+ 0x100
      IfEqual C,0, SetEnv C, % sBox%k% + 0x100
      StringRight C, C, 2
      Result := Result C
   }
   SetFormat Integer, %Format%
   Return Result
}

RC4hex2txt(Data,Pass)
{
   ATrim = %A_AutoTrim%
   AutoTrim Off
   Loop 256
   {
      a := A_Index - 1
      StringMid C, Pass, Mod(a,StrLen(Pass))+1, 1
      Key%a% := Asc(C)
      sBox%a% = %a%
   }
   b = 0
   Loop 256
   {
      a := A_Index - 1
      b := b + sBox%a% + Key%a%  & 255
      T := sBox%a%
      sBox%a% := sBox%b%
      sBox%b% = %T%
   }
   i = 0
   j = 0
   Loop Parse, Data
   {
      If (A_Index & 1)
         C = 0x%A_LoopField%
      Else {
         i := i + 1  & 255
         j := sBox%i% + j  & 255
         k := sBox%i% + sBox%j%  & 255
         C := (C A_LoopField) ^ sBox%k%
         IfEqual C,0, SetEnv C, % sBox%k%
         Result := Result Chr(C)
      }
   }
   AutoTrim %ATrim%
   Return Result
}


With the changes in AutoHotKey Version 1.0.46.00, some speedup and simplifications are possible:
Code:
; Needs AutoHotKey Version 1.0.46.00 or later

#SingleInstance Force
#NoEnv
SetBatchLines -1
Process Priority,,High                 ; Run faster

RC4Pass = Version 1.0.40.09`nwww.autohotkey.com`nŠ2003-2005 Chris Mallett, portions ŠAutoIt Team

RC4Data = AutoHotkey unleashes the full potential of your keyboard, joystick, and mouse. For example, in addition to the typical Control, Alt, and Shift modifiers, you can use the Windows key and the Capslock key as modifiers.

RC4Enc := RC4txt2hex(RC4Data "`n" RC4Data "`n" RC4Data "`n" RC4Data "`n" RC4Data,RC4Pass)
RC4Dec := RC4hex2txt(RC4Enc,RC4Pass)
MsgBox %RC4Data%`n`nEncrypted 5-times with pass:`n`n%RC4Pass%`n`nto`n`n%RC4Enc%`n`nDecypted to`n`n%RC4Dec%

ExitApp

RC4txt2hex(Data,Pass) {
   Format := A_FormatInteger
   SetFormat Integer, Hex
   b := 0, j := 0
   VarSetCapacity(Result,StrLen(Data)*2)
   Loop 256 {
      a := A_Index - 1
      Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
      sBox%a% := a
   }
   Loop 256 {
      a := A_Index - 1
      b := b + sBox%a% + Key%a%  & 255
      T := sBox%a%
      sBox%a% := sBox%b%
      sBox%b% := T
   }
   Loop Parse, Data
   {
      i := A_Index & 255
      j := sBox%i% + j  & 255
      k := sBox%i% + sBox%j%  & 255
      Result .= SubStr(Asc(A_LoopField)^sBox%k%, -1, 2)
   }
   StringReplace Result, Result, x, 0, All
   SetFormat Integer, %Format%
   Return Result
}

RC4hex2txt(Data,Pass) {
   b := 0, j := 0, x := "0x"
   VarSetCapacity(Result,StrLen(Data)//2)
   Loop 256 {
      a := A_Index - 1
      Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
      sBox%a% := a
   }
   Loop 256 {
      a := A_Index - 1
      b := b + sBox%a% + Key%a%  & 255
      T := sBox%a%
      sBox%a% := sBox%b%
      sBox%b% := T
   }
   Loop % StrLen(Data)//2 {
      i := A_Index  & 255
      j := sBox%i% + j  & 255
      k := sBox%i% + sBox%j%  & 255
      Result .= Chr((x . SubStr(Data,2*A_Index-1,2)) ^ sBox%k%)
   }
   Return Result
}

This version of the RC4txt2hex function is slightly faster, but uses twice as much memory. Normally, it should not be a problem.
Code:
RC4txt2hex(Data,Pass) {
   Format := A_FormatInteger
   SetFormat Integer, Hex
   b := 0, j := 0
   VarSetCapacity(Result,StrLen(Data)*4)
   Loop 256 {
      a := A_Index - 1
      Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
      sBox%a% := a
   }
   Loop 256 {
      a := A_Index - 1
      b := b + sBox%a% + Key%a%  & 255
      T := sBox%a%
      sBox%a% := sBox%b%
      sBox%b% := T
   }
   Loop Parse, Data
   {
      i := A_Index & 255
      j := sBox%i% + j  & 255
      k := sBox%i% + sBox%j%  & 255
      Result .= Asc(A_LoopField)^sBox%k%
   }
   Result := RegExReplace(Result, "0x(.)(?=0x|$)", "0$1")
   StringReplace Result, Result, 0x,,All
   SetFormat Integer, %Format%
   Return Result
}

Edit: 20061219 - New version for AutoHotKey Version 1.0.46.00
Edit: 20061220 - AutoTrim handling is not needed in the new AHK versions, removed (thanks PhiLho)
Edit: 20061221 - Removed dummy Abs()


Last edited by Laszlo on Thu Dec 21, 2006 8:28 pm; edited 4 times in total
Back to top
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 5890

PostPosted: Fri Jul 14, 2006 8:47 am    Post subject: Reply with quote

Dear Laszlo, Smile

I wanted to store my Username+Password for my multiple GMail accounts as a single encrypted file.
I tried your RC4 functions, and

It is working great!!!

Thank you very much. Smile

Regards, Smile
_________________
SKAN - Suresh Kumar A N
Back to top
View user's profile Send private message
Atomhrt



Joined: 02 Sep 2004
Posts: 128
Location: Sunnyvale

PostPosted: Fri Jul 14, 2006 4:48 pm    Post subject: Reply with quote

This is nice, thanks! A thought...

It would be nice to hide the length of the input string by generating a output hex string that is actually longer than the input string. One way to do this is have a byte in the output string that contains the actual size of the input sting in the output string.
_________________
I am he of whom he speaks!
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Fri Jul 14, 2006 5:10 pm    Post subject: Reply with quote

Do you mean, that the public length of the password leaks? It is true, but it is not a concern with good enough passwords. You should never use shorter than 8 characters, with shifts, symbols, etc. There are 95^8 = ~6.6/10^15 candidates to try for a blind key search. If the attacker does not know the length, he has to try all the shorter passwords, too, 1+95+95^2...+95^8 = ~6.7*10^15 possibilities, practically the same.

Of course, if the password is chosen poorly, a dictionary attack might succeed, regardless of the encryption method.
Back to top
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 5890

PostPosted: Tue Dec 19, 2006 2:51 pm    Post subject: Reply with quote

Dear Laszlo, Smile

I have been using the code without even taking a look at it ( all these days. )
Someday, I would like to study this code and so, would like the title post to be intact...

However, with SubStr() & Comma Seperated Values (and maybe RegEx), can this code be shortened and increased in performance ?

Regards, Smile
_________________
SKAN - Suresh Kumar A N
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Tue Dec 19, 2006 9:35 pm    Post subject: Reply with quote

Goyyah wrote:
with SubStr() & Comma Seperated Values (and maybe RegEx), can this code be shortened and increased in performance ?
I added a new version in the first post. It is shorter and should be somewhat faster. I did not put long assignments into one line, to maintain legibility, but you could.
Back to top
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 5890

PostPosted: Wed Dec 20, 2006 6:49 am    Post subject: Reply with quote

Laszlo wrote:
I added a new version in the first post. It is shorter and should be somewhat faster.


Thank you very much, Sir. Very Happy

Laszlo wrote:
I did not put long assignments into one line, to maintain legibility, but you could.


The algorithm is already hard for me to grasp. Once understood, the number of lines is what I would try to reduce.
I will have to study and compare both the versions side by side.

These pair of functions are among the finest available in the forum...

Thanks again and Regards, Smile
_________________
SKAN - Suresh Kumar A N
Back to top
View user's profile Send private message
PhiLho



Joined: 27 Dec 2005
Posts: 6721
Location: France (near Paris)

PostPosted: Wed Dec 20, 2006 4:42 pm    Post subject: Re: RC4 encryption to hex stream Reply with quote

Laszlo wrote:
With the changes in AutoHotKey Version 1.0.46.00, some speedup and simplifications are possible:
Impressive. I played a bit with the code, never able to make it faster... Wink
It shows:
1) Your code is highly optimized. Nothing new here...
2) Chris' code is well optimized too, SubStr is fast!

Two minor remarks:
- I always found strange that & has a lower priority than + (even the C language makers stated it was a design error), so I tend to write: b := (b + sBox%a% + Key%a%) & 255
Of course, you code (and style) is valid.
- In RC4hex2txt, you don't have to play with AutoTrim, since you only use expression concatenation.
_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")
Back to top
View user's profile Send private message Visit poster's website
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Wed Dec 20, 2006 5:02 pm    Post subject: Re: RC4 encryption to hex stream Reply with quote

PhiLho wrote:
you don't have to play with AutoTrim, since you only use expression concatenation.
Thanks, I removed it. It just remained there from earlier versions, when it was necessary.
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Wed Dec 20, 2006 5:38 pm    Post subject: Re: RC4 encryption to hex stream Reply with quote

PhiLho wrote:
code is highly optimized
There are still some speedups possible. For example, when we compute k, the sum sBox%i% + sBox%j% cannot be larger than 510 (255+255), so if we duplicate the sBox array, this larger index still finds the right entry. This way we can remove the mask operation (& 255). It means a couple of percents acceleration for longer texts. (At short texts it is offset by the need for copying 255 array elements. I did not copy this to the first post, because in typical applications it does not brings you much.)
Code:
RC4txt2hex(Data,Pass) {
   Format := A_FormatInteger
   SetFormat Integer, Hex
   b := 0, j := 0
   VarSetCapacity(Result,StrLen(Data)*2)
   Loop 256 {
      a := A_Index - 1
      Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
      sBox%a% := a
   }
   Loop 256 {
      a := A_Index - 1
      b := b + sBox%a% + Key%a%  & 255
      T := sBox%a%
      sBox%a% := sBox%b%
      sBox%b% := T
   }
   Loop 255 {
      i := A_Index - 1
      k := i + 256
      sBox%k% := sBox%i%
   }
   Loop Parse, Data
   {
      i := A_Index & 255
      j := sBox%i% + j  & 255
      k := sBox%i% + sBox%j%
      Result .= SubStr(Asc(A_LoopField)^sBox%k%, -1, 2)
   }
   StringReplace Result, Result, x, 0, All
   SetFormat Integer, %Format%
   Return Result
}

RC4hex2txt(Data,Pass) {
   b := 0, j := 0
   VarSetCapacity(Result,StrLen(Data)//2)
   Loop 256 {
      a := A_Index - 1
      Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
      sBox%a% := a
   }
   Loop 256 {
      a := A_Index - 1
      b := b + sBox%a% + Key%a%  & 255
      T := sBox%a%
      sBox%a% := sBox%b%
      sBox%b% := T
   }
   Loop 255 {
      i := A_Index - 1
      k := i + 256
      sBox%k% := sBox%i%
   }
   Loop % StrLen(Data)//2 {
      i := A_Index  & 255
      j := sBox%i% + j  & 255
      k := sBox%i% + sBox%j%
      Result .= Chr(Abs("0x" SubStr(Data,2*A_Index-1,2)) ^ sBox%k%)
   }
   Return Result
}
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Thu Dec 21, 2006 8:23 pm    Post subject: Reply with quote

...to get a fraction of a percent speedup, we can exploit a peculiarity of AHK v 1.0.46.xx: expressions containing literal strings are evaluated less deeply than the ones with variables. In the function RC4hex2txt we need to prepend "0x" to the pair of hex digits processed. If we do it the obvious way: ("0x" . SubStr(Data,2*i-1,2)), we get a string, which cannot be part of an arithmetic expression. There are several workarounds, like passing this expression to a function, which does not change its numerical value, like Abs(), or Ceil(). We can force the evaluation with a dummy assignment, like (x := "0x" . SubStr(Data,2*i-1,2)), but the simplest and fastest (so far) solution is to store the string "0x" in the variable x, and use (x . SubStr(Data,2*A_Index-1,2)). Interestingly, AHK evaluates this expression numerically.
Code:
RC4hex2txt(Data,Pass) {
   b := 0, j := 0, x := "0x"
   VarSetCapacity(Result,StrLen(Data)//2)
   Loop 256 {
      a := A_Index - 1
      Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
      sBox%a% := a
   }
   Loop 256 {
      a := A_Index - 1
      b := b + sBox%a% + Key%a%  & 255
      T := sBox%a%
      sBox%a% := sBox%b%
      sBox%b% := T
   }
   Loop % StrLen(Data)//2 {
      i := A_Index  & 255
      j := sBox%i% + j  & 255
      k := sBox%i% + sBox%j%  & 255
      Result .= Chr((x . SubStr(Data,2*A_Index-1,2)) ^ sBox%k%)
   }
   Return Result
}

Since it has no drawback, I updated the first post with this trick.
Back to top
View user's profile Send private message
iason



Joined: 01 Nov 2005
Posts: 125

PostPosted: Sun Sep 30, 2007 4:16 pm    Post subject: Reply with quote

Laszlo, thank You very much Sir again for another bit of very useful code!

A very straight forward question:
Is this safe to use in (my) bilingual system? (I want to hide information in .ini files, hidden from prying eyes.)
_________________
help to be helped
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Sun Sep 30, 2007 4:32 pm    Post subject: Reply with quote

If the input does not contain NUL characters (does not normally happen), it is safe in any langauge.
Back to top
View user's profile Send private message
iason



Joined: 01 Nov 2005
Posts: 125

PostPosted: Sun Sep 30, 2007 7:54 pm    Post subject: Reply with quote

Laszlo wrote:
...(does not normally happen)...

This declaration eases my worry, since being clueless i don't well know what a NUL character is - searched Wiki etc. and did not understand much about NUL/NULL chars etc, i just suspect and hope that they are are absent in ordinary strings such as mine.

Thanks again!
_________________
help to be helped
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 4016
Location: Pittsburgh

PostPosted: Sun Sep 30, 2007 7:58 pm    Post subject: Reply with quote

Yes, they are not in ANSI strings, only in binary data.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group