If you're a Palm OS programmer writing shareware, you need a way to generate registration codes from the Palm user name and perhaps some other data. PORT is the tool set I whipped up to accomplish that. They are free for use under the terms of the GNU General Public License. The one module you link with your Palm program is not GPL'd, so that you may use it in closed-source projects. I still do hope that you send bug fixes and such back to me.
I run these programs primarily on Mac OS X these days, but in the past they have been verified to work on Linux and on Win32 under the Cygwin environment. They should be portable to any other Unixy system.
PORT is made of several parts:
1.10, 2007.06.25 — Made the Perl scripts run with strictures enabled, and with all perlcritic level 5 warnings addressed.
Renamed config file to config.dat, because it has a new format due to above change.
Retired rename-csvs script.
1.09, 2005.08.24 — Fixes reqiured to make it run correctly on Mac OS X. These fixes are likely necessary for other 64-bit platforms as well. (Previously PORT was used only on 32-bit Linux and Windows.)
1.08, 2004.01.18 — Removed postmail from package. (A simple SMTP client program.) Changed over to MSMTP to gain authentication support, required by many ISPs' mail servers these days.
1.07, 2003.05.13 — PalmGear CSVs no longer contain a CSV number, so now parse-order works in more general terms.
Added rename-csvs script.
1.06, 2003.01.06 — Various fixes to compile without warnings under Standard C++ compilers.
1.05, 2001.11.18 — Added support for the new CSV number and fee-paid fields PalmGear has added to their CSV files.
Added detection of blank Palm user names. If the Palm user name is blank, we no longer try to generate a key and registration email. We generate a "you need to send me your Palm user name" email instead.
1.04, 2001.08.20 — Added debug mode to parse-order, which shows how the CSV line was parsed.
Added detection of blank order number. PGHQ did that to me once... We skip the line if there is no order number.
Several bug fixes.
1.03, 2001.06.19 — Better package distribution mechanism; this just makes it easier for me to release new versions of PORT.
1.02, 2001.05.15 — Extracted the build-email functionality out of parse-order into its own script, so that you can generate keys by hand, instead of only from CSV files. This lets you process registrations by snail-mail, for example.
1.01, 2000.11.23 — First public version.
1.00, 2000.10.14 — Initial version; never released.
As distributed, you have to do a bit of configuration to make PORT work.
First you have to configure the Perl scripts by editing the config.dat file. The most important configurable in there is the mail server's domain name. You have to change this, because my email server won't let you send email through it unless you have my password. The other configurables are less important, but you may want to fiddle with them.
Next, you have to edit the configurables in private.h. These values change how the keys are generated. In particular, they make it possible for me to distribute these key tools without allowing people who don't want to pay shareware fees to generate their own keys for my programs. Cryptographically speaking, these fiddle factors are a kind of "private key". Most of them you can set to any value that strikes your fancy, but one of them, PORT_STRIDE, requires some care in choosing. See below for a full discussion.
Then you have to edit the registration email templates: the files reg-email.tpl and no-name-email.tpl. The first template is used for successful registrations, and the second is used when the user doesn't provide their Palm user name when registering, therefore making it impossible to generate the registration key. (It happens!) The templates work on a simple substitution rule: variables begin with a dollar sign (e.g. "$progname") and everything else is copied literally into the registration email. The parse-order script defines seventeen such variables, all taken from the PalmGear CSV record. You can add more variables if you need them, but the default set is sufficient for most purposes. My own registation emails actually use only four of these.
Now you should be able to type "make" to build the tools, and optionally "make install" to install them in /usr/local/bin.
Next, create subdirectories for the CSV and email files. By default, these should be named "csvs" and "emails". As distributed, these tools look for those directories as subdirectories of the current directory. You could, for example, make these subdirectories of your project's source code directory. You can change these default names by editing the config.dat file.
Finally, download MSMTP and set it up to work with your SMTP server.
PalmGear sends you an email every day when someone registers a copy of your software during that day. The emails have a CSV file attached which you need to save out to PORT's CSV directory. Personally, I name the files after the current date: "csvs/YYYYMMDD.csv". You can use any scheme that makes sense to you.
Then you run the parse-order script with the "base name" of the CSV file; in my scheme, that's the date part. So if I get a CSV file on 5/12/2003, I save it out as csvs/20030512.csv, and the command to parse that file is "./parse-order 20030512". parse-order reads each CSV line in the file, parses it, and generates a registration email (or a no-name email, if necessary) for each valid line.
The parse-order then generates a simple script called "send-emails" which is just a list of msmtp commands to send the generated emails.
To sum up, then, the procedure is a simple three steps:
When your new customer gets the registration email, they will have to type the registration key into your program somehow. Then, your program has to verify that key. In the distribution package, there's a sample routine in the verify-key.c file that shows how you can check the key for validity. The code doesn't completely compile, it's just there to give you an idea of how to use the functions in the keytuility module.
In the private.h file, there's a constant called PORT_STRIDE. This controls how serial numbers are generated. If you set the stride to 7 and PORT_FIRST_SERIAL to 1, the first serial number will be 1, the next 8, then 15, 22, and so on. If you set the stride to 1, you will get a simple 1, 2, 3, 4... serial number series.
The problem with a simple serial number is that it's easy to guess, which weakens the key. If instead the stride value is not known, you introduce some uncertainty into the process. Yet if this stride value is constant, you can say for certain whether a given serial number is valid or not: just subtract the starting value from the serial number and divide by the stride. If you get a remainder, the serial number is bogus. The verify-key.c sample routine shows this technique.
You can get quite clever with this. For example, the number theoreticians tell me that if you use a prime number for the stride, you will generate each serial number exactly once if you wrap through the set of values (0 through 65,535, since the serial number is a 16-bit value) enough times. Or, you could change the version constant every time you wrapped around, and use a different starting value and a different stride each time through. You might duplicate serial numbers this way, but you'd also generate confusion for people trying to break your keys. :)
In addition to ordering via PalmGear, I allow my users to snail-mail their registration to me. To support that, the engine that generates a key and a registration email from the registrant's email address and Palm user name is in a separate program, build-email. Just as the parse-order script parses PalmGear's CSV files and calls build-email to build the key and the registration email, you can read your customer's registration letter and run build-email by hand with the approritate parameters. Run it without arguments to see what it requires.
If you want to get really old-school, you can run the keytool program by hand to generate a key without generating a registration email.
You don't have to understand how PORT generates keys in order to use the tools. All you have to do is change the constants in private.h so that your keys are somewhat secure, and enjoy the software. For the curious and the paranoid, though, I will now describe what my program does and why it's built the way it is.
My most important design criteria was that the generated keys be fairly short. In the Windows world, it's common for shareware to use very long keys, because you can cut and paste the key from the registration email into the program's registration dialog. But in the Palm world, the user will very likely have to transcribe the key with Grafiti. A longer key could be more secure, but for now, assume that this tradeoff in favor of the user's ease over security makes the most sense.
The key itself contains 56 bits. Written out in decimal, that would require 17 characters. PORT encodes its keys in a "base 32" number system, which only requires 12 charaters to express the same key. The scheme uses the characters 0-9 and A-Z, excepting the four characters easiest to confuse, 0, 1, I and O. By using a base that's a power of 2, the math is easier, which makes the code simpler. A larger "base" would allow the key to be expressed in fewer characters, but it becomes more difficult to enter with Graffiti, too. Base 32 seems to be the best tradeoff.
The key generator's inputs are the Palm user name, a secret "salt" value, a serial number, and a key version number. The final 56-bit key is the 32-bit hash of the key inpits, a 16-bit serial number, and an 8-bit key version, all encoded in base 32.
The conversion to base 32 notation is actually fairly tricky, because the PC platform uses little-endian integers, but the Palm devices use big-endian integers. The obvious way to implement the encoder and decoder makes the code endian-dependent. Therefore, keyutility.c uses platform-neutral bit shifting functions, instead of the CPU's native bit shifting features. This makes for some fairly ugly code — you shouldn't try to understand it, because you don't want the headache that results. :) If you have to modify the code for some reason, first read the little-endian version in base32.cpp, and then compare that to the version in keyutility.c.
Only the 32-bit hash part of the key can be considered cryptographically secure.
PORT has two other security features, but they don't increase the key space. The "salt" value just ensures that one PORT user can't trivially make up keys for another program that also uses PORT. The keys are "blinded" with a configurable XOR function, but the only purpose of this is so that a literal binary dump of the key value won't show any values whose meaning is obvious. There's a 1:1 correspondence between the blinded data and what a non-cryptographer would call "plain text", so it's not truly encrypted.
Because the key space is only 32 bits, it's relatively straightforward to pull off a brute-force attack. The breaking time is measured in mere days.
If it's so easy to break the keys, you might ask why I didn't use a more secure hash function. It's simple: longer keys are harder for your users to transcribe, and they don't add any real security. Let's say the breaking time is 2 days, on average, for a brute-force attack program to find a key. A skilled Palm assembly language programmer could locate the key checking algorithm in your binary and patch it out in about the same amount of time. Therefore, extending the key length to try and gain security makes no sense.
PORT is like your car's door locks: its purpose is to keep honest people honest, not to keep determined thieves out.
PORT is fairly configurable as distributed, but I can think of two other fairly easy ways to modify it.
The first is to add more info to the key block. An example is adding an expiration date, to allow for a time-limited trial period. You can encode a year, month and day in 15 bits, which will allow dates out to 64 years hence. I chose a 15 bit scheme because it's exactly 3 characters in base 32.
The second modification is to change the hashing algorithm. I use a 32-bit CRC from RFC 1662. Changing to a different 32-bit hash function would serve the same purpose as the "salt" value: it makes it harder for one PORT user to generate keys for another program that also uses PORT. But, this does not add any security, because a brute force attack just tries all 232 possible keys; the key space is independent of the algorithm used. To get more security, you'd need to use a hashing algorithm that generates more bits, such as SHA-1 or MD5. These will result in keys roughly double or triple the length of standard PORT keys, however. Also, since these hash functions generate more than 32 bits, you'll have to take care that you handle the endianness issues correctly.
The parse-order script has a simple debug mode, mainly useful for debugging CSV parsing. If you pass the "-d" option to the program it will show you the parsed CSV information and a few other things it normally doesn't display.
These tools are free for you to use. There is no registration fee, and for that matter I would probably return a check if someone sent one to me for this software. However, if you want to thank me for letting you use these fine tools, send me a registration code for your program. My hotsync ID is "Warren Young".
|Go to my home page|