Trouble emplementing a simple XOR cipher

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Trouble emplementing a simple XOR cipher

15 Nov 2013, 03:22

I am trying to write a basic XOR cipher in AHk. For some reason my code only works sometimes depending on the key used:

Code: Select all

txt := "The Quick Brown Fox Jumps Over The Lazy Dog."
key := "why won't this work?why won't this work?why won't this work?"
;key := "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
enc := xorcipher(txt, key)
dec := xorcipher(enc, key)

msgbox, % "Plaintext:`n" txt "`n`nKey:`n" key "`n`nEnciphered:`n" enc "`n`nDeciphered:`n" dec

xorcipher(text, key)
 {
   loop, parse, text
    {
      out .= chr(asc(a_loopfield) ^ asc(substr(key, a_index, 1)))
    }
   return out
 }
One key works, the other fails. Any idea why?
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: TRouble emplementing a simple XOR cipher

15 Nov 2013, 04:04

;)

Code: Select all

txt := "The Quick Brown Fox Jumps Over The Lazy Dog."
key := "why won't this work?why won't this work?why won't this work?"
;key := "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
enc := xorcipher(txt, key)
dec := xorcipher(key, enc)

msgbox, % "Plaintext:`n" txt "`n`nKey:`n" key "`n`nEnciphered:`n" enc "`n`nDeciphered:`n" dec

xorcipher(text, key)
 {
   loop,parse, text
    {
			If !enc:=asc(a_loopfield) ^ asc(substr(key, a_index, 1))
				out.=a_loopfield
			else out .= chr(enc)
    }
   return out
 }
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: TRouble emplementing a simple XOR cipher

15 Nov 2013, 04:21

... ?

That does seem to make the decipher work, mostly. But it also adds the key to the end on the deciphered text? Thank you for the help, but I would greatly appreciate an explanation... Please? :shock:
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
User avatar
LinearSpoon
Posts: 156
Joined: 29 Sep 2013, 22:55

Re: TRouble emplementing a simple XOR cipher

15 Nov 2013, 06:14

The problem occurs when a letter in the text happens to be the same as its corresponding letter in the key

For example, the 'h' here:
"The Quick Brown Fox Jumps Over The Lazy Dog."
"why won't this work?why won't this work?why won't this work?"

Any number xored with itself produces zero (null). AutoHotkey won't actually append an empty string to the encoded text, so that letter essentially gets skipped. If there are letters missing from the encoded text, during the decoding loop, they get xored with the wrong letters from the key and produce the wrong output. Notice this key and txt work (replacing matching characters with X):

Code: Select all

txt := "The Quick Brown Fox Jumps Over The Lazy Dog."
key := "wXyXwon'tXthis work?why won't thisXwork?why won't this work?"
enc := xorcipher(txt, key)
dec := xorcipher(enc, key)

msgbox, % "Plaintext:`n" txt "`n`nKey:`n" key "`n`nEnciphered:`n" enc "`n`nDeciphered:`n" dec

xorcipher(text, key)
 {
   loop, parse, text
    {
      out .= chr(asc(a_loopfield) ^ asc(substr(key, a_index, 1)))
    }
   return out
 }
HotKeyIt's fix is basically to append the offending letter without encoding if it would otherwise be null. The reason it also appends the key is because he flipped the parameters on the deciphering call (the loop runs longer than it's supposed to because the key is longer than the input). Reverse them again and it should work fine…
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: TRouble emplementing a simple XOR cipher

15 Nov 2013, 06:33

Thank you again for your admirably clear and informative help LinearSpoon. :)

So, the issues is that AHk cannot work with a null character? If this is the case I think XOR is not going to work for my purpose, even with the work around HotKeyIt was kind enough to provide...

No matter. Thank you both for your help.
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: Trouble emplementing a simple XOR cipher

15 Nov 2013, 11:30

This will work:

Code: Select all

txt := "The Quick Brown Fox Jumps Over The Lazy Dog."
key := "why won't this work?why won't this work?why won't this work?"
enc := xorcipher(txt, key)
dec := xorcipher(key, enc)

msgbox, % "Plaintext:`n" txt "`n`nKey:`n" key "`n`nEnciphered:`n" enc "`n`nDeciphered:`n" dec

xorcipher(text, key)
 {
   loop,parse, text
    {
			If !enc:=asc(a_loopfield) ^ asc(substr(key, a_index, 1))
				out.=a_loopfield
			else out .= chr(enc)
			If StrLen(key)=A_Index
				break
    }
   return out
 }
User avatar
LinearSpoon
Posts: 156
Joined: 29 Sep 2013, 22:55

Re: Trouble emplementing a simple XOR cipher

15 Nov 2013, 12:35

So would this without an extra if statement in the loop :lol:

Code: Select all

txt := "The Quick Brown Fox Jumps Over The Lazy Dog."
key := "why won't this work?why won't this work?why won't this work?"
enc := xorcipher(txt, key)
dec := xorcipher(enc, key)   ;<---------------- You had them flipped

msgbox, % "Plaintext:`n" txt "`n`nKey:`n" key "`n`nEnciphered:`n" enc "`n`nDeciphered:`n" dec

xorcipher(text, key)
 {
   loop,parse, text
    {
            If !enc:=asc(a_loopfield) ^ asc(substr(key, a_index, 1))
                out.=a_loopfield
            else out .= chr(enc)
    }
   return out
 }
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Trouble emplementing a simple XOR cipher

15 Nov 2013, 12:59

Well you'll simply have to work with binary data.
I'm working on an String encryption so I know some stuff about this so this should work:

Code: Select all

xorcipher(text, key)
{
SetFormat, Integer, Hex    
loop,parse, text
    {
           enc:=substr(asc(a_loopfield) ^ asc(substr(key, mod(a_index,strlen(key)), 1)),3)
		   while (strlen(enc)<4)
               enc:="0" . enc
            out.=enc    
     }
   return out
}
You'll have to use a different decipher function.
Recommends AHK Studio
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Trouble emplementing a simple XOR cipher

15 Nov 2013, 13:54

Or even better:

Code: Select all

xorcipher(text, key)
{
V:=""
VarSetCapacity(V,StrLen(text)*2)
Loop, % Strlen(text)
	numput(numget(text,A_Index*(1+A_IsUnicode),A_IsUnicode?"UShort":"UChar") ^ numget(key,mod(A_Index*(1+A_IsUnicode),Strlen(key)),A_IsUnicode?"UShort":"UChar"),V,A_Index*2-2,"UShort")
V2:=""
DllCall("crypt32\CryptBinaryToStringA","ptr",&V,"uint",strlen(text)*2,"uint",1,"ptr",0,"uint*",n)
VarSetCapacity(V2,n)
DllCall("crypt32\CryptBinaryToStringA","ptr",&V,"uint",strlen(text)*2,"uint",1,"ptr",&V2,"uint*",n)
return , StrGet(&V2,n,"utf-8")
}
Recommends AHK Studio
User avatar
LinearSpoon
Posts: 156
Joined: 29 Sep 2013, 22:55

Re: Trouble emplementing a simple XOR cipher

15 Nov 2013, 14:53

I think you've missed the point of the xor cipher.. The same function is used to encode and decode the text... Your function returns something like:
Plaintext:
The Quick Brown Fox Jumps Over The Lazy Dog.

Key:
why won't this work?why won't this work?why won't this work?

Enciphered:
AAAcAAAAJgAaAAcARAAfAAAANgAaAAYABABOAFcAKQAdABMAHwA9AB0AFABQAAQA
TwAhAFEAEQBSAFcAPAARAEUAVwAjAA8AXQANAAAAMAAHAA4AXQAgAA==

Deciphered:
KQA4AEMANgAuAC8AZgA+AEcANQAJACgAMgBDADYAPQAzACoAWQA2ACkAOABhADkA
CAAvAEYANQBhAC4AKQA7AGEANQAgAC8AYQAXAGEAPwA5ACgAFwBhADUAIgAzACMA
SAA2AFEAOABiAEcALgAoAGYANgBxADYAKQAoAGEAegBlADoAUAA1AEgANQAuACwA
MgBlACYALQAhACoAeQAUACkAKQBhADYAPQAvAGIAIQBhACEAHwA4AEoANgAuAFYA
ZgAsAHEANQAmACgAMgBhADYAIgAzACoAdwA2ACkATQBhAC8APgAvAEAANQBhAEoA
VQB0ACoAdwA=
User avatar
FanaticGuru
Posts: 1946
Joined: 30 Sep 2013, 22:25

Re: Trouble emplementing a simple XOR cipher

15 Nov 2013, 19:08

Here is my XOR cipher I wrote some time ago.

Code: Select all

String := "Each script is a plain text file containing commands to be executed by the program (AutoHotkey.exe). A script may also contain hotkeys and hotstrings, or even consist entirely of them. However, in the absence of hotkeys and hotstrings, a script will perform its commands sequentially from top to bottom the moment it is launched."

Key := "Creating a script"

Coded := XOR_String_Plus(String, Key)
Decoded := XOR_String_Minus(Coded, Key)

MsgBox % "String:`n" String "`n`nCoded:`n" Coded "`n`nDecoded:`n" Decoded

XOR_String_Plus(String,Key)
{
	Key_Pos := 1
	Loop, Parse, String
	{
		String_XOR .= Chr((Asc(A_LoopField) ^ Asc(SubStr(Key,Key_Pos,1))) + 15000)
		Key_Pos += 1
		if (Key_Pos > StrLen(Key))
			Key_Pos := 1
	}
	return String_XOR
}

XOR_String_Minus(String,Key)
{
	Key_Pos := 1
	Loop, Parse, String
	{
		String_XOR .= Chr(((Asc(A_LoopField) - 15000) ^ Asc(SubStr(Key,Key_Pos,1))))
		Key_Pos += 1
		if (Key_Pos > StrLen(Key))
			Key_Pos := 1
	}
	return String_XOR
}

; If dealing only with numbers the code is trivial
; This is mathematically perfect encryption that can not be broken 
;   by analysis if the Key is the same length as the Number
/*
Number := "1371113171923"
Key := "1234567890987"
Coded :=Number ^ Key
Decoded := Coded ^ Key
MsgBox % "Number:`t" number "`n`nKey:`t" Key "`n`nCoded:`t" Coded "`n`nDecoded:`t" Decoded
*/
I split it up into two functions simply because I wanted to shift the coded characters up into more interesting character range and also avoid the problem of my encoded string getting control characters that can not be displayed or have special meaning.

The functions are exactly the same except one adds an amount to each character and one subtracts an amount from each character to shift the range of characters that are displayed.

It has to be run as Unicode though as it uses an extended character set.

Output:
Image

Also of note is that if you make the key random and the same length as the string to be encoded then you end up with a mathematically perfect encryption that can not be broken by analysis.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Trouble emplementing a simple XOR cipher

16 Nov 2013, 02:14

Wow! Thanks to all for contributing to my education. I am trying to wrap my head around your answers, so your patience is greatly appreciated.

@HotKeyIt:
Your workaround works fine to eliminate messed up characters from key bits matching text bits. Unfortunately I don't think that fix lets the cipher actually work to obscure the text very well. Since some of the plaintext may not be enciphered at all the security of the cipher is compromised, I think (not that it is secure to begin with). Thank you for your help.

@LinearSpoon:
Thank you for explaining the issue, both with my code and with HotKeyIt's. I reworked it to use ternary. Not that it works any differently, I just think it looks better:

Code: Select all

txt := "The time has come for all good men to come to the aid of their country."
key := "Ice Cream"
enc := xorcipher(txt, key)
dec := xorcipher(enc, key)

msgbox, % "Plaintext:`n" txt "`n`nKey:`n" key "`n`nEnciphered:`n" enc "`n`nDeciphered:`n" dec

xorcipher(text, key)
 {
   loop, parse, text
    {
      chr := asc(a_loopfield) ^ asc(substr(key, mod(a_index, strlen(key)), 1))
      out .= chr ? chr(chr) : a_loopfield
    }
   return out
 }
And I don't necessarily require that the cipher work with a single function.

@nnnik:
You say I can work with the characters in binary, but your code appears to use hexadecimal...? That does give me an idea though.

@FanaticGuru:
I have seen your code before on the other forum, when I was first tinkering with XOR! :)

@all:
nnnik's code seems to indicate that while a null cannot be stored in a string as a character, perhaps it can be stored as the character code itself?

Edit:
I tested it and yes, a null returns a 0 when asc() is used. This poses another issue. Say I XOR two strings and never reconvert using chr() so all characters remain as number codes. Then in order to let them all be in the same string but be able to get the original codes back later I pad the left side with 0s and use LTrim() to remove those 0s later. Kind of like this:

Code: Select all

txt := "The Quick Brown Fox Jumps Over The Lazy Dog."
key := "Open Sesame"
enc := xorencipher(txt, key)
dec := xordecipher(enc, key)

msgbox, % "Plaintext: " txt "`n`nKey: " key "`n`nEnciphered: " enc "`n`nDeciphered: " dec

xorencipher(text, key)
 {
   loop, parse, text
    {
      out .= substr("000" . asc(a_loopfield) ^ asc(substr(key, mod(a_index, strlen(key)), 1)), -3)
    }
   return out
 }

xordecipher(text, key)
 {
   count := 1
   loop, % strlen(text) / 4
    {
      out .= chr(ltrim(substr(text, count, 4), "0") ^ asc(substr(key, mod(a_index, strlen(key)), 1)))
      count+=4
    }
   return out
 }
This works to allow the XORed text to be saved as a string, but null characters are lost on deciphering because the LTrim() function gets rid of the rightmost 0 in the string. Is there a way to remove the padding 0s but only up to a max number? Obviously I could do that by checking if the leftmost characters is a0 and the length of the string, but doing that for each characters group would make the decipher function ridiculously slow. It would be nice if LTrim() had a max length parameter like SubStr() does. :roll:

Edit:
It occurs to me to ask, why nulls can't be added to a string? Character 0 in the asc() character table is a null. The relevant part of that sentence is that nulls ARE characters. Why are other non printing characters OK but nulls are not? How would a XOR cipher be implemented in other languages so that they don't have these problems?
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Trouble emplementing a simple XOR cipher

16 Nov 2013, 06:11

I would still like answers to my questions, but I made this as a workaround:

Code: Select all

txt := "The XOR operator is extremely common as a component in more complex ciphers. By itself, using a constant repeating key, a simple XOR cipher can trivially be broken using frequency analysis. If the content of any message can be guessed or otherwise known then the key can be revealed. Its primary merit is that it is simple to implement, and that the XOR operation is computationally inexpensive. A simple repeating XOR cipher is therefore sometimes used for hiding information in cases where no particular security is required."

key := "Peter Piper picked a peck of pickled peppers."

enc := xorencipher(txt, key)
dec := xordecipher(enc, key)

msgbox, % "Plaintext:`n" txt "`n`nKey:`n" key "`n`nEnciphered:`n" enc "`n`nDeciphered:`n" dec

xorencipher(text, key)
 {
   loop, parse, text
    {
      out .= substr("000" . asc(a_loopfield) ^ asc(substr(key, mod(a_index, strlen(key)), 1)), -3)
    }
   return out
 }

xordecipher(text, key)
 {
   count := 1
   loop, % strlen(text) / 4
    {
      chr := ltrim(substr(text, count, 4), 0)
      out .= chr((chr ? chr : 0) ^ asc(substr(key, mod(a_index, strlen(key)), 1)))
      count+=4
    }
   return out
 }
This solution appears to solve my problem, though it would still be nice if a REAL XOR cipher were possible in AHk.
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Trouble emplementing a simple XOR cipher

16 Nov 2013, 09:04

Hi
Autohotkey is using so called 0-Terminated Strings.
Basically it looks like this:
"Anything not 0 and more Characters | 0"
The last character is an 0Char it is the end of the String.
So If an 0 appears before the actual end the String ends there.
You'll have to use numput like I did in my second function.
Recommends AHK Studio
User avatar
LinearSpoon
Posts: 156
Joined: 29 Sep 2013, 22:55

Re: Trouble emplementing a simple XOR cipher

16 Nov 2013, 09:57

It occurs to me to ask, why nulls can't be added to a string? Character 0 in the asc() character table is a null. The relevant part of that sentence is that nulls ARE characters. Why are other non printing characters OK but nulls are not? How would a XOR cipher be implemented in other languages so that they don't have these problems?
As nnnik mentions, AHK uses a null to mark the end of the string.
What should be the correct operation here appending string B to string A?
A = 1,2,3,0 (in ascii values)
B = 0
A .= B = 1,2,3,0
AHK may very well append the null character but it wouldn't change anything. The new null character will still be considered the end of the string for later appends.

This is a working example of a cipher that allows null characters. It requires a length parameter because strlen(text) cannot be trusted to return the correct number of characters. VarSetCapacity(text, -1) will also give the wrong length. (Why? Because they count the characters/bytes to the first null - but that isn't necessarily all of the string here)

Code: Select all

txt := "The Quick Brown Fox Jumps Over The Lazy Dog."
key := "why won't this work?"

enc := xorcipher(txt, key, len := strlen(txt))
dec := xorcipher(enc, key, len)
msgbox % enc "`n" dec

xorcipher(text, key, textlen=0)
{
	static charsize := A_IsUnicode ? 2 : 1, chartype := A_IsUnicode ? "ushort" : "uchar"
	Loop, % textlen ? textlen : strlen(text)
	{
		textchar := NumGet(text, charsize*(A_Index-1), chartype)
		keychar := NumGet(key, charsize*mod(A_Index, strlen(key)), chartype)
		NumPut(textchar ^ keychar, text, charsize*(A_Index-1), chartype)
	}
	return text
}
PS: I like FanaticGuru's cipher. The only downside is that it requires Unicode AHK.
User avatar
dmg
Posts: 287
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Trouble emplementing a simple XOR cipher

17 Nov 2013, 04:43

Thanks for explaining guys. I think my workaround is OK. This is what I did with it:

Code: Select all

#notrayicon
#noenv
#singleinstance, ignore
setbatchlines, -1
setworkingdir, %a_scriptdir%
base := _random(-2147483648, 2147483647)

menu, tray, nostandard
menu, tray, tip, XOR+
menu, tray, add, Restore, win
menu, tray, add, About, about
menu, tray, add
menu, tray, add, Exit, guiclose
menu, tray, default, restore

menu, text, add, Load from file..., openfile
menu, text, add
menu, text, add, Save to file..., savetofile
menu, text, add, Save to clipboard, savetoclip
menu, text, icon, Load from file..., SHELL32.dll, 71, 16
menu, text, icon, Save to file..., SHELL32.dll, 71, 16
menu, text, icon, Save to clipboard, SHELL32.dll, 22, 16
menu, mainbar, add, File, :text
menu, mainbar, add, About, about
gui, menu, mainbar

gui, font, s8
gui, +resize +minsize
gui, add, groupbox, x10 y0 w350 h226 vgbxmain
gui, add, edit, vscroll wanttab x20 y16 w330 h170 vtext, 
gui, add, edit, x20 y196 w200 h20 vpass, 
gui, add, button, x230 y196 w60 h20 vbtnencipher gencipher, Encipher
gui, add, button, x290 y196 w60 h20 vbtndecipher gdecipher, Decipher

gui, show, w370 h236, XOR+
return

savetoclip:
 {
   gui, submit, nohide
   gui, +owndialogs
   if (text = "")
    {
      msgbox, 64, Save..., The text field is empty., 10
    }
   else
    {
      clipboard := text
      msgbox, 64, Save..., Your text has been saved to the clipboard., 10
    }
 }
return

savetofile:
 {
   gui, submit, nohide
   gui, +owndialogs
   if (text = "")
    {
      msgbox, 64, Save..., The text field is empty., 10
    }
   else
    {
      fileselectfile, path, s18, *.txt, Save to file..., (*.txt)
      if (path != "")
       {
         if fileexist(path)
          {
            filedelete, %path%
          }
         fileappend, %text%, %path%, utf-8
         splitpath, path, name
         msgbox, 64, Save..., Your text has been saved to "%name%"., 10
       }
    }
 }
return

openfile:
 {
   gui, +owndialogs
   fileselectfile, path, 3, *.txt, Open file..., (*.txt)
   fileread, content, %path%
   stringreplace, content, content, `r`n, `n, 1
   guicontrol, , text, %content%
 }
return

encipher:
 {
   gui, submit, nohide
   gui, +owndialogs
   if (text = "") && (pass = "")
    {
      msgbox, 64, Encipher..., Both fields are empty., 10
    }
   else if (text = "")
    {
      msgbox, 64, Encipher..., The text field is empty., 10
    }
   else if (pass = "")
    {
      msgbox, 64, Encipher..., The password field is empty., 10
    }
   else
    {
      stringreplace, text, text, `r`n, `n, 1
      
      ciphertext := _encipher(text, pass)
      guicontrol, , text, %ciphertext%
    }
 }
return

decipher:
 {
   gui, submit, nohide
   gui, +owndialogs
   if (text = "") && (pass = "")
    {
      msgbox, 64, Decipher..., Both fields are empty., 10
    }
   else if (text = "")
    {
      msgbox, 64, Decipher..., The text field is empty., 10
    }
   else if (pass = "")
    {
      msgbox, 64, Decipher..., The password field is empty., 10
    }
   else
    {
      stringreplace, text, text, `r`n, `n, 1
      
      plaintext := _decipher(text, pass)
      guicontrol, , text, %plaintext%
    }
 }
return

_encipher(text, password)
 {
   key := _keygen(text, password)
   loop, parse, text
    {
      out .= substr("000" . asc(a_loopfield) ^ asc(substr(key, mod(a_index, strlen(key)), 1)), -3)
    }
   return _convert(_scramble(out, password), password)
 }

_decipher(text, password)
 {
   count := 1
   key := _keygen(text, password)
   text := _descramble(_restore(text, password), password)
   loop, % strlen(text) / 4
    {
      chr := ltrim(substr(text, count, 4), 0)
      out .= chr((chr ? chr : 0) ^ asc(substr(key, mod(a_index, strlen(key)), 1)))
      count+=4
    }
   return out
 }

_convert(input, seed)
 {
   global base
   table := _scramble(_table(), seed)
   min := "1|29|37|45|53|61|69|77|85|93"
   max := "28|36|44|52|60|68|76|84|92|100"
   stringsplit, table, table
   stringsplit, min, min, |
   stringsplit, max, max, |
   loop, 10
    {
      x := a_index - 1
      min_%x% := min%a_index%
      max_%x% := max%a_index%
    }
   random, , base + 2147483648
   loop parse, input
    {
      pick := _random(min_%a_loopfield%, max_%a_loopfield%)
      output .= table%pick%
    }
   return output
 }

_restore(input, seed)
 {
   table := _scramble(_table(), seed)
   min := "1|29|37|45|53|61|69|77|85|93"
   max := "28|36|44|52|60|68|76|84|92|100"
   stringsplit, table, table
   stringsplit, min, min, |
   stringsplit, max, max, |
   loop, 10
    {
      x := a_index - 1
      min_%x% := min%a_index%
      max_%x% := max%a_index%
    }
   loop, 10
    {
      index := a_index - 1
      count := min_%index% - 1
   
      while (count++ < max_%index%)
       {
         alpha := asc(table%count%)
         num%alpha% := index
       }
    }
   loop parse, input
    {
      char := asc(a_loopfield)
      output .= num%char%
    }
   return output
 }

_scramble(string, seed)
 {
   random, , seed
   length := strlen(string)
   loop, % length
    {
      random, position, 1, (length - a_index + 1)
      out .= substr(string, position, 1)
      string := substr(string, 1, position - 1) . substr(string, position + 1)
    }
   return out
 }

_descramble(string, seed)
 {
   random, , seed
   length := strlen(string)
   loop, % length
    {
      random, position, 1, (length - a_index + 1)
      char%a_index% := position
    }
   loop, % length
    {
      newstring := substr(newstring, 1, char%length% - 1) . substr(string, length, 1) . substr(newstring, char%length%)
      length--
    }
   return newstring
 }

_keygen(text, password)
 {
   seed := _hash(password)
   random, , seed
   loop, % strlen(text)
    {
      random, ran, 1, 1000
      key .= chr(ran)
    }
   return key
 }

_table()
 {
   loop, 100
    {
      out .= _chr(a_index - 1)
    }
   return out
 }

_hash(string)
 {
   hash := 2166136261
   loop, parse, string
    {
      hash := 16777619 * (hash ^ Asc(SubStr(string, A_Index, 1)))
    }
   return hash & 0xFFFFFFFF
 }

_asc(input)
 {
   return input = "`n" ? 0 : input = "’" ? 96 : input = "–" ? 97 : input = "“" ? 98 : input = "”" ? 99 : asc(input) - asc(a_space) + 1
 }

_chr(input)
 {
   return input = 0 ? "`n" : input = 96 ? "’" : input = 97 ? "–" : input = 98 ? "“" : input = 99 ? "”" : chr(input + asc(a_space) - 1)
 }

about:
 {
   if (about_gui != 1)
    {
      gosub, get_about
      gui, font, s8
      gui, 2:add, button, x340 y275 w60 h20 ghome_site, Home
      gui, 2:add, button, default x400 y275 w60 h20 g2guiclose, OK
      gui, 2:add, edit, +readonly vscroll x10 y10 w450 h260, %about%
      gui, 2:show, center w470 h300, About XOR+
      about_gui := 1
    }
   else
    {
      gui, 2:destroy
      about_gui := 0
    }
 }
return

get_about:
 {
   about := 
(
"Yet to be written..."
)
 }
return

home_site:
 {
   ;run, http://crzyinc.weebly.com/XOR+.html
   msgbox, Home site not yet established...
 }
return

guisize:
 {
   gui, +owndialogs
   if (a_eventinfo = 1) && (flag != 1)
    {
      if (!set)
       {
         gui, restore
         msgbox, 35, Minimize..., Send window to the system tray?
       }
      flag := 1
      ifmsgbox yes
       {
         set := 1
       }
      ifmsgbox no
       {
         set := 2
       }
      if (set = 1)
       {
         gosub, win
       }
      else if (set = 2)
       {
         gui, minimize
       }
    }
   else
    {
      anchor("gbxmain", "w h", 1)
      anchor("text", "w h", 1)
      anchor("pass", "y w", 1)    
      anchor("btnencipher", "x y", 1)
      anchor("btndecipher", "x y", 1)
    }
   sleep, 200
   flag := 0
 }
return

win:
 {
   toggle := !toggle
   if (toggle)
    {
      gui hide
      menu, tray, icon
    }
   else
    {
      gui, show, center
      menu, tray, noicon
    }
 }
return

guiclose:
 {
   gui, show
   gui, submit, nohide
   gui, +owndialogs
   if (text != "") && (pass != "")
    {
      msgbox, 65, Close..., Text and password will be lost on exit.
    }
   else if (text != "")
    {
      msgbox, 65, Close..., Text will be lost on exit.
    }
   else if (pass != "")
    {
      msgbox, 65, Close..., Password will be lost on exit.
    }
   ifmsgbox cancel
    {
      return
    }
   exitapp
 }
return

2guiclose:
 {
   gui, 2:destroy
   about_gui := 0
 }
return

_random(min, max)
 {
   random, var, %min%, %max%
   return var
 }

anchor(c, a = "", r = false)
 {
   static d
	 guicontrolget, p, pos, %c%
	 if ex := errorlevel
	  {
		  gui, %a_gui%:+lastfound
		  controlgetpos, px, py, pw, ph, %c%
	  }
	 if !(a_gui or px) and a
	  {
		  return
		}
	 i = x.w.y.h./.7.%a_guiwidth%.%a_guiheight%.`n%a_gui%:%c%=
	 stringsplit, i, i, .
	 d := a ? d . ((n := !instr(d, i9)) ? i9 : "") : regexreplace(d, "\n\d+:" . c . "=[\-\.\d\/]+")
	 loop, 4
	  {
	    x := a_index, j := i%x%, i6 += x = 3
		  , k := !regexmatch(a, j . "([\d.]+)", v) + (v1 ? v1 : 0)
		  , e := p%j% - i%i6% * k, d .= n ? e . i5 : ""
		  , regexmatch(d, "\Q" . i9 . "\E(?:([\d.\-]+)/){" . x . "}", v)
		  , l .= p%j% := instr(a, j) ? (ex ? "" : j) . v1 + i%i6% * k : ""
	  }
	if r
	 {
	   rx = draw
	 }
	if ex
	 {
	   controlmove, %c%, px, py, pw, ph
	 }
	else
	 {
	   guicontrol, move%rx%, %c%, %l%
	 }
 }
This appears to work as intended. My only real concern is the _keygen() function. I have it set to generate random asc() characters between 1 and 1000. If I increase that number much beyond 1000 it begins to break the cipher. I believe having the key consist of the widest possible range of characters increases the security of the cipher, so is there a reason it messes up and/or a way to increase it without breaking it?
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
User avatar
FanaticGuru
Posts: 1946
Joined: 30 Sep 2013, 22:25

Re: Trouble emplementing a simple XOR cipher

18 Nov 2013, 12:13

LinearSpoon wrote:
PS: I like FanaticGuru's cipher. The only downside is that it requires Unicode AHK.
If you don't want it to require Unicode you can change the +15000 and -15000 in the functions to a much lower number, like in the range of 1 to 100.

You have to add at least 1 though to avoid the 0 null problem. You have to change a null to something else as others have stated storing a null in a string causes problems.

I like the Chinese character range though because it looks intimidating.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Trouble emplementing a simple XOR cipher

18 Nov 2013, 13:21

You could simply use DllCall to convert to hex or base64
Recommends AHK Studio

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], leothlon and 102 guests