Security & Palm OS 5.x

Michael presents techniques for using masked records and encrypting/decrypting data on the Palm OS 5.x platform.


June 01, 2004
URL:http://www.drdobbs.com/security/security-palm-os-5x/184405688

June, 2004: Security & Palm OS 5.x

Masking records and encrypting/ decrypting data

Michael explored Palm OS security because he develops Palm applications for the health-care field. He also serves New York's financial district as a C/C++ consultant and can be reached at myamytechnology.com.


Constructor or PilRC Designer?


Security in the first version of the Palm OS relied partly on physical protection. That is, the handheld was stored on your person and you took care of it much like you would your wallet. In terms of software protection, good security could be had if you configured the device to prompt for a password when you turned it on. For this to work though, you had to turn off and lock the device when you were done with it, a task that was easily forgotten. An autolock feature wouldn't arrive until Palm OS 4.0.

Palm OS 1.0 also implemented a "secret" bit that marked records hidden and required a password to view them. A minor weakness, however, was that the secret bit relied on well-behaved programs to honor its meaning. A rogue program could simply ignore the secret bit, dumping the record's information. Attackers, however, needed to have physical possession of the handheld, get past the power-on password if present, have knowledge of Palm programming, and some idea of the record layout. In those days, such knowledge and experience wasn't widely available, making security through obscurity a reasonable strategy, at least for Palm OS 1.0.

Palm OS 3.5 introduced masked records. Unlike hidden records, masked records made their presence known but had their contents masked. Masked records also relied on the secret bit. An internal system security state determined how the record would be displayed—visible, masked, or hidden. Like the secret records in the Palm OS 1.0, the success of this scheme depended on the cooperation of the applications. This weakness, however, had grown more serious because Palm programming had become much more widespread.

Developers intent on protecting their users' data addressed this weakness with third-party cryptography libraries or rolled their own solutions. The latter was a dicey proposition unless you made a living in cryptography. Recognizing the need, Palm OS 5.0 introduced the Cryptography Provider Manager (CPM) to offer cryptographic services such as data encryption and decryption, message hashing, and message authentication. The CPM currently supports only one algorithm provider—RSA—although future versions of the Palm OS will allow you to plug in other providers. There is no key management to facilitate transferring encrypted data to the desktop and decrypting from there. At least with the first release of CPM, cryptography routines must take place on the handheld.

In this article, I present techniques for using masked records and encrypting/decrypting data. I limit my discussion to Palm OS 5.x (Garnet) and earlier. Palm OS 6.0, the new branch that is also known as "Cobalt," is beyond the scope of this article. The sample program I present builds a simple database consisting of names of famous or semifamous programmers (see Programmers at Work, by Susan Lammers, Microsoft Press, 1986). To keep the program self contained, I created the data as a string list resource. When the demo is run for the first time, the Palm database is created from this string list. To keep the program simple, I used exactly 11 records, just enough to fill a table on a 160×160 screen. That way, I didn't have to contend with scrolling issues. As Figure 1 shows, the demo is interactive. Tap on the checkbox to toggle the state of the secret bit. Use the Security button to change how the Palm OS should display the records. Tap on the masked field and you are prompted for a password before the demo exposes the record contents.

Behind the Mask

The demo, maskedRecs, was built with Metrowerks CodeWarrior R9 and Palm OS 5 SDK R3 on Windows 2000. For creating and managing resources, I opted for PalmSource's Constructor 1.9.1. A popular alternative is PilRC Designer (see the accompanying text box "Constructor or PilRC Designer?"). The arbitrary creator ID for this demo is "DJMR" (short for "Dobb's Journal Masked Recs").

When I created a new project with CodeWarrior, it generated a skeleton program for me, naming it Starter.c (available electronically; see "Resource Center," page 3). Starter.c contains some utility functions such as detecting the OS version. In my example, I set the minimum OS version to 3.5. Starter.c also contains the program entry and exit points, AppStart() and AppStop(), respectively. Inside AppStart(), I obtained the system security state, assigning it to a global variable; see Example 1. Depending on this variable, the database is opened in either "read/write" mode or "read/write/show secret" mode. The global, along with a record's secret bit, is necessary to properly show, mask, or hide a given record. Should the user change the system security state, the database needs to be closed and reopened in the proper mode, and the global variable needs to be updated.

CodeWarrior also generated a skeletal resource file: Starter.rsrc. Of interest is the string list resource titled "AtWork" where I stored developer names and the products they are known for. The string list resource allows a prefix that could be useful if you maintain a lot of string lists. For this demo, I left it blank. In creating a database from this string list, I used a handy routine provided by the SDK: SysStringByIndex(). It copies out a string from the list by index. If I had entered a prefix in the string list resource, the prefix would be inserted in front of the extracted string.

Inside the resource file, you'll also find the table object named "AtWork" on the main form. It has two columns—one for the checkbox and one for the developer name—and 11 rows.

I created a new file, MainForm.c (available electronically) to handle events from the main form and to manage the table. Examining MainFormInit(), you'll find that it sets the table to display a checkbox in column zero and text in column one. Columns are unusable by default, so I enabled them. I also set the attribute of column one (developer name) as maskable so that I may control its appearance without affecting the checkbox in column zero.

Text in tables require special attention. To be drawn properly, they require:

Looking again at MainFormInit(), you'll find that it allocates memory to store a list of names. This memory is freed in MainFormCleanup(). You'll also find the following call:

TblSetLoadDataProcedure (tableP, devNameCol, LoadTextTableItemCB);

This establishes LoadTextTableItemCB() as the callback routine responsible for supplying the Palm OS with the three pieces of text information. LoadTextTableItemCB() is invoked during a table redraw and retrieves the record number associated with a particular row:

recordNum = TblGetRowID (tableP, row);

Table rows can be mapped with arbitrary data. In a function invoked earlier, MainFormLoadTable(), I scanned through the database and mapped the rows with the record numbers I wanted to display using TblSetRowID(). Thus associated, a record can be retrieved using DmQueryRecord() and the text portion of the record copied into memory. LoadTextTableItemCB() can then supply a memory handle to the text, initialize the offset into the handle to zero, and measure and return the length of the string.

Take a closer look at MainFormLoadTable() where the mapping occurs. To retrieve records, I looped through the database using DmQueryNextInCategory(). Like DmQueryRecord(), it retrieves a record for read only (busy bit not set). Unlike DmQueryRecord(), if the database were opened to hide secret records, DmQueryNextInCategory() would automatically skip over records that have their secret bit set. Recall that the open mode was set in AppStart().

Even though this demo doesn't use categories, I can still use this function; passing "dmAllCategories" as the third argument ensures that all records are queried.

Determining whether to mask or expose a record required that I check the record's secret bit and the system security state, which is defined in PalmSource's SDK header file, PrivateRecords.h; see Example 2. If the record were private and the security state set to maskPrivateRecords, I masked the row as in Example 3.

Empty rows were set to unusable and, thus, will not respond to user taps. As a redundant defensive measure, I mapped the disabled rows to a value defined by dmMaxRecordIndex or 0xFFFF. Any calls to query such a record number would fail. A robust implementation could follow up with the SDK's ErrTry/ErrThrow/ ErrCatch macros or, if using C++, exception handling.

Table Events

The event handler, MainFormHandleEvent(), processes two table-related events: tblEnterEvent and tblSelectEvent. tblEnterEvent occurs when users hold the stylus down within a column and row boundary of a table. A tblSelectEvent follows if users lift the stylus up within the same column and row boundary.

Checkboxes are automatically toggled on a tblEnterEvent. To override this default behavior, I trapped this event and wrote a handler to toggle the checkbox, set or clear the record's private attribute, and update the table mask. I also set the handled flag to True, indicating to the Palm OS not to autotoggle the checkbox.

Working with the developer name, I wrote a handler in response to a tblSelectEvent. If the record were masked, the handler would prompt the user for a password with a call to SecVerifyPW(). The net effect of this call is to change the internal security state to show all records. Because I need to show only the selected record, I restored the internal security state with a call to PrefSetPreference().

Using masked records in this manner conforms to the built-in Palm applications (MemoPad, for instance), which provides users with a uniform experience—a good thing. But it's also clear from this demo how easy it is to ignore the secret bit and expose a private record. That's where encryption comes in.

Encryption

The architecture of the CPM is robust, with an API that permits low-level tuning (specifying pad characters, for example), but with default options that make it easy to use. Implementation in OS 5.0, however, is incomplete; without key management, encryption/decryption is confined to your handheld. Palm OS 6.0 may address these shortcomings, but you can't ignore the installed base of OS 5.0 devices. If you are writing software where encrypted data moves between the handheld, desktop, back-end server, and beyond, you need a third-party library.

That said, the CPM will improve and protect local databases. The demo, encryptString, encrypts and decrypts a string. There are two fields—one for you to enter plain text, and one that displays the ASCII hex equivalent. For example, the plaintext "abc 123" in hex, including the null terminator, appears as "6162632031323300" (see Figure 2). After encrypting, the hex display will represent the cipher text, which will vary depending on the encryption key. Upon decrypting, the hex field will, if all goes well, display the original sequence.

Like maskedRecs, this demo was also built with CodeWarrior R9, but as an exercise, I used PilRC Designer 2.0.5.1 for managing resources instead of the Constructor. The resource file is in text format with the name "encryptString_Rsc.rcp" (available electronically). The arbitrary creator ID for this demo is "DJES."

Because CPM is a shared library, a little housekeeping is necessary during startup. In the file encryptString.c (available electronically), AppStart() first determines if the library is already loaded, and if not, loads the library. The library is unloaded when the program ends, inside AppStop(). Similarly, the encryption key is generated during startup and released when the program ends. Because the same key is used throughout the demo, this was the simplest approach, but you should generate and release, store and retrieve, keys where it makes sense in your program.

Keys

The CPM stores key information in the structure APKeyInfoStruct. For the most part, you don't need to work with the fields, but you are responsible for allocating memory for the structure, initializing it, and freeing resources when you're done. This structure is used in key generation, key importing and exporting, and of course, encryption and decryption.

The CPMLibGenerateKey() function creates a symmetric key. Passing in a zeroed key structure requests the default key and populates the structure accordingly. CPMLibGenerateKey() also accepts a seed value that can be a password from the user. Unfortunately, under Palm OS 5.0, the function does nothing with this seed, which means an identical key cannot be recreated from the same seed or password. This is known as "key derivation" and without it, your ability to decrypt from another device or platform is limited.

A key, however, can be exported and cached safely somewhere within the handheld: the preferences database, the application info block, a Palm OS database, or somewhere in expansion memory. Wherever you decide, it would be wise for your design to allow for backups of the exported key. For example, the preference database would be a good choice because it can be backed up to the desktop during a hotsync. I emphasize this because, should the exported key become lost or corrupt, your users won't be able to decrypt their data.

On the handheld, keys are normally exported in RAW format. The design of CPM also allows exporting keys in XML and ANS.1 DER (Abstract Syntax Notation, Distinguished Encoding Rules; see http://www.asn1.org/consortium.htm), which should prove useful when transferring keys between the handheld and other platforms. But when I tried to use either of these two formats, the function CPMLibExportKeyInfo() returned an error 0x3810, which indicates a parameter error. (CPM error types can be found in CPMlibCommon.h.) The architecture does show promise, but the implementation is disappointing.

RAW format worked, and you can test it using the demo. From the menu, select "Options|Export Key...". Examining encryptStringsource.c, you find the function ExportKey(), which calls CPMLibExportKeyInfo() twice. The first call determines how much memory is required to store the exported key so that you may allocate memory appropriately. The second call actually exports the key. The exported key is then imported and is used in subsequent encryption and decryption operations.

Cipher Info

To characterize cipher text, the CPM uses the structure APCipherInfoStruct. It contains fields that describe the encryption and decryption operations, such as the algorithm provider, padding constants, and an initialization vector. Like the key structure, the APCipherInfoStruct is initialized in AppStart() and released in AppStop(). Initializing the structure to zeroes requests the default settings, the approach I used because there's only one algorithm provider to choose from in Palm OS 5.0.

APCipherInfoStruct can be exported to facilitate (future) encryption and decryption on other platforms. Currently, the CPMLibExportCipherInfo() function does not work and causes a "fatal reset" on the device I tested with, the Tungsten C. I coded an ExportCipher() routine but did not invoke it as part of the demo. Similar to the way keys are exported, the function CPMLibExportCipherInfo() must also be called twice.

Closing Thoughts

There are good reasons to implement masked records, even though they provide mild security when used alone. Users seem to like masked records. Typically, they are showing their colleagues something on the handheld and don't want to reveal certain bits of information.

There's less of a reason to use CPM in its current form. One remote benefit is to have your application use CPM for local encryption, thus obviating the need for users to tinker with the built-in Palm OS security options and keeping the entire cryptographic experience transparent.

In future versions of the CPM, I expect PalmSource to support key derivation. As part of a wish list, I'd like to see an external (desktop-based) cryptographic toolkit that imports and exports key and cipher information, and that also implements the same algorithm providers found on the handheld. Another possibility would be to incorporate such a toolkit into the Palm Conduit Development Kit (CDK) so that data can be encrypted and decrypted as it moves between the handheld and desktop. This would eliminate a separate decrypt process should you need to import the handheld data into a desktop spreadsheet or back-end database.

DDJ

June, 2004: Security & Palm OS 5.x

gPrivateRecordVisualStatus = 
    (privateRecordViewEnum)PrefGetPreference (prefShowPrivateRecords);
if (gPrivateRecordVisualStatus == hidePrivateRecords)
     mode = dmModeReadWrite;
else
     mode = dmModeReadWrite | dmModeShowSecret;

Example 1: Assigning system security state to a global variable.

June, 2004: Security & Palm OS 5.x

typedef enum privateRecordViewEnum {
    showPrivateRecords = 0x00, 
    maskPrivateRecords, 
    hidePrivateRecords
} privateRecordViewEnum;

Example 2: System security state in PrivateRecords.h.

June, 2004: Security & Palm OS 5.x

DmRecordInfo (gMaskedRecDBP, recordNum, &attr, NULL, NULL);
isMasked = (((attr & dmRecAttrSecret) && gPrivateRecordVisualStatus == maskPrivateRecords));
TblSetRowMasked(tableP, row, isMasked);

Example 3: Masking a row.

June, 2004: Security & Palm OS 5.x

Figure 1: MaskedRecs demo on Tungsten C simulator.

June, 2004: Security & Palm OS 5.x

Figure 2: EncryptStrings demo on Tungsten C simulator.

June, 2004: Security & Palm OS 5.x

Constructor or PilRC Designer?

The Constructor made its debut on the Macintosh platform and was subsequently ported to Windows. The port works well enough, although not without some quirks (see my article "EC: A Euro Calculator for the Palm," DDJ, January 2000). The output file is in binary format, which isn't particularly conducive to version control. Still, I have successfully archived these files in Visual SourceSafe as binary blobs. The Constructor's Mac ancestry also created an extra step after linking, requiring the PalmRez Post Linker to convert Mac-formatted resources to the PalmOS.

The Constructor handles complex forms very well. It hides or shows unusable objects, and displays a form's object hierarchy. There's also an alignment tool to keep your objects straight, saving you the trouble of counting pixels. The built-in bitmap editor is convenient. And if you need to work with sound, the Constructor lets you manage .WAV files.

These features are absent in PilRC Designer, but PilRC Designer has advantages of its own. It has broad support for skins beyond Palm handhelds and includes devices from Sony, Symbol, the defunct HandEra, and the wide display AlphaSmart Dana. It has zoom capability that makes working in high resolutions (1600×1024, for instance) easy on the eyes. Its resource files are in text format. This means the files are portable between Linux and Windows, can be stored in version control without a fuss, and it avoids the need for the PalmRez Post Linker. PilRC Designer can also read the Constructor's binary file, importing what it understands and flagging as unknown what it doesn't, such as .WAV resources. Currently, there is no simple method to go the other way, from PilRC's text format to the Constructor's binary format.

There is considerable uncertainty regarding PilRC Designer's future. The product is no longer formally supported and the developer's web site, http://www.falch.net/, is down most of the time. You wouldn't necessarily be stranded if you already committed to PilRC Designer because it is really a front end to PilRC. PilRC is the underlying resource compiler, and its source code and binaries are available under GNU GPL (see http://www.ardiri.com/). If you are comfortable designing in a text editor, you can use PilRC as a standalone tool.

—M.Y.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.