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 

Basic Encryption 2.7
Goto page 1, 2, 3, 4  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Titan



Joined: 11 Aug 2004
Posts: 5382
Location: /b/

PostPosted: Sat Jan 28, 2006 3:31 pm    Post subject: Basic Encryption 2.7 Reply with quote

As the title suggests, this is a basic yet highly effective encryption/decryption algorithm. It provides almost instantaneous encryption and keeps the cipher text the same size as the original text.
Credits: Laszlo (for various of things) and PhiLho (for performance tips)

Example:


Here's a speed test, you will need to include the original function in the script for it to work: BasicEncryptionSpeed.ahk

Usage guide:
Enc(type, str, pass [, l, h])
type: boolean - true for encryption or false for decryption
str: the string to be encrypted/decrypted
pass: the password for encryption/decryption
l & h are advanced params that you should omit (working ASCII bounds)

Download (< 1kb)


Last edited by Titan on Thu Apr 20, 2006 1:49 pm; edited 10 times in total
Back to top
View user's profile Send private message Visit poster's website
kiu



Joined: 18 Dec 2005
Posts: 229
Location: Italy - Galatro(RC)

PostPosted: Sun Jan 29, 2006 9:09 am    Post subject: Reply with quote

mmm, maybe useful for many purposes
_________________
____________________
______________________
kiu
Back to top
View user's profile Send private message Visit poster's website
Laszlo



Joined: 14 Feb 2005
Posts: 4078
Location: Pittsburgh

PostPosted: Sun Jan 29, 2006 4:24 pm    Post subject: Reply with quote

Well, it is that: a (really) Basic Encryption script. There are a few basic problems with it:
- The encryption is dependent only on the first character of the password and its length
- The ciphertext can contain non-printable characters, what makes printing or saving it complicated
- With long passwords, the encrypted character codes can grow beyond the byte boundary, and disappear.
- The floor function does not have a function there.
- Only a constant is added to each character code, so trying all the possible offsets (less than 200) trivially breaks it.

Still, it can be useful to hide text from your kids. For a little more security and robustness, I'd suggest a few changes:
- restrict the input and output to printable characters (like in here).
- step through cyclically and use all characters in the password.

Even with these changes, the resulting cipher is weak: Subtracting two ciphertexts removes the effects of the password, providing the same result as subtracting the original texts. If an attacker knows a long enough plaintext-ciphertext pair, with this subtraction he can decrypt your messages.
Back to top
View user's profile Send private message
Titan



Joined: 11 Aug 2004
Posts: 5382
Location: /b/

PostPosted: Sun Jan 29, 2006 4:42 pm    Post subject: Reply with quote

I was going to AHKisize the TEA algorithm, I never knew you done it already Surprised ... fantastic.

In that case I'll abandon this script. But like you said, it can still prove useful in some cases.
Back to top
View user's profile Send private message Visit poster's website
Laszlo



Joined: 14 Feb 2005
Posts: 4078
Location: Pittsburgh

PostPosted: Sun Jan 29, 2006 4:58 pm    Post subject: Reply with quote

Titan wrote:
I'll abandon this script
Don't do that. With the changes above we could have a ten-liner for text scrambling, useful for simple applications or as a placeholder in a script until higher security ciphers get implemented. If you change the password frequently, you could get some security, too.
Back to top
View user's profile Send private message
Titan



Joined: 11 Aug 2004
Posts: 5382
Location: /b/

PostPosted: Sun Jan 29, 2006 5:01 pm    Post subject: Reply with quote

Allright, I'll take your suggestions and write the next version, cheers.
Back to top
View user's profile Send private message Visit poster's website
Titan



Joined: 11 Aug 2004
Posts: 5382
Location: /b/

PostPosted: Wed Feb 15, 2006 1:29 am    Post subject: Reply with quote

Laszlo (or anyone else who can help),
I was in the process of writing the next version when I hit a dead end. I was able to encrypt the text but decrypting wasn't possible.

The encryption works by rotating the ASCII value of each character in the string against a list of alphanumeric characters. I'm not a cryptographic expert so I don't know if my encryption is seen as mathmatically legal or whatnot, but here it is (try it out first):
Code:
; Basic Encryption 2a - by Titan
SetBatchLines, -1

string = AutoHotkey is a free, open-source utility for Windows.
pass = googol

MsgBox, 64, Basic Encryption Test, % "Original:`t" . string
. "`n`nEncrypt:`t" . Enc(1, string, pass)   . "`nDecrypt:`t" Enc(0, Enc(1, string, pass), pass)

Enc(method, string, pass) {
   c = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
   StringSplit, ch, c
   Loop, Parse, string
   {
      l := Asc(A_LoopField)
      Loop, Parse, pass
      {
         Loop, % Ceil(Asc(A_LoopField)/50)
         {
            If method contains 0,decrypt,dec,d,D
            {
            
               ; ******************** Error
               l -= % StrLen(pass)
               If l < 0
                  l += % ch0
               If (l > ch0)
                  l -= % ch0
               ; ******************** EndError
               
            } Else {
               l += % StrLen(pass)
               Loop, % Floor(l / ch0)
                  l -= % ch0
            }
         }
      }
      cr := ch%l%
      cstr := cstr . cr
   }
   Return, % cstr
}

_________________

Back to top
View user's profile Send private message Visit poster's website
Laszlo



Joined: 14 Feb 2005
Posts: 4078
Location: Pittsburgh

PostPosted: Wed Feb 15, 2006 4:27 am    Post subject: Reply with quote

- You don't need % after -= or +=, but it is not an error.
- For speed, I would check if encryption or decryption is requested, outside of the text-processing loop, but it is still OK the way it is.
- Your input contains other characters, than listed in "c", like Space, "-", "," and ".". You never get them back with decryption. It looks safer to allow all ANSI (ASCII) characters between 32 and 126.
- I don't understand the function of the innermost loop, which runs once, twice or three times. Does it provide an extra level of complexity for the cipher? The length of the password is subtracted, which tends to be 5..8, making the effects of the cipher very easy to guess. I would subtract the characters of the password instead, which exhibit larger variations.
- If I understand right, the characters of the password are checked if their ANSI code is 0..49, 50..99 or 100..150, and this determines the number of times the innermost loop runs. For example, all the codes of the letters in google are larger than 100, so they all make the innermost loop run 3 times. Most of the small letters are like this, making the encryption often the same with different passwords of the same length.
- You restart processing the password at each letter of the input, so they are (cyclically) translated by the same amount. This is very easy to guess. As I said, it is easier and more secure to use the next password character directly. Something like this
Code:
string = AutoHotkey(R) is a free, open-source utility for Windows.
pass = googol

MsgBox 64, Basic Encryption Test, % "Original:`t" . string
. "`n`nEncrypt:`t" . Enc(1, string, pass)   . "`nDecrypt:`t" Enc(0, Enc(1, string, pass), pass)

Enc(method, string, pass)
{
   i = 0
   If method contains 0,decrypt,dec,d,D
      Loop Parse, string
      {
         i := Mod(i,StrLen(pass))+1        ; index of the next pass char
         StringMid x, pass, i, 1           ; pass char
         y := Asc(A_LoopField) - Asc(x)+32 ; subtract pass char moved to 0..95
         IfLess y,32, EnvAdd y, 95         ; wrap around
         cstr := cstr . Chr(y)             ; attach translated letter to output
      }
   Else {
      Loop Parse, string
      {
         i := Mod(i,StrLen(pass))+1        ; index of the next pass char
         StringMid x, pass, i, 1           ; pass char
         y := Asc(A_LoopField) + Asc(x)-32 ; add pass char moved to 0..95
         IfGreater y,126, EnvSub y, 95     ; wrap around
         cstr := cstr . Chr(y)             ; attach translated letter to output
      }
   }
   Return cstr
}
Back to top
View user's profile Send private message
PhiLho



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

PostPosted: Wed Feb 15, 2006 9:51 am    Post subject: Reply with quote

Very nice!
I like it, I may use it if I need to put a password in a script that must run unattended.
The protection is very brittle, but at least, it protects against a casual glance at a script. To break the "protection", you just have to add a msgbox after the decryption... But it is the case for any script that must send the password, whatever the protection scheme.

I played with the code to make some small performance enhancements (probably unnoticeable anyway...) and to avoid duplicate code (but resulting in less elegant code...):
Code:
AutoTrim Off
string = AutoHotkey(R) is a free, open-source utility for Windows.
pass = googol

MsgBox 64, Basic Encryption Test
, % "Original:`t" . string
. "`n`nEncrypt:`t" . Enc(1, string, pass)
. "`nDecrypt:`t" Enc(0, Enc(1, string, pass), pass)

Enc(method, string, pass)
{
   local i, x, y, pl, sub, c, cstr

   pl := StrLen(pass)
   If method contains 0,decrypt,dec,d,D
      sub = SubPass
   Else
      sub = AddPass
   Loop Parse, string
   {
      i := Mod(i, pl) + 1               ; index of the next pass char
      StringMid x, pass, i, 1           ; pass char
      Gosub %sub%
      c := Chr(y)
      cstr = %cstr%%c%                  ; attach translated letter to output
   }
   Return cstr

AddPass:
   y := Asc(A_LoopField) + Asc(x)-32    ; add pass char moved to 0..95
   IfGreater y, 126, EnvSub y, 95       ; wrap around
Return

SubPass:
   y := Asc(A_LoopField) - Asc(x)+32    ; subtract pass char moved to 0..95
   IfLess y, 32, EnvAdd y, 95           ; wrap around
Return
}

I avoid to compute the password length on each loop: this is a classical mistake, probably less annoying in languages storing this length (like AHK) than in C when you have to walk the loop each time. But still it avoids a function call.
I even thought of precomputing the array of Asc(x)-32, but this is too much...

And I used the more performant non-expression concatenation, using expression here can give signifiant slowdown on very long strings. But such encryption usually work on small strings anyway, so it is almost pointless.

Likewise, one may want to encrypt some controls chars (new line markers, tabs) or even high Ascii chars (accented chars), but this is a bit outside the scope of this function.

Thank you Laszlo for improving it, thank you Titan for proposing it Smile
_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Last edited by PhiLho on Thu Feb 16, 2006 2:02 pm; edited 1 time in total
Back to top
View user's profile Send private message Visit poster's website
Titan



Joined: 11 Aug 2004
Posts: 5382
Location: /b/

PostPosted: Wed Feb 15, 2006 12:13 pm    Post subject: Reply with quote

Thanks a lot Laszlo Very Happy
I have modified your original script and improved it a little (usings PhiLho's suggestions), the script is now version 2.0.
_________________

Back to top
View user's profile Send private message Visit poster's website
Laszlo



Joined: 14 Feb 2005
Posts: 4078
Location: Pittsburgh

PostPosted: Wed Feb 15, 2006 4:13 pm    Post subject: Reply with quote

PhiLho wrote:
some small performance enhancements
Actually, your code is slower and longer:
- StrLen(string) just references an internal variable associated to "string", and if done properly, it is not slower than referencing an explicit AHK variable. In other languages StrLen(string) could be slower, but any reasonable compiler optimizes constant expressions to be computed outside of the loop. It was an issue 30 years ago, but since then it is considered bad stile to do this trivial optimization steps by hand.
- You have now a Gosub/Return pair inside the Loop, which adds two extra steps. If the loop is short, setting up the desired subroutine and defining them takes more code than repeating the loop.
- You are right with the string concatenation: AHK is faster (at long strings) with the non-expression form. This script is meant for short strings, and the extra assignment instruction takes longer than the saving with a faster AHK instruction.

Although your version is slower (not noticeably), it has the advantage, that when the code is changed, there is only one place to update. Here we could use a macro facility, hopefully provided in a future AHK version.
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 4078
Location: Pittsburgh

PostPosted: Wed Feb 15, 2006 5:19 pm    Post subject: Reply with quote

The easiest to handle `r, `n, `t (tab) characters is to leave them alone. Although it leaks some information (the formatting), it also has some advantages: the ciphertext will not contain very long lines (for nicely formatted plaintexts), or have many line breaks not in the plaintext. The modification is trivial:
Code:
Enc(method, string, pass)
{
   i = 0
   If method contains 0,decrypt,dec,d,D
      Loop Parse, string
      {
         If (A_LoopField < A_Space) {
            cstr = %cstr%%A_LoopField%     ; leave control characters alone
            Continue
         }
         i := Mod(i,StrLen(pass))+1        ; index of the next pass char
         StringMid x, pass, i, 1           ; pass char
         y := Asc(A_LoopField) - Asc(x)+32 ; subtract pass char moved to 0..95
         IfLess y,32, EnvAdd y, 95         ; wrap around
         cstr := cstr . Chr(y)             ; attach translated letter to output
      }
   Else {
      Loop Parse, string
      {
         If (A_LoopField < A_Space) {
            cstr = %cstr%%A_LoopField%     ; leave control characters alone
            Continue
         }
         i := Mod(i,StrLen(pass))+1        ; index of the next pass char
         StringMid x, pass, i, 1           ; pass char
         y := Asc(A_LoopField) + Asc(x)-32 ; add pass char moved to 0..95
         IfGreater y,126, EnvSub y, 95     ; wrap around
         cstr := cstr . Chr(y)             ; attach translated letter to output
      }
   }
   Return cstr
}
Now, the loop got longer, so PhiLho's subroutine call inside the loop could save a couple of lines: trade speed for size.
Back to top
View user's profile Send private message
Titan



Joined: 11 Aug 2004
Posts: 5382
Location: /b/

PostPosted: Wed Feb 15, 2006 5:37 pm    Post subject: Reply with quote

Laszlo wrote:
The easiest to handle `r, `n, `t (tab) characters is to leave them alone.
Have you seen the first post; the new version 2.0 script handles characters like è, `n and all other characters.
_________________

Back to top
View user's profile Send private message Visit poster's website
PhiLho



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

PostPosted: Wed Feb 15, 2006 6:04 pm    Post subject: Reply with quote

Laszlo wrote:
Actually, your code is slower and longer:
You may be right on the slowdown, I didn't profiled it.

Quote:
- StrLen(string) just references an internal variable associated to "string", and if done properly, it is not slower than referencing an explicit AHK variable. In other languages StrLen(string) could be slower, but any reasonable compiler optimizes constant expressions to be computed outside of the loop. It was an issue 30 years ago, but since then it is considered bad stile to do this trivial optimization steps by hand.
Well, I still see that, even in Java code where it isn't necessary...
And for C, unless the compiler is very smart, it seems hard to detect if the string has a constant length or if it is altered in the loop.
I agree that most modern languages will just freeze the stop value (calculate it only once), but C is still very low level.
Well, we are in AHK, so I don't know if the function call is slower than the variable reference or not. Of course, that's splitting hairs Smile

Quote:
- You have now a Gosub/Return pair inside the Loop, which adds two extra steps. If the loop is short, setting up the desired subroutine and defining them takes more code than repeating the loop.
For that, we have to take a look at AHK code... I guess that Gosub is faster than a function call (no parameters to set up), but indeed slower than inlined code. This change is mostly to avoid code duplication (as you noticed), althought given the short code, it is a bit of a luxury Smile

Quote:
- You are right with the string concatenation: AHK is faster (at long strings) with the non-expression form. This script is meant for short strings, and the extra assignment instruction takes longer than the saving with a faster AHK instruction.
Yes, I tried to tone down my changes with comments similar to yours (which are better expressed...), and I may even prefer your version Smile

As I wrote, I just played with the source, I didn't intend to make a breakthrought improvement.
I started to program with Basic and assembly code on 8bit processors, so I took bad optimization habits Smile
_________________
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: 4078
Location: Pittsburgh

PostPosted: Wed Feb 15, 2006 6:49 pm    Post subject: Reply with quote

Titan wrote:
Have you seen the first post; the new version 2.0 script handles characters like è, `n and all other characters.
Now I looked at it. It can still use some improvements:

- The function uses a single character of the password to encrypt with, which has too little variability.

- If the character range specified is larger than 32..126, the ciphertext could contain nonprintable characters, like Asc(127). These would cause troubles, if you read and write them: some just disappear, others map to the same black square. You always have to remember, what you can and what you cannot do with these strings.

PhiLho wrote:
I started to program with Basic and assembly code on 8bit processors, so I took bad optimization habits
I had that, too. I learned programming in machine code. Any instruction we could save, reduced the length of the paper tape they were punched on, and so reduced the chance of a typing error or an error of the tape reader. It was a huge step, when symbolic assemblers became available. Then Algol 60 came along. I wrote my first real program (Gomoku playing game) for the Danish Gear computer, which used magnetic drum as program storage, and supported recursive calls by duplicating the code of the function. It still performed thousands of lines of code a second. It is hard to comprehend, that my laptop is a million times faster, and it still matters, how a simple function is coded.
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, 3, 4  Next
Page 1 of 4

 
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