simple encryption/decryption method

I did a tutorial on this site and came up with these scripts from it. I thought some of you might find them useful. 3 scripts in the next 3 messages!
The details are in the scripts.


-- this script will encrypt a word, a sentence, or multiple sentences.

(*======DISCLAIMER=======*)
-- I found this technique at http://macscripter.net/articles/197_0_10_29_C/
-- You should read that article to learn what this script does
-- text from the article says:
(*While there is no such thing as a 100% secure encryption method, the particular method I will talk about is very basic and the security of it is minimal. It should be accepted for introductory and educational purposes only. If you want to be able to send semi-sensitive emails that can only be read by someone with the "key" to decipher the message, this will suffice. If you are sending sensitive information, like credit card numbers or financial statements you definitely should not use this method. The average person is not going to be able to crack messages encrypted with this formula but someone with even rudimentary knowledge of code breaking probably can so use this method at your own risk.*)

(*======IMPORTANT=======*)
-- In choosing a value for the multiplier and choosing a character list, the multiplier and the modulus (i.e. the count of the character list) must be "relatively prime."
--Two numbers are said to be relatively prime when the only factor they have in common is 1.
-- I have included a script to help you check for relatively prime numbers.

(*======MY NOTES=========*)
-- You set your encryption methods apart from others by choosing different multipliers and character lists
-- You can even vary the order of the characters in your character list to change things up
-- You need to know the multiplier and the exact character list used to encrypt a message if you want to decrypt it
(*Note at the end of my charList I have the letter "a"... it's a duplicate of the "a" I have earlier in the list. I have this duplicate "a" because in my testing I found that if one of the characters in my "words_to_encrypt" was the last letter in charList then I got an error. The error was because the mod function returned 0 (zero) when it tried to encrypt that letter, and this zero caused an error in another part of the script... therefore I found that adding a duplicate letter at the end of charList solved this problem*)

(*======What you need to supply to the script=========*)

set words_to_encrypt to "I want to encrypt sentences. Not just words!"
set multiplier to 5
set charList to {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", " ", "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "{", "}", "|", ":", "\"", "<", ">", "?", "`", "-", "=", "[", "]", "\\", ";", "'", ",", ".", "/", "a"}


considering case
	--get a list of numbers for the words corresponding to the item numbers of the characters in charList
	set p_letter_list to text items of words_to_encrypt
	set p_num_list to {}
	repeat with i from 1 to (count of p_letter_list)
		set this_letter to item i of p_letter_list
		repeat with j from 1 to count of charList
			set this_char to item j of charList
			if this_letter is this_char then
				set end of p_num_list to j
				exit repeat
			end if
		end repeat
	end repeat
	--encrypt the numbers
	set modulus to count of charList
	set c_num_list to {}
	repeat with i from 1 to (count of p_num_list)
		set p_num to item i of p_num_list
		set c_num to ((p_num * multiplier) mod modulus)
		set end of c_num_list to c_num
	end repeat
	--get the characters for the encrypted numbers corresponding to the characters in charList
	set c_letter_list to {}
	repeat with i from 1 to (count of c_num_list)
		set this_item to item i of c_num_list
		set end of c_letter_list to (item this_item of charList)
	end repeat
	--coerce the encrypted characters into a string
	set c_string to c_letter_list as string
end considering

→ this is the encrypted result → “|Ase^dAd_Ay^o\C:dA/y^dy^oy/-Ah_dAXi/dAs_\t/K”

this is the script to check for relatively prime numbers


-- this determines if 2 numbers are relatively prime
-- Two numbers are said to be relatively prime when the only factor they have in common is 1

set multiplier to 6 -- you choose any number here... you want one that is relatively prime to the modulus
set modulus to 96 -- this is the count of the charList

-- determine the factors of the multiplier
set multiplier_factors to {}
repeat with i from 1 to round (multiplier / 2)
	if (multiplier mod i) = 0 then
		set end of multiplier_factors to i
	end if
end repeat
set end of multiplier_factors to multiplier

-- see if any of the factors of multiplier are factors of modulus
set common_factors to {}
repeat with i from 1 to count of multiplier_factors
	if (modulus mod (item i of multiplier_factors)) = 0 then
		set end of common_factors to (item i of multiplier_factors)
	end if
end repeat

if (count of common_factors) > 1 then
	return "Not Relatively Prime, the 2 numbers have the following factors in common: " & common_factors
else
	return "Relativley Prime (i.e. only 1 is a common factor)"
end if

here’s the decryption script


-- this script will decrypt a word, a sentence, or multiple sentences.

(*======What you need to supply to the script=========*)
(*=========These come from the encryption script=========*)

set words_to_decrypt to "|Ase^dAd_Ay^o\\C:dA/y^dy^oy/-Ah_dAXi/dAs_\\t/K"
set multiplier to 5
set charList to {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", " ", "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "{", "}", "|", ":", "\"", "<", ">", "?", "`", "-", "=", "[", "]", "\\", ";", "'", ",", ".", "/", "a"}

considering case
	-- get a list of numbers for the encrypted word corresponding to the item numbers of the characters in charList
	set c_letter_list to text items of words_to_decrypt
	set c_num_list to {}
	repeat with i from 1 to (count of c_letter_list)
		set this_letter to item i of c_letter_list
		repeat with j from 1 to count of charList
			set this_char to item j of charList
			if this_letter is this_char then
				set end of c_num_list to j
				exit repeat
			end if
		end repeat
	end repeat
	-- calculate m2 which is the multiplicative inverse of the multiplier, and is needed to decrypt the encrypted word
	set n to count of charList
	set multiplier to multiplier as integer
	set m2 to 0
	repeat until ((multiplier * m2) mod n) = 1
		set m2 to m2 + 1
	end repeat
	-- decrypt the numbers
	set p_num_list to {}
	repeat with i from 1 to (count of c_num_list)
		set c_num to item i of c_num_list
		set p_num to ((c_num * m2) mod n)
		set end of p_num_list to p_num
	end repeat
	-- get the characters for the decrypted numbers corresponding to the character in charList
	set p_letter_list to {}
	repeat with i from 1 to (count of p_num_list)
		set this_item to item i of p_num_list
		set end of p_letter_list to (item this_item of charList)
	end repeat
	-- coerce the decrypted characters into a string
	set p_string to p_letter_list as string
end considering

→ this is the decrypted result → “I want to encrypt sentences. Not just words!”

This is really neat, except that I can’t help but point out that using a prime number of characters in your character list would eliminate the necessity for checking for relative primes. Since you can’t go up with printable characters, you ought to go down to 89.


set characterList to {}
repeat with i from 33 to 121
	set end of ch to ASCII character i
end repeat

which is a list of 89 printable characters and if you use them as your character list, you can use any multiplier you like.

Yes Adam, I thought it was neat too… that’s why I dug into it the way I did.
Re: limiting the charList to a prime number… I agree that would make it easier, but I’d rather have all the ascii printable characters in my list so when I try to encrypt something I don’t have to worry whether any of the characters are missing from my charList.

Anyway, I wipped up this randomizer subroutine which will randomize the charList. So you can use this to generate your charList and then you’ll be reasonably sure that you’re using a unique charList/multiplier combination.


set theList to {}
repeat with i from 32 to 126 -- the printable ascii character range
	set end of theList to ASCII character i
end repeat

set charList to my randomizeList(theList) & "a" -- Note: as explained above, an "a" is added to the end of the charList yielding 96 characters in the list


(*======Subroutines======*)
-- Note this subroutine requires a modified version of the subroutine "IndexOfItem by Emmanuel Levy"
-- Note this subroutine doesn't work on list_of_lists, or list_of_records
on randomizeList(theList)
	set randomList to {}
	repeat with i from 1 to (count of theList)
		set randomItem to some item of theList -- get a random item from the list
		set itemIndex to IndexOfItem(randomItem, theList) -- get the index number of the random item
		if (count of theList) > 1 then -- remove the item number from the list
			if itemIndex = theList's length then
				set theList to items 1 thru -2 of theList
			else if itemIndex = 1 then
				set theList to rest of theList
			else
				set theList to items 1 thru (itemIndex - 1) of theList & items (itemIndex + 1) thru -1 of theList
			end if
			set end of randomList to randomItem
		else
			set end of randomList to (item 1 of theList)
			exit repeat
		end if
	end repeat
	return randomList
end randomizeList

on IndexOfItem(theItem, theList) -- credit to Emmanuel Levy but I modified it with the considering case statements
considering case
	set text item delimiters to return
	set theList to return & theList & return
	set text item delimiters to {""}
	try
		-1 + (count (paragraphs of (text 1 thru (offset of (return & theItem & return) in theList) of theList)))
	on error
		0
	end try
end considering
end IndexOfItem

Hi Regulus;

If you care about speed of randomization, my method below is more than 7.5 times faster as tested using GetMilliSec and Nigel Garvey’s “Lotsa” construction. Note that it generates the index list internally as well.


set Timing to main(500)

on main(lotsa)
	-- Set preliminary values here.
	set theList to {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", " ", "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "{", "}", "|", ":", "\"", "<", ">", "?", "`", "-", "=", "[", "]", "\\", ";", "'", ",", ".", "/", "a"}
	-- Dummy loop to absorb a small observed
	-- time handicap in the first repeat.
	repeat lotsa times
	end repeat
	
	-- Test 1.
	set t to GetMilliSec
	repeat lotsa times
		-- Regulus call here.
		my randomizeList(theList)
	end repeat
	set t1 to ((GetMilliSec) - t) / 1000
	
	-- Test 2.
	set t to GetMilliSec
	repeat lotsa times
		-- A Bell's call here.
		my RandList(theList)
	end repeat
	set t2 to ((GetMilliSec) - t) / 1000
	-- Timings.
	return {t1, t2, t1 / t2}
end main

on randomizeList(theList) -- Regulus
	set randomList to {}
	repeat with i from 1 to (count of theList)
		set randomItem to some item of theList -- get a random item from the list
		set itemIndex to IndexOfItem(randomItem, theList) -- get the index number of the random item
		if (count of theList) > 1 then -- remove the item number from the list
			if itemIndex = theList's length then
				set theList to items 1 thru -2 of theList
			else if itemIndex = 1 then
				set theList to rest of theList
			else
				set theList to items 1 thru (itemIndex - 1) of theList & items (itemIndex + 1) thru -1 of theList
			end if
			set end of randomList to randomItem
		else
			set end of randomList to (item 1 of theList)
			exit repeat
		end if
	end repeat
	return randomList
end randomizeList

on IndexOfItem(theItem, theList) -- credit to Emmanuel Levy but I modified it with the considering case statements
	considering case
		set text item delimiters to return
		set theList to return & theList & return
		set text item delimiters to {""}
		try
			-1 + (count (paragraphs of (text 1 thru (offset of (return & theItem & return) in theList) of theList)))
		on error
			0
		end try
	end considering
end IndexOfItem

to RandList(OL) -- My method for randomizing a list that may contain duplicate entries.
	script L -- force both lists into memory for easy access
		property O : OL
		property idx : {} -- original ordering of OL
		property k : {} -- the index
		property r : {} -- the randomized list
	end script
	set c to count L's O -- so as not to calculate it in every repeat
	-- make the original ordered list
	repeat with j from 1 to count L's O
		set end of L's idx to j
	end repeat
	-- randomize it
	repeat until (count L's k) = c
		tell some item of L's idx to if it is not in L's k then
			set end of L's k to it
			set end of L's r to (L's O)'s item it
		end if
	end repeat
	return L's r
end RandList

Hi Adam, I am interested in speed gains! This one won’t make much difference for this script but I need to learn what you’ve done here. I’ve only been doing this for a month or so, so I have lots to learn. I haven’t even gotten into using the script calls as you’ve done here, so I need time to figure out why it’s faster, what the advatages of using them are etc. I see your comment about it loading stuff into ram, so it looks interesting. If you know of any place where I can learn about the script call let me know. I read a little last night but just the basics. You can be sure I’ll be practicing with them.

Anyway, I ran your speed test and here’s my results from a dual 2 GHz G5 with 2 GB ram… {10.79, 6.756, 1.597098875074}.

It’s no where near the speed increase you’re seeing. I’m not sure why since the specs of our machines should be close. I even rebooted into a freash user account to make sure I didn’t have any addons or mods that I’ve made affecting the results. They were the same in both accounts.

Hi, Regulus;

Speed comparisons of scripts for doing something at random are spotty at best because, as Nigel said in this Code Exchange thread, it depends on how many “some items” are required to find a unique addition to the list and “does not contain” involves a lot of testing as the list grows.

Having said that, the use of a script entity within a script is a well-known speeder-upper in list manipulations because of differences in the way in which AppleScript stores the list(s) involved. When you run a script object you are not running the script per se, you are running an instance of it. Each time the script object is invoked (in this case just once), AppleScript creates a new copy of it in memory and sets up the structure to connect it to the script that called it. In our case here, all we did with our script object was store some properties; but as our main script runs, the data in those properties are available “live” from memory. If we had simply declared the properties without the script object, then AppleScript (at least as I understand it) stores a reference to the array in memory that contains the list and has to grab the data by following the references each time its variable is encountered.

As you can see, my understanding of this distinction is somewhat “fuzzy” because I don’t know the details of how Script objects are stored and treated, but it is generally accepted practice that when you must visit a long list frequently as we do in this case, then it’s worth the overhead of setting up the script object in the first place, but probably not otherwise. If you read the thread on QuickSort here in Code Exchange you’ll see more examples.

With respect to your speed tests, I reran the test on my machine (a dual-core G5/2.3 with 2GB memory, Tiger’s latest) and got the same results for 500 repeats - 42.8 seconds for yours, 6.193 for mine, ratio 6.9:1. I don’t know why yours are different unless you ran a much smaller value of “Lotsa” - then the extreme variation would produce spotty results. One thing I would point out - considering case is not speedy - and my version doesn’t need it.

You got a speed of 42.8 secs for 500 iterations of my randomize code
I got a speed of 10.79 secs for 500 iterations of my randomize code

I ran the speed test at least 20 times and none of the times for my code were over 12 secs. I’m really surprised at your results considering your machine is faster than mine. When you said your code was 7.5 times faster than mine, I assumed you meant that you were getting faster results on your code than I was, not that you were getting slower results on my code than I was… that’s why I rebooted my machine into a fresh user account… I was thinking I needed to do something to speed up my machine.

This doesn’t explain why my code runs so much slower on your machine because my code doesn’t do any of this. I reduce the length of my list as I get the random item from it, so no extra iterations of these are necessary. This would affect your code, but we’re not seeing a huge speed difference on your code.

I’m stumped. In any case though your randomize code is faster than mine, so I’ve ditched my code and am using yours now. Plus your code will work on mixed lists where mine didn’t.

And thanks for the tips about the script entities. I’ve got some work to do to understand them better. While I was reading through the Qsort thread, I picked up another tip i.e. where using > is faster than using >= … so I’ve got a lot to learn. I guess that’s half the fun of all this! :rolleyes:

Wow. Your machine can run your code 4 times faster than mine does. Somethng wrong with that picture - I’ll look into it further and let you know. I was running mine from Script Debugger 4 while you were probably using the Script Editor - I’ll look into that too. Thanks for letting me know.

Hi Regulus;

Turns out that the differences are due to running the test in Script Debugger 4. When I run it in the Script Editor I get 1.49 as the ratio.

Also, in this thread, Nigel Garvey has posted a killer randomizer that he called Rand2 - substantially faster than mine because it avoids the “some” repetitions for uniqueness. :wink:

If you’re looking for real encryption, you can easily access many standard encryption methods via openssl. While it’s a nice exercise in scripting to create ascii shifting encryptors (I’ve spent a bit of time messing with them them myself), it’s ultimately easier and more secure to just use real encryption technology.

The following uses the blowfish algorithm in only a few lines of code. I added a simple handler that creates a 16 character nonsensicle password (encryption key) from various character ranges of a list of jumbled text objects. This makes the password you use technically hardcoded, but not readily visible in the script… even when it’s run-only and viewed in a text editor. You could use any number of methods of deriving this key, from a simple key stored in the script to a complex function that magically derives a string from some other source, as I’ve done… depending on the level of security desired. I also put in a simple handler (‘processInput’) that allows you to test the handlers by just running the script.

processInput("", "Encrypt")

(* * * * * * Handlers for encrypting the data * * * * * * * * * * *)
to eS(inS, inK, inM)
	(* 'Encrypt String':
		This handler uses the blowfish encryption available in openssl.  
			The handler is configured to accept the string to be encrypted, the key to use 
			(generated by the 'gK()' handler below), and the mode to pass to the openssl
			call... either encrypt("e") or decrypt("d"). *)
	
	return do shell script ("echo " & (quoted form of inS) & " | openssl enc -bf -" & inM & " -pass pass:" & (quoted form of inK) & " -salt -a")
end eS

to gK()
	(* 'Get Key':
		This handler assembles a password(encryption key) to use with the blowfish script
			This is done to better hide the key in the script, so people reading through a
			compiled, run-only script will have a difficult time determining what the key is. *)
	
	set kL to {"jTiiGHa67567U2FsdGVkX184g", "C3w2235689mNVxw35467JnJMH", "JGdD34hn7n7N6bdFg67H6d54o"}
	return ((characters 8 through 13 of (item 2 of kL)) & (characters 2 through 6 of (item 3 of kL)) & (characters 19 through 23 of (item 1 of kL))) as string
end gK

(* * * * * * Sample handler to show usage * * * * * * * * * * *)
to processInput(inString, inAction)
	set outString to ""
	
	if (inString is not "") then --> Process any incoming string
		if (inAction is "Encrypt") then
			set {encMode, inAction} to {"e", "Decrypt"}
		else if (inAction is "Decrypt") then
			set {encMode, inAction} to {"d", "Encrypt"}
		end if
		set outString to (eS(inString, gK(), encMode))
	end if
	
	set userInput to (display dialog "Enter a string:" default answer outString buttons {"Decrypt", "Cancel", "Encrypt"} default button inAction)
	set {inString, inAction} to {(text returned of userInput), (button returned of userInput)}
	processInput(inString, inAction)
end processInput

Cheers,
j

jobu, that’s awesome. I was waiting for someone to chime in with some real encryption method.

Now I just need about a week to understand your code. I never saw applescript like that before! I’m looking at it now and I’m having trouble following it. But I’ll get it, just give me a little time!

Hi Jobu, I think I’m understanding it now after a little concentration. Here’s what I got… please tell me if this is right… and answer a couple questions at the bottom!

inS is the string to encrypt or decrypt
inK is the key, gotten from gk() subroutine but could be anything I choose
inM is the mode, e or d for encrypt/decrypt

–breaking down the shell command
echo inS | → pipes your string to be encoded/decoded to openssl command

–openssl arguments
enc -bf → encoding with cyphers using the blowfish cypher, but there are other cyphers that could be used
-inM → e or d for encrypt/decrypt
-pass pass:" & (quoted form of inK) → the_pass_key

  1. what is -salt and -a
  2. When I encrypt the same word over and over I get a different encrypted string returned to me each time??? I can then input any of the encrypted strings and get back my original word!!! How does that happen considering I’m using the same password?

Hi Adam, wow that’s amazing!

I saw it already! Pretty cool. Considering what jobu posted though I don’t think I’ll need it.

‘-salt’ is a function used by the enc function to encode the input. I’m no expert, but I believe that it’s the ‘seed’ used to create a more random password. You can leave it out if you wish, but it offers free added security if I’m not mistaken, and makes the code standards compliant. Not using it is only an option to allow for backwards compatibility according to the docs.

‘-a’ is also used by the enc function, and it encodes the string as base64 after encrypting it and before decoding it. This ensures compatibility with acsii encoding, and is probably best left alone.

That’s the magic of true encryption. The output string you get back when you run the function contains the original string, your password, and a magic number (that is random every time)… all jumbled up and held together by the algorithm that that you’ve used to encrypt it. So, yes, you can put in any of the output strings you receive and have them be decrypted successfully. They are not just evaluated as valid based on the password and the string, but also on their compliance with the encryption method… the blowfish algorithm, in this case. This certainly adds to not just the randomness, but also the level of security. By successfully hiding your key in your script, there really is no way for anyone to break the encryption, as far as I know.

I’m no master of encryption, though, I just know what I’ve found on the interweb and from trial and error… so this is just my take on things. :cool:

j

Regulus;

You might not need Nigel’s script now, but it’s the fastest one I’ve seen – save it in your collection.

Jobu

Fantastic stuff. I haven’t a clue how it works, but it not only does it, it does it quickly. :slight_smile:

Hi. I finally got down to writing my Christmas cards this evening, so this reply is to the state of this thread when I downloaded it several hours ago.

I hope you’ll excuse a couple of nitpickings about the opening encryption and decryption scripts. Both points concern the first and last lines inside the ‘considering case’ blocks.

set p_letter_list to text items of words_to_encrypt

That should be ‘characters of words_to_encrypt’. A string’s ‘text items’ depend on the current value of AppleScript’s text item delimiters. The default value of these delimiters is {“”} and, when they’re set to this, the string’s ‘text items’ are the same as its ‘characters’. But if, for some reason, the delimiters had been set to some other value elsewhere in the script “ say, for argument, to “encrypt” “ the text items of words_to_encrypt would be {"I want to “, " sentences. Not just words!”}. If you’re going to use ‘text items’, it’s good practise to set the text item delimiters explicitly beforehand “ though in this case it’s better to use the term ‘characters’.

set c_string to c_letter_list as string

Similarly, when a list is coerced to string, the result is affected by current setting of the text item delimiters, which are inserted between each item in the list. So it’s a good idea to be explicit about the delimiter setting here too:

set astid to AppleScript's text item delimiters -- Note the current delimiter setting.
set AppleScript's text item delimiters to {""} -- or "" -- Set the delimiters to an empty string.
set c_string to c_letter_list as string -- Do the list coercion in that state.
set AppleScript's text item delimiters to astid -- Restore the previous delimiter setting.
c_string

More accurately, it’s to do with differences in the way AppleScript handles lists when they’re referred to by variables and when they’re referred to by references to variables. In the encryption script above, there’s this line:

set this_char to item j of charList

Here, the list is referred to by the variable charList. When handling the expression ‘item j of charList’, AppleScript carries out certain safety checks which include, I believe, a check to make sure that the list doesn’t contain itself.

Since charList is a top-level variable (ie. not in a handler) it’s technically a global “ though it may need to be explicitly declared as such to be accessed from inside a handler. Globals and top-level properties “belong” to the script in which they occur, so it’s possible to refer to them in relation to the script itself, which is called ‘me’ in AppleScript.

set this_char to item j of my charList -- NB. 'my'.

A possessive expression like ‘my charList’ or ‘item j of charList’ is called a “reference”. ‘item j of charList’ is a reference to an item in the list held by charList; ‘my charList’ is a reference to the variable charList itself. It’s when we combine these “ including a reference to the list variable in the reference to the list item, as in the example immediately above “ that we see the increase in speed. For some reason, AppleScript doesn’t carry out the safety checks in this case, and the time saved by not doing them makes an enormous difference to overall time.

Inside a handler, variables are, by default, local. Locals are just temporary and don’t “belong” to anything, so it’s not possible to set up references to them. However, it’s possible, while they exist, to give them custody of some data called a “script object”, which is a sort of script-within-a-script. A script object can have its own properties and it’s possible to have references to these. So by assigning a list to a property of a script object, we’re able to use the list-variable reference syntax locally within a handler. The script object doesn’t physically contain the list or affect it in any way. It merely provides a referenceable variable whereby we can refer to it.

The speed gain, by the way, only occurs when the reference to the list variable is included in a reference to one or more of the list’s elements or properties. There’s no gain with processes that act on the list itself, such as ‘count’, ‘contains’, ‘is in’. In fact, referencing the list variable may even slow them down v-e-r-y slightly.

-- In this illustration:
-- 'myList' is a top-level variable;
-- 'theList' is a local variable within the handler;
-- 'l' is a property of the script object held in the handler's local variable 'o'.
-- The list is the same physical entity in each case, only the variables are local or global.

set myList to {1, 2, 3, 4, 5} -- Imagine this list as being much longer.
myHandler(myList)

on myHandler(theList)
	script o
		property l : theList
	end script

	set c to (count theList) -- marginally faster than '(count o's l)'.
	repeat with i from 1 to c
		get item i of o's l -- very much faster than 'item i of theList'.
	end repeat
end myHandler

Nigel, that’s an awesome explanation… very clear and understandable. All of your points are well taken. That answers my questions on script entities and their advantages. I’ll certainly try to incorporate these lessons into my code writing. I know I’ll be a better programmer for it. Thank you!

Jobu, when I try to run the script below with text created and written from a script it works. When I try to read a text file that was created, for example, in bbedit, it encrypts, but fails on decryption with the message “Bad Magic Number” and the shell script highlighted. Any clues?


set inString to (read (choose file))
set O to (eS(inString, gK(), "e"))
set D to (eS(O, gK(), "d"))

to eS(inS, inK, inM)
	return do shell script ("echo " & (quoted form of inS) & " | openssl enc -bf -" & inM & " -pass pass:" & (quoted form of inK) & " -salt -a")
end eS

to gK()
	(* 'Get Key':
		This handler assembles a password(encryption key) to use with the blowfish script
			This is done to better hide the key in the script, so people reading through a
			compiled, run-only script will have a difficult time determining what the key is. *)
	
	set kL to {"jTiiGHa67567U2FsdGVkX184g", "C3w2235689mNVxw35467JnJMH", "JGdD34hn7n7N6bdFg67H6d54o"}
	return ((characters 8 through 13 of (item 2 of kL)) & (characters 2 through 6 of (item 3 of kL)) & (characters 19 through 23 of (item 1 of kL))) as string
end gK