Here is another script, using the same stream cipher, and the assumption, that all parties share a secret key (e.g. agreed over the phone). This is useful to encrypt text in edit controls, like Notepad, email programs or Internet chats. It uses a HotKey: Alt-X, which encrypts the plaintext in the current control (like Edit1), precedes it with a random 8-digit hex initial counter value: IV (Initial Vector), enclosed between _\ and /_, like _\f0123456/_. (If you don’t like the delimiters, it is easy to change them.)
If the file has been encrypted, we find an IV in the beginning. In this case Alt-X replaces the current ciphertext with its decrypted original. This is what we need in editors: encrypt before save, decrypt after load.
In chat programs the decrypted message cannot be written in the control of the received messages, so the location of the output should depend on the circumstances. The easiest was that if some text is marked (selected), only that is processed and the result appears in a MsgBox. If you write a message, pressing Alt-X encrypts and replaces the whole. If you receive several encrypted messages, each starting with an IV, just select the desired one and Alt-X opens up a MsgBox with the decrypted message.
We should never ever use an IV twice, because an attacker gains valuable information about both messages if he subtracts the two ciphertext character codes. Generating a random IV makes it happen with very low probability. In our case, in the average 64K messages have to be sent, before a repetition is expected. This scheme is not meant for military secrets, but for encrypting chats about our girl/boyfriends. It is adequate for that. If you need more security, you could generate longer IV's, like 160-bits. The topmost 128 bits are XOR-ed to the secret key, the remaining 32 bits constitute the initial counter value. In this case 2**80 IV's have to be generated, before a repetition is expected. It would take longer than the age of the Universe even on billions of the fastest computers working in parallel.
The problem of true random number generation remains. Initializing the built in random number generator of AHK with the date, time, up-time of the PC, etc. is bad: an attacker can guess these time values (which was the infamous Netscape bug). I will post some time a Linux entropy pool type true random number generator for AHK (measuring the user’s keystroke time intervals, the mouse movements, microphone, webcam data, network packet time arrivals, etc.). For our purposes encrypting the current time with our secret key is good enough. Before encryption it is recommended that the user checks if the PC clock is roughly accurate (by looking at the tray clock), to make sure that a Trojan or a virus has not reset it.
/* AutoHotkey Version: 1.0.35+ Language: English Platform: Win2000/XP Author: Laszlo Hars <www.Hars.US> Script to en/decrypt text in edit controls Plus-minus Counter Mode: stream cipher using add/subtract with reduced range (32...126). Characters outside remain unchanged (TAB, CR, LF, ...). The underlying cipher is TEA, the Tiny Encryption Algorithm http://www.simonshepherd.supanet.com/tea.htm At Alt-X all text from an edit control is got (e.g. Notepad), or the selection if it exists. If it starts with an IV, decrypt, otherwise encrypt - prepending IV. If there was no selection, the text is replaced, otherwise the en/decrypted text is shown in a MsgBox Version: 1.0 2005.07.10 First created */ SetBatchLines -1 ; do it fast StringCaseSense Off AutoTrim Off Mark1 = _\ ; 2-char delimiters Mark2 = /_ k1 := 0x11111111 ; 128-bit secret key k2 := 0x22222222 ; hard coded or k3 := 0x33333333 ; could be user input k4 := 0x44444444 !x:: WinGet ID, ID, A ; use current window Selected = 1 ControlGet T, Selected,,,ahk_id %ID% IfEqual T,, { ; no selection = all text Selected = 0 ControlGetText T,,ahk_id %ID% } StringGetPos p, T, %Mark1% ; look for IV IfLess p, 0, GoTo ENCRYPT StringGetPos p, T, %Mark2% IfNotEqual p,10, GoTo ENCRYPT StringMid p, T, 3, 8 If p is not xdigit ; if no IV: Encrypt GoTo ENCRYPT DECRYPT: StringTrimLeft T, T, 12 ; remove IV from text k5 = 0x%p% ; set new IV i = 9 ; pad-index, force restart p = 0 ; counter to be encrypted L = ; processed text Loop % StrLen(T) { i++ IfGreater i,8, { ; all 9 pad values exhausted u := p v := k5 ; another secret p++ ; increment counter TEA(u,v, k1,k2,k3,k4) Stream9(u,v) ; 9 pads from encrypted counter i = 0 } StringMid c, T, A_Index, 1 a := Asc(c) if a between 32 and 126 { ; chars > 126 or < 31 unchanged a -= s%i% IfLess a, 32, SetEnv, a, % a+95 c := Chr(a) } L = %L%%c% ; attach encrypted character } IfEqual Selected, 0 ControlSetText,, %L%, ahk_id %ID% Else MsgBox %L% Return ENCRYPT: StringLeft k5, A_NowUTC, 8 ; current time StringRight v, A_NowUTC, 6 v := v*1000 + A_MSec ; in MSec SetFormat Integer, H TEA(k5,v, k1,k2,k3,k4) ; k5 = starting random counter value SetFormat Integer, D StringTrimLeft u, k5, 2 u = 0000000%u% StringRight IV, u, 8 ; 8-digit hex w/o 0x i = 9 ; pad-index, force restart p = 0 ; counter to be encrypted L = %Mark1%%IV%%Mark2% ; IV prepended to processed text Loop % StrLen(T) { i++ IfGreater i,8, { ; all 9 pad values exhausted u := p v := k5 ; IV p++ ; increment counter TEA(u,v, k1,k2,k3,k4) Stream9(u,v) ; 9 pads from encrypted counter i = 0 } StringMid c, T, A_Index, 1 a := Asc(c) if a between 32 and 126 { ; chars > 126 or < 31 unchanged a += s%i% IfGreater a, 126, SetEnv, a, % a-95 c := Chr(a) } L = %L%%c% ; attach encrypted character } IfEqual Selected, 0 ControlSetText,, %L%, ahk_id %ID% Else MsgBox %L% Return TEA(ByRef y,ByRef z,k0,k1,k2,k3) ; (y,z) = 64-bit I/0 block { ; (k0,k1,k2,k3) = 128-bit key IntFormat = %A_FormatInteger% SetFormat Integer, D ; needed for decimal indices s := 0 d := 0x9E3779B9 Loop 32 { k := "k" . s & 3 ; indexing the key y := 0xFFFFFFFF & (y + ((z << 4 ^ z >> 5) + z ^ s + %k%)) s := 0xFFFFFFFF & (s + d) ; simulate 32 bit operations k := "k" . s >> 11 & 3 z := 0xFFFFFFFF & (z + ((y << 4 ^ y >> 5) + y ^ s + %k%)) } SetFormat Integer, %IntFormat% y += 0 z += 0 ; Convert to original ineger format } Stream9(x,y) ; Convert 2 32-bit words to 9 pad values { ; 0 <= s0, s1, ... s8 <= 94 Local z ; makes all s%i% global s0 := Floor(x*0.000000022118911147) ; 95/2**32 Loop 8 { z := (y << 25) + (x >> 7) & 0xFFFFFFFF y := (x << 25) + (y >> 7) & 0xFFFFFFFF x = %z% s%A_Index% := Floor(x*0.000000022118911147) } }