 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Titan
Joined: 11 Aug 2004 Posts: 5382 Location: /b/
|
Posted: Sat Jan 28, 2006 3:31 pm Post subject: Basic Encryption 2.7 |
|
|
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 |
|
 |
kiu
Joined: 18 Dec 2005 Posts: 229 Location: Italy - Galatro(RC)
|
Posted: Sun Jan 29, 2006 9:09 am Post subject: |
|
|
mmm, maybe useful for many purposes _________________ ____________________
______________________
kiu |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4078 Location: Pittsburgh
|
Posted: Sun Jan 29, 2006 4:24 pm Post subject: |
|
|
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 |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5382 Location: /b/
|
Posted: Sun Jan 29, 2006 4:42 pm Post subject: |
|
|
I was going to AHKisize the TEA algorithm, I never knew you done it already ... fantastic.
In that case I'll abandon this script. But like you said, it can still prove useful in some cases. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4078 Location: Pittsburgh
|
Posted: Sun Jan 29, 2006 4:58 pm Post subject: |
|
|
| 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 |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5382 Location: /b/
|
Posted: Sun Jan 29, 2006 5:01 pm Post subject: |
|
|
| Allright, I'll take your suggestions and write the next version, cheers. |
|
| Back to top |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5382 Location: /b/
|
Posted: Wed Feb 15, 2006 1:29 am Post subject: |
|
|
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 |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4078 Location: Pittsburgh
|
Posted: Wed Feb 15, 2006 4:27 am Post subject: |
|
|
- 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 |
|
 |
PhiLho
Joined: 27 Dec 2005 Posts: 6721 Location: France (near Paris)
|
Posted: Wed Feb 15, 2006 9:51 am Post subject: |
|
|
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  _________________
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 |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5382 Location: /b/
|
Posted: Wed Feb 15, 2006 12:13 pm Post subject: |
|
|
Thanks a lot Laszlo
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 |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4078 Location: Pittsburgh
|
Posted: Wed Feb 15, 2006 4:13 pm Post subject: |
|
|
| 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 |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4078 Location: Pittsburgh
|
Posted: Wed Feb 15, 2006 5:19 pm Post subject: |
|
|
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 |
|
 |
Titan
Joined: 11 Aug 2004 Posts: 5382 Location: /b/
|
Posted: Wed Feb 15, 2006 5:37 pm Post subject: |
|
|
| 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 |
|
 |
PhiLho
Joined: 27 Dec 2005 Posts: 6721 Location: France (near Paris)
|
Posted: Wed Feb 15, 2006 6:04 pm Post subject: |
|
|
| 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
| 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
| 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
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  _________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2") |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4078 Location: Pittsburgh
|
Posted: Wed Feb 15, 2006 6:49 pm Post subject: |
|
|
| 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 |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|